Subversion Repositories Games.Carmageddon

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <string.h>
4
 
5
 
6
int main (int argc, char **argv)
7
{
8
        // Carmageddon data file decryption utility
9
 
10
        #define DECODE_CHAR_WITH_KEY(c,key,should_bump_seed) do { \
11
                if (c == '\t') \
12
                        c = 0x80; \
13
                c -= 32; \
14
                if ((c & 0x80) == 0) \
15
                        c ^= (key)[seed] & 0x7f; \
16
                c += 32; \
17
                if (c == 0x80) \
18
                        c = '\t'; \
19
                if (should_bump_seed) \
20
                        seed = (seed + 7) % 16; \
21
        } while (0)
22
 
23
        const char *key1 = "\x6c\x1b\x99\x5f\xb9\xcd\x5f\x13\xcb\x04\x20\x0e\x5e\x1c\xa1\x0e";
24
        const char *key2 = "\x67\xa8\xd6\x26\xb6\xdd\x45\x1b\x32\x7e\x22\x13\x15\xc2\x94\x37";
25
        const char *key_to_use;
26
        char line_buffer[1024];
27
        char *file_pathname = NULL;
28
        int should_fix_b0rken_crypto = 1;
29
        unsigned char c;
30
        int seed;
31
        int len;
32
        int i;
33
        FILE *fp;
34
 
35
        // process command-line arguments
36
        for (i = 1; i < argc; i++)
37
        {
38
                if (strcmp (argv[i], "--dont-fix-b0rken-carmageddon-crypto") == 0)
39
                        should_fix_b0rken_crypto = 0;
40
                else if (file_pathname == NULL)
41
                        file_pathname = argv[i];
42
        }
43
 
44
        // consistency check
45
        if (file_pathname == NULL)
46
        {
47
                fprintf (stderr, "usage: %s [--dont-fix-b0rken-carmageddon-crypto] <FILE.TXT>\n", argv[0]);
48
                exit (1);
49
        }
50
 
51
        // open the Carmageddon data file to decrypt
52
        fp = fopen (file_pathname, "rb");
53
        if (fp == NULL)
54
        {
55
                fprintf (stderr, "error: couldn't open '%s'\n", argv[1]);
56
                exit (1);
57
        }
58
 
59
        // read it line per line
60
        while (fgets (line_buffer, sizeof (line_buffer), fp) != NULL)
61
        {
62
                len = (int) strlen (line_buffer); // measure line length
63
 
64
                // is this line encrypted ?
65
                if (line_buffer[0] == '@')
66
                {
67
                        // chop off all trailing CR and LFs from the input data
68
                        while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n')))
69
                                line_buffer[--len] = 0;
70
 
71
                        // start with the first key and initialize the algorithm seed to the remainder of the length of data / 16
72
                        key_to_use = key1;
73
                        seed = (len - 1) % 16;
74
 
75
                        // for each encrypted character...
76
                        for (i = 1; i < len; i++)
77
                        {
78
                                c = line_buffer[i]; // quick access to character
79
 
80
                                // when loading game data, Carmageddon does not switch the XOR cypher when the comments start
81
                                if (should_fix_b0rken_crypto && (i >= 3) && (line_buffer[i - 2] == '/') && (line_buffer[i - 3] == '/'))
82
                                {
83
                                        DECODE_CHAR_WITH_KEY (c, key2, 0); // decode character with the alternate key, but don't advance the seed
84
                                        if ((i > 4) || (c == ' ') || (c == '\t') || (c == '/'))
85
                                                key_to_use = key2; // if this character looks sensible enough, it's time to swap keys
86
                                        c = line_buffer[i]; // reload character after decryption attempt with alternate key
87
                                }
88
 
89
                                DECODE_CHAR_WITH_KEY (c, key_to_use, 1); // decode character and advance the seed
90
                                line_buffer[i - 1] = c; // write decoded character one position backwards to erase the '@' prefix
91
                        }
92
 
93
                        line_buffer[i - 1] = 0; // terminate the decrypted string properly
94
                }
95
 
96
                // chop off all trailing CR and LFs from the decrypted data once again
97
                while ((len > 0) && ((line_buffer[len - 1] == '\r') || (line_buffer[len - 1] == '\n')))
98
                   line_buffer[--len] = 0;
99
 
100
                fprintf (stdout, "%s\n", line_buffer); // dump decrypted line to the standard output, with a proper newline at the end
101
        }
102
 
103
        fclose (fp); // close the input file
104
        exit (0); // and exit with a success code
105
}