This repository has been archived on 2025-02-27. You can view files and clone it, but cannot push or open issues or pull requests.
CnC_Renegade/Code/Installer/SerialDialog.cpp

436 lines
17 KiB
C++
Raw Permalink Normal View History

/*
** Command & Conquer Renegade(tm)
** Copyright 2025 Electronic Arts Inc.
**
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation, either version 3 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/***********************************************************************************************
*** Confidential - Westwood Studios ***
***********************************************************************************************
* *
* Project Name : Installer *
* *
* $Archive:: /Commando/Code/Installer/SerialDialog.cpp $*
* *
* $Author:: Ian_l $*
* *
* $Modtime:: 1/15/02 11:09a $*
* *
* $Revision:: 10 $*
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
// Includes.
#include "SerialDialog.h"
#include "CodeControl.h"
#include "EditCtrl.h"
#include "Installer.h"
#include "Resource.h"
#include "Translator.h"
// Defines.
#define EDIT_CONTROL_COUNT 4
// Forward declarations.
unsigned int Check_Sum (char *str);
// Static data.
static const int _EditControlIds [EDIT_CONTROL_COUNT] = {IDC_SERIAL_EDIT1,
IDC_SERIAL_EDIT2,
IDC_SERIAL_EDIT3,
IDC_SERIAL_EDIT4};
static const int _EditControlLengths [EDIT_CONTROL_COUNT] = {6, 6, 6, 4};
static char *_SerialNumberLowRange;
static char *_SerialNumberHighRange;
/***********************************************************************************************
* SerialDialogClass::On_Init_Dialog -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void SerialDialogClass::On_Init_Dialog (void)
{
if (!_Installer.Beta_Test()) {
#if USE_QA_SERIAL_NOS
_SerialNumberLowRange = "0661";
_SerialNumberHighRange = "0661";
#else
_SerialNumberLowRange = "0559";
_SerialNumberHighRange = "0660";
#endif
} else {
_SerialNumberLowRange = "0663";
_SerialNumberHighRange = "0663";
}
#if NDEBUG
#if USE_QA_SERIAL_NOS
Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass (_SerialNumberLowRange));
#endif
#else
// Initialize with a valid serial number.
if (!_Installer.Beta_Test()) {
#if USE_QA_SERIAL_NOS
Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("066146"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("321463"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("028258"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("8591"));
#else
Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("065906"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("044792"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("767144"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("4915"));
#endif
} else {
Set_Dlg_Item_Text (IDC_SERIAL_EDIT1, WideStringClass ("066390"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT2, WideStringClass ("274825"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT3, WideStringClass ("508134"));
Set_Dlg_Item_Text (IDC_SERIAL_EDIT4, WideStringClass ("6328"));
}
#endif
InstallMenuDialogClass::On_Init_Dialog();
}
/***********************************************************************************************
* SerialDialogClass::On_Unicode_Char -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void SerialDialogClass::On_Unicode_Char (uint16 unicode)
{
// Scan the edit controls for input focus...
for (unsigned i = 0; i < EDIT_CONTROL_COUNT; i++) {
EditCtrlClass *editcontrol = Get_Dlg_Item (_EditControlIds [i])->As_EditCtrlClass();
// Does this control have focus?
if (editcontrol->Has_Focus()) {
int textlength = wcslen (editcontrol->Get_Text());
// Is this key one of the edit keys?
switch (unicode) {
case VK_BACK:
if (textlength == 0) {
if (i > 0) {
EditCtrlClass *preveditcontrol = Get_Dlg_Item (_EditControlIds [i - 1])->As_EditCtrlClass();
preveditcontrol->Set_Focus();
preveditcontrol->Set_Sel (-1, -1);
}
} else {
InstallMenuDialogClass::On_Unicode_Char (unicode);
}
break;
case VK_DELETE:
case VK_HOME:
case VK_END:
case VK_LEFT:
case VK_RIGHT:
case VK_RETURN:
case VK_UP:
case VK_DOWN:
case VK_TAB:
// Process the key.
InstallMenuDialogClass::On_Unicode_Char (unicode);
break;
default:
// Is it a numeric key?
if ((unicode >= L'0') && (unicode <= L'9')) {
if (textlength < _EditControlLengths [i]) {
// Process the key.
InstallMenuDialogClass::On_Unicode_Char (unicode);
textlength = wcslen (editcontrol->Get_Text());
// If the edit control is now full and the caret is at the end...
if ((textlength == _EditControlLengths [i]) && (textlength == editcontrol->Get_Caret_Pos())) {
// If the next edit control is empty switch focus to it.
if (i < EDIT_CONTROL_COUNT - 1) {
EditCtrlClass *nexteditcontrol = Get_Dlg_Item (_EditControlIds [i + 1])->As_EditCtrlClass();
if (wcslen (nexteditcontrol->Get_Text()) == 0) {
nexteditcontrol->Set_Focus();
}
}
}
} else {
if ((textlength == _EditControlLengths [i]) && (textlength == editcontrol->Get_Caret_Pos())) {
// If the next edit control is empty switch focus to it and process the key.
if (i < EDIT_CONTROL_COUNT - 1) {
EditCtrlClass *nexteditcontrol = Get_Dlg_Item (_EditControlIds [i + 1])->As_EditCtrlClass();
if (wcslen (nexteditcontrol->Get_Text()) == 0) {
nexteditcontrol->Set_Focus();
InstallMenuDialogClass::On_Unicode_Char (unicode);
}
}
}
}
}
}
break;
}
}
}
/***********************************************************************************************
* SerialDialogClass::On_Command -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
void SerialDialogClass::On_Command (int ctrl_id, int message_id, DWORD param)
{
bool valid = true;
switch (ctrl_id) {
case IDOK:
{
StringClass serialnumber;
valid = Get_Serial_Number (serialnumber);
if (valid) {
#if NDEBUG
StringClass lowrange (_SerialNumberLowRange);
StringClass highrange (_SerialNumberHighRange);
// Limit range of serial number.
valid = !(((_strnicmp (serialnumber, lowrange, 4) < 0) || (_strnicmp (serialnumber, highrange, 4) > 0)));
#endif
if (valid) {
unsigned i, v;
// Scan the string for all zeros.
v = 0;
for (i = 0; i < (unsigned) serialnumber.Get_Length(); i++) {
v += *(serialnumber.Peek_Buffer() + i) - '0';
}
valid = (v > 0);
if (valid) {
const unsigned offset = 18;
StringClass checksumstring (serialnumber);
unsigned checksum;
// Apply checksum test.
*(checksumstring.Peek_Buffer() + offset) = '\0';
checksum = Check_Sum (checksumstring.Peek_Buffer());
valid = (checksum == (uint32) atol (serialnumber.Peek_Buffer() + offset));
}
}
}
break;
}
default:
// Do nothing.
break;
}
if (valid) {
InstallMenuDialogClass::On_Command (ctrl_id, message_id, param);
} else {
MessageBoxClass::Do_Dialog (TxWideStringClass (IDS_WARNING), TxWideStringClass (IDS_INCORRECT_SERIAL), MessageBoxClass::MESSAGE_BOX_TYPE_OK, this);
}
}
/***********************************************************************************************
* SerialDialogClass::Get_Serial_Number -- *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 08/22/01 IML : Created. *
*=============================================================================================*/
bool SerialDialogClass::Get_Serial_Number (StringClass &serialnumber)
{
bool valid = false;
for (unsigned i = 0; i < EDIT_CONTROL_COUNT; i++) {
EditCtrlClass *editcontrol = Get_Dlg_Item (_EditControlIds [i])->As_EditCtrlClass();
// Extract the serial number.
WideStringClass widedigits (editcontrol->Get_Text());
StringClass digits;
// Ensure that the text contains correct no. of characters.
// NOTE: Non-numeric characters have already been filtered out, so no need to check for this.
valid = (widedigits.Get_Length() == _EditControlLengths [i]);
if (!valid) {
break;
}
widedigits.Convert_To (digits);
serialnumber += digits;
}
return (valid);
}
/***********************************************************************************************
* SerialDialogClass::CheckSum -- Generate a checksum number between 0...9999 from a null *
* terminated string of numbers. *
* *
* INPUT: none. *
* *
* OUTPUT: none. *
* *
* WARNINGS: *
* *
* The checksum is divided into 2 parts. The first is computed by grabbing 7 digits at a *
* grabbing 7 digits at a time and summing them mod 97. The second part is computed by *
* grabbing 5 digits at a time and The second part is computed by grabbing 5 digits at a *
* time and summing them mod 93. *
* *
* Note that it's important that 97 & 93 are prime (or at least relatively prime...) and *
* less than 100. 7 & 5 were chosen because they can stay out of phase for the length of *
* the input string. *
* *
* The two components together make the checksum. This will catch all errors of 1 & 2 *
* digits and many other errors, but the proof is left as an exercise to the reader. *
* *
* Note, if you try and checksum ammounts over 30 chars the above guarantees will fail. *
* (That's the number of chars that the skip & offset values will stay out of phase). * *
* *
* Note: The checksum of all zeros will be 0 so you need to special case the check to not *
* allow this (since it's a pretty obvious thing for a user to type all 0's to try and *
* cheat the system). *
* *
* HISTORY: *
* 10/30/1995 MML : Created. *
*=============================================================================================*/
unsigned int Check_Sum (char *str)
{
unsigned int counter = 0;
unsigned int retval = 0;
unsigned int group = 0;
int len = strlen( str );
int mult = 0;
int i;
int j;
const int skipa = 7; // part A's skip value
const int skipb = 5; // ... part B
const int offsa = -5; // Everywhere the skips are in phase is a place where an 2nd error can occur and not be detected.
//---------------------------------------------------------------------------
// Part1
//---------------------------------------------------------------------------
counter = 0;
for ( i = offsa; i < len; i += skipa ) {
mult = 1;
for ( j = 1; j < skipa; j++ ) {
mult *= 10;
}
group = 0;
for ( j = i; j < MIN( len, i+skipa ); j++ ) {
if ( j >= 0 ) {
group += ((int)( str[j] - '0' )) * mult;
}
mult /= 10;
}
counter += group;
counter %= 97;
}
retval = counter * 100;
//---------------------------------------------------------------------------
// Part2
//---------------------------------------------------------------------------
counter = 0;
for ( i = 0; i < len; i += skipb ) {
mult = 1;
for ( j = 1; j < skipb; j++ ) {
mult *= 10;
}
group = 0;
for ( j = i; j < MIN( len, i+skipb ); j++ ) {
if ( j >= 0 ) {
group += ((int)( str[j] - '0' )) * mult;
}
mult /= 10;
}
counter += group;
counter %= 93;
}
retval += counter;
return (retval);
}