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 (hawkear@gmx.de)
// 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;
}
};
|