-
Notifications
You must be signed in to change notification settings - Fork 8
/
Copy pathchc_decode.hh
73 lines (62 loc) · 1.92 KB
/
chc_decode.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#pragma once
#include <boost/crc.hpp>
#include <string>
#include <stdexcept>
#include <zlib.h>
// Class freely inspired from ALLconv by Holger Kuhn ([email protected])
// Thanks for its help
class ChcDecode {
public:
ChcDecode() {
for( unsigned int i = 0 ; i < 4 ; i++ ) {
key_crc[i] = 0;
}
}
// TODO: move buffer uncypher inside load instead of getMelody
void load(std::string key[4]) {
for( unsigned int i = 0 ; i < 4 ; i++ ) {
boost::crc_32_type crc;
crc.process_bytes(key[i].c_str(), key[i].size()+1);
key_crc[i] = crc.checksum();
}
}
std::string getMelody(char *buffer, unsigned int buffer_size, unsigned int id) {
unsigned int *chc_buffer = (unsigned int*)buffer;
if( buffer_size%8 != 0 ) throw std::runtime_error("CHC file is not 8 bytes padded");
for(unsigned int i = 0 ; i < buffer_size/8 ; i++) {
decrypt(&chc_buffer[i*2], key_crc);
}
unsigned int songs = chc_buffer[0];
if( songs > 100 ) throw std::runtime_error("CHC key probably wrong (too many songs)");
unsigned int start = 0;
uLongf packsize = 0;
uLong size = 0;
for( unsigned int i = 0 ; i < songs ; i++) {
if( chc_buffer[1+i*4] == id ) {
start = chc_buffer[2+i*4];
packsize = chc_buffer[3+i*4];
size = chc_buffer[4+i*4];
break;
}
}
if( packsize == 0 ) throw std::runtime_error("Melody not found in CHC file");
Bytef *dest = new Bytef[size];
uncompress(dest, &size, (Bytef*)buffer+start, packsize);
std::string result((char*)dest, (unsigned int)size);
delete[] dest;
return result;
}
private:
unsigned int key_crc[4];
void decrypt(unsigned int *v, unsigned int k[4]) {
unsigned int v0 = v[0], v1 = v[1], i;
unsigned int sum = 0xC6EF3720;
unsigned int delta = 0x9e3779b9;
for(i = 0; i<32; i++) { // basic cycle start
v1 -= (v0<<4) + (k[2] ^ v0) + (sum ^ (v0>>5)) + k[3];
v0 -= (v1<<4) + (k[0] ^ v1) + (sum ^ (v1>>5)) + k[1];
sum -= delta;
} // end cycle
v[0] = v0; v[1] = v1;
}
};