00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifdef HAVE_CONFIG_H
00026 #include <config.h>
00027 #endif
00028
00029 #include <cstring>
00030
00031 #include "model/Password.hh"
00032
00033 using namespace mpg;
00034
00035 const wxString Password::ALPHABET(wxT("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
00036 "abcdefghijklmnopqrstuvwxyz?- "));
00037
00038 Password::Password() {
00039 std::memset(data, 0, PASSWORD_LENGTH_BYTES);
00040 encode();
00041 }
00042
00043 Password::Password(const wxString &password, bool fixChecksum)
00044 throw(InvalidPasswordException) {
00045 if (password.Length() != PASSWORD_LENGTH) {
00046 throw InvalidPasswordException("Invalid Password Length",
00047 INVALID_LENGTH);
00048 }
00049
00050 decode(password, fixChecksum);
00051
00052
00053 encode();
00054 }
00055
00056 bool Password::getBit(int bit) const throw(std::out_of_range) {
00057 if ((bit < 0) || (bit > PASSWORD_BITS)) {
00058 throw std::out_of_range("invalid bit: must be in range [0, 127]");
00059 }
00060
00061 int byte = bit / 8;
00062
00063 return (data[byte] & (1 << (bit % 8)));
00064 }
00065
00066 void Password::setBit(int bit, bool value) throw(std::out_of_range) {
00067 if ((bit < 0) || (bit > PASSWORD_BITS)) {
00068 throw std::out_of_range("invalid bit: must be in range [0, 127]");
00069 }
00070
00071 int byte = bit / 8;
00072
00073 if (value) {
00074 data[byte] |= (1 << (bit % 8));
00075 } else {
00076 data[byte] &= ~(1 << (bit % 8));
00077 }
00078
00079 encode();
00080 }
00081
00082 wxUint32 Password::getGameTime() const {
00083 const wxUint32 *ptr = reinterpret_cast<const wxUint32 *>(data +
00084 GAME_TIME_BYTE);
00085
00086 return wxUINT32_SWAP_ON_BE(*ptr);
00087 }
00088
00089 void Password::setGameTime(wxUint32 time) {
00090 wxUint32 *ptr = reinterpret_cast<wxUint32 *>(data + GAME_TIME_BYTE);
00091 *ptr = wxUINT32_SWAP_ON_BE(time);
00092
00093 encode();
00094 }
00095
00096 void Password::setMissiles(unsigned char missiles) {
00097 data[MISSILE_COUNT_BYTE] = missiles;
00098
00099 encode();
00100 }
00101
00102 void Password::setShift(unsigned char shift) {
00103 data[SHIFT_BYTE] = shift;
00104
00105 encode();
00106 }
00107
00108 unsigned char Password::calcChecksum() const {
00109 unsigned char checksum = 0;
00110
00111 for (int i = 16; i >= 0; --i) {
00112 checksum += data[i];
00113 }
00114
00115 return checksum;
00116 }
00117
00118 void Password::decode(const wxString &password, bool fixChecksum)
00119 throw(InvalidPasswordException) {
00120
00121 unsigned char metroid[PASSWORD_LENGTH];
00122
00123 for (unsigned int i = 0; i < PASSWORD_LENGTH; ++i) {
00124 if (password[i] == wxT(' ')) {
00125 metroid[i] = SPACE_VALUE;
00126 } else {
00127 int pos = ALPHABET.Find(password[i]);
00128
00129 if (pos < 0) {
00130 throw InvalidPasswordException("Invalid Character in Password",
00131 INVALID_ALPHABET);
00132 }
00133
00134 metroid[i] = pos;
00135 }
00136 }
00137
00138
00139 unsigned char *ptr = data;
00140
00141 for (int i = 0; i < 6; ++i) {
00142 unsigned char *temp = metroid + (i * 4);
00143
00144 *ptr = (*temp << 2) | (*(temp + 1) >> 4);
00145 ++ptr;
00146
00147 *ptr = (*(temp + 1) << 4) | (*(temp + 2) >> 2);
00148 ++ptr;
00149
00150 *ptr = (*(temp + 2) << 6) | *(temp + 3);
00151 ++ptr;
00152 }
00153
00154
00155 short carry = 1, carryTemp;
00156 int count = data[SHIFT_BYTE];
00157
00158 for (int i = 0; i < count; ++i) {
00159 unsigned char temp = data[15];
00160
00161 for (int j = 15; j >= 0; --j) {
00162 carryTemp = (data[j] & 0x80) >> 7;
00163 data[j] <<= 1;
00164 data[j] |= (carry & 0x1);
00165 carry = carryTemp;
00166 }
00167
00168 carryTemp = (temp & 0x80) >> 7;
00169 temp <<= 1;
00170 temp |= (carry & 0x1);
00171 carry = carryTemp;
00172
00173 data[15] = temp;
00174 }
00175
00176
00177 unsigned char checksum = calcChecksum();
00178
00179 if (data[CHECKSUM_BYTE] != checksum) {
00180 if (!fixChecksum) {
00181 throw InvalidPasswordException("Checksum Verification Failed",
00182 INVALID_CHECKSUM);
00183 }
00184 }
00185 }
00186
00187 void Password::encode() {
00188
00189 data[CHECKSUM_BYTE] = calcChecksum();
00190
00191
00192 unsigned char raw[PASSWORD_LENGTH_BYTES];
00193 std::memcpy(raw, data, PASSWORD_LENGTH_BYTES);
00194
00195
00196 short carry = 1, carryTemp;
00197 int count = raw[SHIFT_BYTE];
00198
00199 for (int i = 0; i < count; ++i) {
00200 unsigned char temp = *raw;
00201
00202 for (int j = 0; j < 16; ++j) {
00203 carryTemp = raw[j] & 0x1;
00204 raw[j] >>= 1;
00205 raw[j] |= (carry & 0x1) << 7;
00206 carry = carryTemp;
00207 }
00208
00209 carryTemp = temp & 0x1;
00210 temp >>= 1;
00211 temp |= (carry & 0x1) << 7;
00212 carry = carryTemp;
00213
00214 *raw = temp;
00215 }
00216
00217
00218 unsigned char metroid[PASSWORD_LENGTH];
00219 unsigned char *ptr = metroid;
00220
00221 for (int i = 0; i < 6; ++i) {
00222 unsigned char *temp = raw + (i * 3);
00223
00224 *ptr = *temp >> 2;
00225 ++ptr;
00226
00227 *ptr = ((*temp & 0x3) << 4) | (*(temp + 1) >> 4);
00228 ++ptr;
00229
00230 *ptr = ((*(temp + 1) & 0xF) << 2) | (*(temp + 2) >> 6);
00231 ++ptr;
00232
00233 *ptr = (*(temp + 2) & 0x3F);
00234 ++ptr;
00235 }
00236
00237
00238 encoded.Empty();
00239
00240 for (unsigned int i = 0; i < PASSWORD_LENGTH; ++i) {
00241 encoded.Append(ALPHABET[metroid[i]]);
00242 }
00243 }
00244