SerialDialog.cpp 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435
  1. /*
  2. ** Command & Conquer Renegade(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  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 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** GNU General Public License for more details.
  14. **
  15. ** You should have received a copy of the GNU General Public License
  16. ** along with this program. If not, see <http://www.gnu.org/licenses/>.
  17. */
  18. /***********************************************************************************************
  19. *** Confidential - Westwood Studios ***
  20. ***********************************************************************************************
  21. * *
  22. * Project Name : Installer *
  23. * *
  24. * $Archive:: /Commando/Code/Installer/SerialDialog.cpp $*
  25. * *
  26. * $Author:: Ian_l $*
  27. * *
  28. * $Modtime:: 1/15/02 11:09a $*
  29. * *
  30. * $Revision:: 10 $*
  31. * *
  32. *---------------------------------------------------------------------------------------------*
  33. * Functions: *
  34. * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  35. // Includes.
  36. #include "SerialDialog.h"
  37. #include "CodeControl.h"
  38. #include "EditCtrl.h"
  39. #include "Installer.h"
  40. #include "Resource.h"
  41. #include "Translator.h"
  42. // Defines.
  43. #define EDIT_CONTROL_COUNT 4
  44. // Forward declarations.
  45. unsigned int Check_Sum (char *str);
  46. // Static data.
  47. static const int _EditControlIds [EDIT_CONTROL_COUNT] = {IDC_SERIAL_EDIT1,
  48. IDC_SERIAL_EDIT2,
  49. IDC_SERIAL_EDIT3,
  50. IDC_SERIAL_EDIT4};
  51. static const int _EditControlLengths [EDIT_CONTROL_COUNT] = {6, 6, 6, 4};
  52. static char *_SerialNumberLowRange;
  53. static char *_SerialNumberHighRange;
  54. /***********************************************************************************************
  55. * SerialDialogClass::On_Init_Dialog -- *
  56. * *
  57. * INPUT: *
  58. * *
  59. * OUTPUT: *
  60. * *
  61. * WARNINGS: *
  62. * *
  63. * HISTORY: *
  64. * 08/22/01 IML : Created. *
  65. *=============================================================================================*/
  66. void SerialDialogClass::On_Init_Dialog (void)
  67. {
  68. if (!_Installer.Beta_Test()) {
  69. #if USE_QA_SERIAL_NOS
  70. _SerialNumberLowRange = "0661";
  71. _SerialNumberHighRange = "0661";
  72. #else
  73. _SerialNumberLowRange = "0559";
  74. _SerialNumberHighRange = "0660";
  75. #endif
  76. } else {
  77. _SerialNumberLowRange = "0663";
  78. _SerialNumberHighRange = "0663";
  79. }
  80. #if NDEBUG
  81. #if USE_QA_SERIAL_NOS
  82. Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass (_SerialNumberLowRange));
  83. #endif
  84. #else
  85. // Initialize with a valid serial number.
  86. if (!_Installer.Beta_Test()) {
  87. #if USE_QA_SERIAL_NOS
  88. Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("066146"));
  89. Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("321463"));
  90. Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("028258"));
  91. Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("8591"));
  92. #else
  93. Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("065906"));
  94. Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("044792"));
  95. Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("767144"));
  96. Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("4915"));
  97. #endif
  98. } else {
  99. Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("066390"));
  100. Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("274825"));
  101. Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("508134"));
  102. Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("6328"));
  103. }
  104. #endif
  105. InstallMenuDialogClass::On_Init_Dialog();
  106. }
  107. /***********************************************************************************************
  108. * SerialDialogClass::On_Unicode_Char -- *
  109. * *
  110. * INPUT: *
  111. * *
  112. * OUTPUT: *
  113. * *
  114. * WARNINGS: *
  115. * *
  116. * HISTORY: *
  117. * 08/22/01 IML : Created. *
  118. *=============================================================================================*/
  119. void SerialDialogClass::On_Unicode_Char (uint16 unicode)
  120. {
  121. // Scan the edit controls for input focus...
  122. for (unsigned i = 0; i < EDIT_CONTROL_COUNT; i++) {
  123. EditCtrlClass *editcontrol = Get_Dlg_Item (_EditControlIds [i])->As_EditCtrlClass();
  124. // Does this control have focus?
  125. if (editcontrol->Has_Focus()) {
  126. int textlength = wcslen (editcontrol->Get_Text());
  127. // Is this key one of the edit keys?
  128. switch (unicode) {
  129. case VK_BACK:
  130. if (textlength == 0) {
  131. if (i > 0) {
  132. EditCtrlClass *preveditcontrol = Get_Dlg_Item (_EditControlIds [i - 1])->As_EditCtrlClass();
  133. preveditcontrol->Set_Focus();
  134. preveditcontrol->Set_Sel (-1, -1);
  135. }
  136. } else {
  137. InstallMenuDialogClass::On_Unicode_Char (unicode);
  138. }
  139. break;
  140. case VK_DELETE:
  141. case VK_HOME:
  142. case VK_END:
  143. case VK_LEFT:
  144. case VK_RIGHT:
  145. case VK_RETURN:
  146. case VK_UP:
  147. case VK_DOWN:
  148. case VK_TAB:
  149. // Process the key.
  150. InstallMenuDialogClass::On_Unicode_Char (unicode);
  151. break;
  152. default:
  153. // Is it a numeric key?
  154. if ((unicode >= L'0') && (unicode <= L'9')) {
  155. if (textlength < _EditControlLengths [i]) {
  156. // Process the key.
  157. InstallMenuDialogClass::On_Unicode_Char (unicode);
  158. textlength = wcslen (editcontrol->Get_Text());
  159. // If the edit control is now full and the caret is at the end...
  160. if ((textlength == _EditControlLengths [i]) && (textlength == editcontrol->Get_Caret_Pos())) {
  161. // If the next edit control is empty switch focus to it.
  162. if (i < EDIT_CONTROL_COUNT - 1) {
  163. EditCtrlClass *nexteditcontrol = Get_Dlg_Item (_EditControlIds [i + 1])->As_EditCtrlClass();
  164. if (wcslen (nexteditcontrol->Get_Text()) == 0) {
  165. nexteditcontrol->Set_Focus();
  166. }
  167. }
  168. }
  169. } else {
  170. if ((textlength == _EditControlLengths [i]) && (textlength == editcontrol->Get_Caret_Pos())) {
  171. // If the next edit control is empty switch focus to it and process the key.
  172. if (i < EDIT_CONTROL_COUNT - 1) {
  173. EditCtrlClass *nexteditcontrol = Get_Dlg_Item (_EditControlIds [i + 1])->As_EditCtrlClass();
  174. if (wcslen (nexteditcontrol->Get_Text()) == 0) {
  175. nexteditcontrol->Set_Focus();
  176. InstallMenuDialogClass::On_Unicode_Char (unicode);
  177. }
  178. }
  179. }
  180. }
  181. }
  182. }
  183. break;
  184. }
  185. }
  186. }
  187. /***********************************************************************************************
  188. * SerialDialogClass::On_Command -- *
  189. * *
  190. * INPUT: *
  191. * *
  192. * OUTPUT: *
  193. * *
  194. * WARNINGS: *
  195. * *
  196. * HISTORY: *
  197. * 08/22/01 IML : Created. *
  198. *=============================================================================================*/
  199. void SerialDialogClass::On_Command (int ctrl_id, int message_id, DWORD param)
  200. {
  201. bool valid = true;
  202. switch (ctrl_id) {
  203. case IDOK:
  204. {
  205. StringClass serialnumber;
  206. valid = Get_Serial_Number (serialnumber);
  207. if (valid) {
  208. #if NDEBUG
  209. StringClass lowrange (_SerialNumberLowRange);
  210. StringClass highrange (_SerialNumberHighRange);
  211. // Limit range of serial number.
  212. valid = !(((_strnicmp (serialnumber, lowrange, 4) < 0) || (_strnicmp (serialnumber, highrange, 4) > 0)));
  213. #endif
  214. if (valid) {
  215. unsigned i, v;
  216. // Scan the string for all zeros.
  217. v = 0;
  218. for (i = 0; i < (unsigned) serialnumber.Get_Length(); i++) {
  219. v += *(serialnumber.Peek_Buffer() + i) - '0';
  220. }
  221. valid = (v > 0);
  222. if (valid) {
  223. const unsigned offset = 18;
  224. StringClass checksumstring (serialnumber);
  225. unsigned checksum;
  226. // Apply checksum test.
  227. *(checksumstring.Peek_Buffer() + offset) = '\0';
  228. checksum = Check_Sum (checksumstring.Peek_Buffer());
  229. valid = (checksum == (uint32) atol (serialnumber.Peek_Buffer() + offset));
  230. }
  231. }
  232. }
  233. break;
  234. }
  235. default:
  236. // Do nothing.
  237. break;
  238. }
  239. if (valid) {
  240. InstallMenuDialogClass::On_Command (ctrl_id, message_id, param);
  241. } else {
  242. MessageBoxClass::Do_Dialog (TxWideStringClass (IDS_WARNING), TxWideStringClass (IDS_INCORRECT_SERIAL), MessageBoxClass::MESSAGE_BOX_TYPE_OK, this);
  243. }
  244. }
  245. /***********************************************************************************************
  246. * SerialDialogClass::Get_Serial_Number -- *
  247. * *
  248. * INPUT: *
  249. * *
  250. * OUTPUT: *
  251. * *
  252. * WARNINGS: *
  253. * *
  254. * HISTORY: *
  255. * 08/22/01 IML : Created. *
  256. *=============================================================================================*/
  257. bool SerialDialogClass::Get_Serial_Number (StringClass &serialnumber)
  258. {
  259. bool valid = false;
  260. for (unsigned i = 0; i < EDIT_CONTROL_COUNT; i++) {
  261. EditCtrlClass *editcontrol = Get_Dlg_Item (_EditControlIds [i])->As_EditCtrlClass();
  262. // Extract the serial number.
  263. WideStringClass widedigits (editcontrol->Get_Text());
  264. StringClass digits;
  265. // Ensure that the text contains correct no. of characters.
  266. // NOTE: Non-numeric characters have already been filtered out, so no need to check for this.
  267. valid = (widedigits.Get_Length() == _EditControlLengths [i]);
  268. if (!valid) {
  269. break;
  270. }
  271. widedigits.Convert_To (digits);
  272. serialnumber += digits;
  273. }
  274. return (valid);
  275. }
  276. /***********************************************************************************************
  277. * SerialDialogClass::CheckSum -- Generate a checksum number between 0...9999 from a null *
  278. * terminated string of numbers. *
  279. * *
  280. * INPUT: none. *
  281. * *
  282. * OUTPUT: none. *
  283. * *
  284. * WARNINGS: *
  285. * *
  286. * The checksum is divided into 2 parts. The first is computed by grabbing 7 digits at a *
  287. * grabbing 7 digits at a time and summing them mod 97. The second part is computed by *
  288. * grabbing 5 digits at a time and The second part is computed by grabbing 5 digits at a *
  289. * time and summing them mod 93. *
  290. * *
  291. * Note that it's important that 97 & 93 are prime (or at least relatively prime...) and *
  292. * less than 100. 7 & 5 were chosen because they can stay out of phase for the length of *
  293. * the input string. *
  294. * *
  295. * The two components together make the checksum. This will catch all errors of 1 & 2 *
  296. * digits and many other errors, but the proof is left as an exercise to the reader. *
  297. * *
  298. * Note, if you try and checksum ammounts over 30 chars the above guarantees will fail. *
  299. * (That's the number of chars that the skip & offset values will stay out of phase). * *
  300. * *
  301. * Note: The checksum of all zeros will be 0 so you need to special case the check to not *
  302. * allow this (since it's a pretty obvious thing for a user to type all 0's to try and *
  303. * cheat the system). *
  304. * *
  305. * HISTORY: *
  306. * 10/30/1995 MML : Created. *
  307. *=============================================================================================*/
  308. unsigned int Check_Sum (char *str)
  309. {
  310. unsigned int counter = 0;
  311. unsigned int retval = 0;
  312. unsigned int group = 0;
  313. int len = strlen( str );
  314. int mult = 0;
  315. int i;
  316. int j;
  317. const int skipa = 7; // part A's skip value
  318. const int skipb = 5; // ... part B
  319. const int offsa = -5; // Everywhere the skips are in phase is a place where an 2nd error can occur and not be detected.
  320. //---------------------------------------------------------------------------
  321. // Part1
  322. //---------------------------------------------------------------------------
  323. counter = 0;
  324. for ( i = offsa; i < len; i += skipa ) {
  325. mult = 1;
  326. for ( j = 1; j < skipa; j++ ) {
  327. mult *= 10;
  328. }
  329. group = 0;
  330. for ( j = i; j < MIN( len, i+skipa ); j++ ) {
  331. if ( j >= 0 ) {
  332. group += ((int)( str[j] - '0' )) * mult;
  333. }
  334. mult /= 10;
  335. }
  336. counter += group;
  337. counter %= 97;
  338. }
  339. retval = counter * 100;
  340. //---------------------------------------------------------------------------
  341. // Part2
  342. //---------------------------------------------------------------------------
  343. counter = 0;
  344. for ( i = 0; i < len; i += skipb ) {
  345. mult = 1;
  346. for ( j = 1; j < skipb; j++ ) {
  347. mult *= 10;
  348. }
  349. group = 0;
  350. for ( j = i; j < MIN( len, i+skipb ); j++ ) {
  351. if ( j >= 0 ) {
  352. group += ((int)( str[j] - '0' )) * mult;
  353. }
  354. mult /= 10;
  355. }
  356. counter += group;
  357. counter %= 93;
  358. }
  359. retval += counter;
  360. return (retval);
  361. }