Password.cc

Go to the documentation of this file.
00001 /*
00002  * Metroid Password Generator
00003  * Copyright (C) 2005,2007-2008 emuWorks
00004  * http://games.technoplaza.net/
00005  *
00006  * This file is part of Metroid Password Generator.
00007  *
00008  * Metroid Password Generator is free software; you can redistribute it and/or
00009  * modify it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2 of the License, or
00011  * (at your option) any later version.
00012  *
00013  * Metroid Password Generator is distributed in the hope that it will be useful,
00014  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016  * GNU General Public License for more details.
00017  *
00018  * You should have received a copy of the GNU General Public License
00019  * along with Metroid Password Generator; if not, write to the Free Software
00020  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00021  */
00022  
00023 // $Id: Password.cc,v 1.13 2008/12/17 01:04:21 jdratlif Exp $
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                                   wxT("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     // reencode just in case the checksum was fixed
00053     encode();
00054 }
00055 
00056 bool Password::getBit(int bit) const {
00057     wxASSERT((bit >= 0) && (bit < PASSWORD_BITS));
00058     
00059     int byte = bit / 8;
00060     
00061     return (data[byte] & (1 << (bit % 8)));
00062 }
00063 
00064 void Password::setBit(int bit, bool value) {
00065     wxASSERT((bit >= 0) && (bit < PASSWORD_BITS));
00066     
00067     int byte = bit / 8;
00068     
00069     if (value) {
00070         data[byte] |= (1 << (bit % 8));
00071     } else {
00072         data[byte] &= ~(1 << (bit % 8));
00073     }
00074     
00075     encode();
00076 }
00077 
00078 wxUint32 Password::getGameTime() const {
00079     const wxUint32 *ptr = reinterpret_cast<const wxUint32 *>(data +
00080                                                              GAME_TIME_BYTE);
00081     
00082     return wxUINT32_SWAP_ON_BE(*ptr);
00083 }
00084 
00085 void Password::setGameTime(wxUint32 time) {
00086     wxUint32 *ptr = reinterpret_cast<wxUint32 *>(data + GAME_TIME_BYTE);
00087     *ptr = wxUINT32_SWAP_ON_BE(time);
00088     
00089     encode();
00090 }
00091 
00092 void Password::setMissiles(unsigned char missiles) {
00093     data[MISSILE_COUNT_BYTE] = missiles;
00094     
00095     encode();
00096 }
00097 
00098 void Password::setShift(unsigned char shift) {
00099     data[SHIFT_BYTE] = shift;
00100     
00101     encode();
00102 }
00103 
00104 unsigned char Password::calcChecksum() const {
00105     unsigned char checksum = 0;
00106     
00107     for (int i = 16; i >= 0; --i) {
00108         checksum += data[i];
00109     }
00110     
00111     return checksum;
00112 }
00113 
00114 void Password::decode(const wxString &password, bool fixChecksum)
00115                       throw(InvalidPasswordException) {
00116     // convert the password string to the metroid alphabet
00117     unsigned char metroid[PASSWORD_LENGTH];
00118     
00119     for (unsigned int i = 0; i < PASSWORD_LENGTH; ++i) {
00120         if (password[i] == wxT(' ')) {
00121             metroid[i] = SPACE_VALUE;
00122         } else {
00123             int pos = ALPHABET.Find(password[i]);
00124             
00125             if (pos < 0) {
00126                 throw InvalidPasswordException("Invalid Character in Password",
00127                                                INVALID_ALPHABET);
00128             }
00129             
00130             metroid[i] = pos;
00131         }
00132     }
00133     
00134     // convert metroid password to encoded password data
00135     unsigned char *ptr = data;
00136     
00137     for (int i = 0; i < 6; ++i) {
00138         unsigned char *temp = metroid + (i * 4);
00139         
00140         *ptr = (*temp << 2) | (*(temp + 1) >> 4);
00141         ++ptr;
00142         
00143         *ptr = (*(temp + 1) << 4) | (*(temp + 2) >> 2);
00144         ++ptr;
00145         
00146         *ptr = (*(temp + 2) << 6) | *(temp + 3);
00147         ++ptr;
00148     }
00149     
00150     // decode the password data
00151     short carry = 1, carryTemp;
00152     int count = data[SHIFT_BYTE];
00153     
00154     for (int i = 0; i < count; ++i) {
00155         unsigned char temp = data[15];
00156         
00157         for (int j = 15; j >= 0; --j) {
00158             carryTemp = (data[j] & 0x80) >> 7;
00159             data[j] <<= 1;
00160             data[j] |= (carry & 0x1);
00161             carry = carryTemp;
00162         }
00163         
00164         carryTemp = (temp & 0x80) >> 7;
00165         temp <<= 1;
00166         temp |= (carry & 0x1);
00167         carry = carryTemp;
00168         
00169         data[15] = temp;
00170     }
00171     
00172     // confirm the checksum and fix if requested
00173     unsigned char checksum = calcChecksum();
00174     
00175     if (data[CHECKSUM_BYTE] != checksum) {
00176         if (!fixChecksum) {
00177             throw InvalidPasswordException("Checksum Verification Failed",
00178                                            INVALID_CHECKSUM);
00179         }
00180     }
00181 }
00182 
00183 void Password::encode() {
00184     // calculate the checksum
00185     data[CHECKSUM_BYTE] = calcChecksum();
00186     
00187     // copy the raw password data
00188     unsigned char raw[PASSWORD_LENGTH_BYTES];
00189     std::memcpy(raw, data, PASSWORD_LENGTH_BYTES);
00190     
00191     // encode the password data
00192     short carry = 1, carryTemp;
00193     int count = raw[SHIFT_BYTE];
00194     
00195     for (int i = 0; i < count; ++i) {
00196         unsigned char temp = *raw;
00197         
00198         for (int j = 0; j < 16; ++j) {
00199             carryTemp = raw[j] & 0x1;
00200             raw[j] >>= 1;
00201             raw[j] |= (carry & 0x1) << 7;
00202             carry = carryTemp;
00203         }
00204         
00205         carryTemp = temp & 0x1;
00206         temp >>= 1;
00207         temp |= (carry & 0x1) << 7;
00208         carry = carryTemp;
00209         
00210         *raw = temp;
00211     }
00212     
00213     // convert it to the metroid alphabet
00214     unsigned char metroid[PASSWORD_LENGTH];
00215     unsigned char *ptr = metroid;
00216     
00217     for (int i = 0; i < 6; ++i) {
00218         unsigned char *temp = raw + (i * 3);
00219         
00220         *ptr = *temp >> 2;
00221         ++ptr;
00222         
00223         *ptr = ((*temp & 0x3) << 4) | (*(temp + 1) >> 4);
00224         ++ptr;
00225         
00226         *ptr = ((*(temp + 1) & 0xF) << 2) | (*(temp + 2) >> 6);
00227         ++ptr;
00228         
00229         *ptr = (*(temp + 2) & 0x3F);
00230         ++ptr;
00231     }
00232     
00233     // convert metroid password to wxString
00234     encoded.Empty();
00235     
00236     for (unsigned int i = 0; i < PASSWORD_LENGTH; ++i) {
00237         encoded.Append(ALPHABET[metroid[i]]);
00238     }
00239 }
00240 

Generated on Tue Dec 16 20:16:56 2008 for Metroid Password Generator by  doxygen 1.5.4