Clone of Akilla's ac2d @ https://github.com/deregtd/AC2D

ChecksumXorGenerator.cpp 5.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. // Modified only to change type names
  19. #include "stdafx.h"
  20. #include "ChecksumXorGenerator.h"
  21. static const DWORD kMaxCacheSize = 100;
  22. ChecksumXorGenerator::ChecksumXorGenerator()
  23. {
  24. cacheBegin_ = 0;
  25. }
  26. void ChecksumXorGenerator::init(DWORD seed)
  27. {
  28. memset(xorTable_, 0, sizeof(xorTable_));
  29. value0_ = seed;
  30. value1_ = seed;
  31. value2_ = seed;
  32. initTables();
  33. cache_.clear();
  34. cacheBegin_ = 2; // there is no sequence 0 or 1
  35. }
  36. DWORD ChecksumXorGenerator::get(DWORD sequence)
  37. {
  38. if(cacheBegin_ == 0)
  39. {
  40. // not initialized
  41. return 0;
  42. }
  43. if(sequence < cacheBegin_)
  44. {
  45. // sequence already purged
  46. return 0;
  47. }
  48. if(sequence >= cacheBegin_ + kMaxCacheSize)
  49. {
  50. // sequence too far in future
  51. return 0;
  52. }
  53. while(sequence >= cacheBegin_ + cache_.size())
  54. {
  55. cache_.push_back(generate());
  56. }
  57. return cache_[sequence - cacheBegin_];
  58. }
  59. void ChecksumXorGenerator::purge(DWORD sequence)
  60. {
  61. if(cacheBegin_ == 0)
  62. {
  63. // not initialized
  64. return;
  65. }
  66. if(sequence >= cacheBegin_ + cache_.size())
  67. {
  68. // get not successful for sequence yet
  69. return;
  70. }
  71. while(sequence >= cacheBegin_)
  72. {
  73. cache_.pop_front();
  74. cacheBegin_++;
  75. }
  76. }
  77. DWORD ChecksumXorGenerator::generate()
  78. {
  79. DWORD value = xorTable_[counter_];
  80. if(counter_ > 0)
  81. {
  82. counter_--;
  83. }
  84. else
  85. {
  86. scramble();
  87. counter_ = 255;
  88. }
  89. return value;
  90. }
  91. void ChecksumXorGenerator::initTables()
  92. {
  93. DWORD xorvals[8];
  94. for(int i = 0; i < 8; i++)
  95. {
  96. xorvals[i] = 0x9E3779B9;
  97. }
  98. for(int i = 0; i < 4; i++)
  99. {
  100. initMix(xorvals);
  101. }
  102. for(int i = 0; i < 256; i += 8)
  103. {
  104. for(int j = 0; j < 8; j++)
  105. {
  106. xorvals[j] += xorTable_[i + j];
  107. }
  108. initMix(xorvals);
  109. for(int j = 0; j < 8; j++)
  110. {
  111. unkTable_[i + j] = xorvals[j];
  112. }
  113. }
  114. for(int i = 0; i < 256; i += 8)
  115. {
  116. for(int j = 0; j < 8; j++)
  117. {
  118. xorvals[j] += unkTable_[i + j];
  119. }
  120. initMix(xorvals);
  121. for(int j = 0; j < 8; j++)
  122. {
  123. unkTable_[i + j] = xorvals[j];
  124. }
  125. }
  126. scramble();
  127. counter_ = 255;
  128. }
  129. void ChecksumXorGenerator::initMix(DWORD* xorvals)
  130. {
  131. #define ROUND(base, shift) \
  132. xorvals[base] ^= xorvals[(base + 1) & 7] shift; \
  133. xorvals[(base + 3) & 7] += xorvals[base]; \
  134. xorvals[(base + 1) & 7] += xorvals[(base + 2) & 7];
  135. ROUND(0, << 0x0B);
  136. ROUND(1, >> 0x02);
  137. ROUND(2, << 0x08);
  138. ROUND(3, >> 0x10);
  139. ROUND(4, << 0x0A);
  140. ROUND(5, >> 0x04);
  141. ROUND(6, << 0x08);
  142. ROUND(7, >> 0x09);
  143. #undef ROUND
  144. }
  145. void ChecksumXorGenerator::scramble()
  146. {
  147. DWORD* local_unk = unkTable_;
  148. DWORD* local_xor = xorTable_;
  149. DWORD key0 = value0_;
  150. value2_++;
  151. DWORD key2 = value1_ + value2_;
  152. DWORD* lc_unk0 = local_unk;
  153. DWORD* lc_unk200 = lc_unk0 + 128;
  154. DWORD* lc_unk0_stop_point = lc_unk200;
  155. DWORD var_18;
  156. DWORD var_1c;
  157. while(lc_unk0 < lc_unk0_stop_point)
  158. {
  159. scrambleRound(key0 << 0x0D, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  160. scrambleRound(key0 >> 0x06, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  161. scrambleRound(key0 << 0x02, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  162. scrambleRound(key0 >> 0x10, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  163. }
  164. lc_unk200 = local_unk;
  165. while(lc_unk200 < lc_unk0_stop_point)
  166. {
  167. scrambleRound(key0 << 0x0D, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  168. scrambleRound(key0 >> 0x06, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  169. scrambleRound(key0 << 0x02, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  170. scrambleRound(key0 >> 0x10, &key0, &key2, &local_unk, &lc_unk0, &lc_unk200, &local_xor, &var_18, &var_1c);
  171. }
  172. value1_ = key2;
  173. value0_ = key0;
  174. }
  175. void ChecksumXorGenerator::scrambleRound(
  176. DWORD shiftedVal,
  177. DWORD* key0_ptr,
  178. DWORD* key2_ptr,
  179. DWORD** localunk_ptr,
  180. DWORD** lc_unk0_ptr,
  181. DWORD** lc_unk200_ptr,
  182. DWORD** localxor_ptr,
  183. DWORD* var_18_ptr,
  184. DWORD* var_1c_ptr)
  185. {
  186. *var_18_ptr = **lc_unk0_ptr;
  187. *key0_ptr = (*key0_ptr ^ shiftedVal) + **lc_unk200_ptr;
  188. *lc_unk200_ptr = *lc_unk200_ptr + 1;
  189. DWORD res = Crazy_XOR_01(*localunk_ptr, *var_18_ptr);
  190. *var_1c_ptr = res + *key0_ptr + *key2_ptr;
  191. **lc_unk0_ptr = *var_1c_ptr;
  192. *lc_unk0_ptr = *lc_unk0_ptr + 1;
  193. res = Crazy_XOR_01(*localunk_ptr, *var_1c_ptr >> 8);
  194. *key2_ptr = res + *var_18_ptr;
  195. **localxor_ptr = *key2_ptr;
  196. *localxor_ptr = *localxor_ptr + 1;
  197. }
  198. DWORD ChecksumXorGenerator::Crazy_XOR_01(const DWORD* data, DWORD index)
  199. {
  200. return *(const DWORD*)((const BYTE*)data + (index & 0x3FC));
  201. }