#include "Database.h" #include extern Logger* debug; Database::Database(bool extended_info) { lobby_num_games = 0; lobby = new string[LOBBY_SIZE]; lobby[LOBBY_ID] = "1"; lobby[LOBBY_NAME] = "bfbc2_01"; lobby[LOBBY_LOCALE] = "en_US"; lobby[LOBBY_MAX_GAMES] = "1000"; this->extended_info = extended_info; initializeData(); } Database::~Database() { delete[] lobby; for(vector::iterator it = games.begin(); it != games.end(); it++) { if(it->key) delete[] it->key; if(it->gdet) delete[] it->gdet; } games.clear(); personas.clear(); users.clear(); } void Database::initializeData() { // these entries are always there (game servers login with them) list_entry server_persona = {1, "bfbc2.server.p", new string[PERSONA_SIZE]}; server_persona.data[USER_ID] = "1"; server_persona.data[USER_EMAIL] = "bfbc2.server.pc@ea.com"; server_persona.data[PLAYER_ID] = "0"; server_persona.data[PERSONA_ONLINE] = "1"; personas.insert(server_persona); server_persona.id = 2; server_persona.name = "bfbc.server.ps"; server_persona.data = new string[PERSONA_SIZE]; server_persona.data[USER_ID] = "2"; server_persona.data[USER_EMAIL] = "bfbc.server.ps3@ea.com"; server_persona.data[PLAYER_ID] = "0"; server_persona.data[PERSONA_ONLINE] = "1"; personas.insert(server_persona); server_persona.id = 3; server_persona.name = "bfbc.server.xe"; server_persona.data = new string[PERSONA_SIZE]; server_persona.data[USER_ID] = "3"; server_persona.data[USER_EMAIL] = "bfbc.server.xenon@ea.com"; server_persona.data[PLAYER_ID] = "0"; server_persona.data[PERSONA_ONLINE] = "1"; personas.insert(server_persona); list_entry server_user = {1, "bfbc2.server.pc@ea.com", new string[USER_SIZE]}; server_user.data[PASSWORD] = "Che6rEPA"; server_user.data[COUNTRY] = ""; server_user.data[BIRTHDAY] = ""; server_user.data[USER_ONLINE] = "1"; users.insert(server_user); server_user.id = 2; server_user.name = "bfbc.server.ps3@ea.com"; server_user.data = new string[USER_SIZE]; server_user.data[PASSWORD] = "zAmeH7bR"; server_user.data[COUNTRY] = ""; server_user.data[BIRTHDAY] = ""; server_user.data[USER_ONLINE] = "1"; users.insert(server_user); server_user.id = 3; server_user.name = "bfbc.server.xenon@ea.com"; server_user.data = new string[USER_SIZE]; server_user.data[PASSWORD] = "B8ApRavE"; server_user.data[COUNTRY] = ""; server_user.data[BIRTHDAY] = ""; server_user.data[USER_ONLINE] = "1"; users.insert(server_user); string directory = "./database/users.lst"; if(!loadFileData(directory.c_str(), USERS)) debug->notification(3, DATABASE, "Could not load users table from \"%s\", using an empty table for both users and personas instead.", directory.c_str()); else { directory = "./database/personas.lst"; if(!loadFileData(directory.c_str(), PERSONAS)) debug->notification(3, DATABASE, "Could not load personas table from \"%s\", using an empty table instead.", directory.c_str()); } debug->notification(1, DATABASE, "Finished initializing database"); } void Database::saveDatabase() { stringstream buffer; bool idsAvailable = false; while(!availableUserSlots.empty()) { buffer << availableUserSlots.front() << "|"; availableUserSlots.pop_front(); if(!idsAvailable) idsAvailable = true; } if(idsAvailable) buffer << "\n\n"; list_id& uli = users.get(); list_id::iterator it; while((it = uli.begin()) != uli.end()) { if(it->id != 1 && it->id != 2 && it->id != 3) // don't save the server stuff in the external file { buffer << it->id << "\f" << it->name << "\f" << it->data[PASSWORD] << "\f" << it->data[COUNTRY] << "\f" << it->data[BIRTHDAY] << "\f" << "0" << "\n"; // we save this when program exits and at that point everybody is set offline } delete[] it->data; uli.erase(it); } saveFileData("./database/users.lst", buffer.str()); buffer.str(""); idsAvailable = false; while(!availablePersonaSlots.empty()) { buffer << availablePersonaSlots.front() << "|"; availablePersonaSlots.pop_front(); if(!idsAvailable) idsAvailable = true; } if(idsAvailable) buffer << "\n\n"; list_id& pli = personas.get(); while((it = pli.begin()) != pli.end()) { if(it->id != 1 && it->id != 2 && it->id != 3) // don't save the server stuff in the external file { buffer << it->id << "\f" << it->name << "\f" << it->data[USER_ID] << "\f" << it->data[USER_EMAIL] << "\f" << it->data[PLAYER_ID] << "\f" << "0" << "\n"; // we save this when program exits and at that point everybody is set offline } delete[] it->data; pli.erase(it); } saveFileData("./database/personas.lst", buffer.str()); } bool Database::loadFileData(const char* file, int struct_type) { bool loadSuccess = true; string tempPath = file; tempPath.append(".tmp"); // make a temporary backup of the .lst file (in case something goes wrong, or is this overcautious?) filesystem::path source_file(file), dest_file(tempPath); if(!filesystem::exists(source_file)) { debug->warning(1, DATABASE, "There is a problem opening the file %s", file); return false; } filesystem::copy_file(source_file, dest_file); // open the actual .lst file ifstream in(file, ifstream::in); if(!in.is_open() || !in.good()) return false; stringstream buffer; buffer << in.rdbuf(); string list = buffer.str(); in.close(); if(struct_type == USERS) usersData = buffer.str(); else personasData = buffer.str(); // first line contains available id's in the list, if there is no first line the next available id is list.size()+1 size_t start = 0, current = 0, end = list.find("\n\n", start); if(end != string::npos) { string header = list.substr(start, end-start); current = header.find('|', start); while(current < header.size() && current != string::npos) { int id = lexical_cast(header.substr(start, current-start)); if(struct_type == USERS) availableUserSlots.push_back(id); else availablePersonaSlots.push_back(id); start = current+1; current = header.find('|', start); } start = current = end+2; } end = list.find('\n', start); int count; if(struct_type) count = PERSONA_SIZE; else count = USER_SIZE; while(end != string::npos) { string line = list.substr(current, end-current); start = 0; list_entry row; end = line.find('\f', start); if(end == string::npos) end = line.size(); row.id = lexical_cast(line.substr(start, end-start)); if(struct_type == USERS && row.id > highestUserId) highestUserId = row.id; else if(struct_type == PERSONAS && row.id > highestPersonaId) highestPersonaId = row.id; start = end+1; if(start < line.size()) { end = line.find('\f', start); if(end == string::npos) end = line.size(); row.name = line.substr(start, end-start); start = end+1; if(struct_type == USERS) row.data = new string[USER_SIZE]; else row.data = new string[PERSONA_SIZE]; for(int i = 0; i < count; i++) { if(start < line.size()) { end = line.find('\f', start); if(end == string::npos) end = line.size(); string value = line.substr(start, end-start); row.data[i] = value; start = end+1; } else { debug->warning(2, DATABASE, "Line in %s is missing at least one column, %i (tmp file will not be deleted as a backup)", file, i); loadSuccess = false; break; } } if(struct_type == USERS) users.insert(row); else personas.insert(row); } else { debug->warning(2, DATABASE, "%s seems to be corrupted, check the file (tmp will not be deleted as a backup)", file); loadSuccess = false; break; } current += start; end = list.find('\n', current); } if(loadSuccess) filesystem::remove(dest_file); // everything went fine, remove the temporary backup again // recheck if there is no id higher than highestId in the availableId list, if so fix the list buffer.str(""); bool rearrange = false; std::list::iterator it; std::list tempList; if(struct_type == PERSONAS && !availablePersonaSlots.empty()) { it = availablePersonaSlots.begin(); while(it != availablePersonaSlots.end()) { // search for highest id in available id list if((*it) >= highestPersonaId) { rearrange = true; it = availablePersonaSlots.erase(it); } else { tempList.push_back((*it)); it++; } } if(rearrange) { while(!tempList.empty()) { buffer << tempList.front() << "|"; tempList.pop_front(); } size_t pos = personasData.find("\n\n"); // this should always be there if the id list is not empty if(pos != string::npos) personasData.replace(0, pos, buffer.str()); else debug->warning(1, DATABASE, "%s seems to contain bad data!", file); } } else if(struct_type == USERS && !availableUserSlots.empty()) { it = availableUserSlots.begin(); while(it != availableUserSlots.end()) { // search for highest id in available id list if((*it) >= highestUserId) { rearrange = true; it = availableUserSlots.erase(it); } else { tempList.push_back((*it)); it++; } } if(rearrange) { while(!tempList.empty()) { buffer << tempList.front() << "|"; tempList.pop_front(); } size_t pos = usersData.find("\n\n"); // this should always be there if the id list is not empty if(pos != string::npos) usersData.replace(0, pos, buffer.str()); else debug->warning(1, DATABASE, "%s seems to contain bad data!", file); } } return true; } bool Database::saveFileData(string file, string data) { bool done = false; string tempPath = file; tempPath.append(".tmp"); // make a temporary backup of the .lst file (in case something goes wrong, or is this overcautious?) filesystem::path source_file(file), dest_file(tempPath); if(!filesystem::exists(source_file)) { debug->warning(1, DATABASE, "There is a problem opening the file %s", file.c_str()); return false; } filesystem::copy_file(source_file, dest_file); ofstream destFile(file, ofstream::out | ofstream::trunc); // we delete all content, is it safe to do this? if(destFile.is_open() && destFile.good()) { destFile.write(data.c_str(), data.size()); if(!destFile.bad()) done = true; destFile.close(); } if(!done) debug->warning(1, DATABASE, "A problem occured when saving %s with the data:\n==begin==\n%s\n==end==\n", file.c_str(), data.c_str()); else filesystem::remove(dest_file); // everything went fine, remove the temporary backup again return done; } int Database::addUser(list_entry user) { bool idFlag = false; if(availableUserSlots.empty()) user.id = users.size()+1; // only the size would be the last id in the list else { idFlag = true; user.id = availableUserSlots.front(); availableUserSlots.pop_front(); } pair success = users.insert(user); if(!success.second) { debug->notification(3, DATABASE, "User ID %i with name %s could not be added to database (name already exists in database?)", user.id, user.name.c_str()); availableUserSlots.push_back(user.id); return -1; } else { if(idFlag) // an id has been removed from the available id's list so remove it in file too { // fileUsers, usersData size_t pos = 0; string searchString = lexical_cast(user.id); searchString.append("|"); if((pos = usersData.find(searchString)) > 0 && usersData[pos-1] != '|') // is the result the correct one or should we search again? { searchString.insert(searchString.begin(), '|'); pos = usersData.find(searchString, pos-1); idFlag = false; } if(pos != string::npos) // no need to delete anything if there is nothing (though that shouldn't be) { size_t end = pos+searchString.length(); if(!idFlag) pos++; // +1 because in this case pos points to a | and not the first number of the id if(pos < end && end < usersData.size()) usersData.erase(pos, end); } } // id updating done, now add (append?) the actual entry usersData.append(lexical_cast(user.id)); usersData.append("\f"); usersData.append(user.name); usersData.append("\f"); usersData.append(user.data[PASSWORD]); usersData.append("\f"); usersData.append(user.data[COUNTRY]); usersData.append("\f"); usersData.append(user.data[BIRTHDAY]); usersData.append("\f0\n"); // this value is resetted when reconnecting anyway, no need to save the real value ofstream fileUsers("./database/users.lst", ofstream::out | ofstream::trunc); fileUsers.write(usersData.c_str(), usersData.size()); fileUsers.close(); // id updating done, now add (append?) the actual entry return user.id; } } bool Database::getUser(int id, list_entry* user) { const list_id &li = users.get(); list_id::iterator it = li.find(id); if(it != li.end()) { user->id = it->id; user->name = it->name; user->data = it->data; return true; } else { user->id = -1; user->name = ""; user->data = NULL; debug->notification(3, DATABASE, "User ID %i was not found in the database", id); return false; } } bool Database::getUser(string name, list_entry* user) { const list_string &ls = users.get(); list_string::iterator it = ls.find(name); if(it != ls.end()) { user->id = it->id; user->name = it->name; user->data = it->data; return true; } else { user->id = -1; user->name = ""; user->data = NULL; debug->notification(3, DATABASE, "User name %s was not found in the database", name.c_str()); return false; } } int Database::addPersona(list_entry persona) { bool idFlag = false; if(availablePersonaSlots.empty()) persona.id = personas.size()+1; //only the size would be the last id in the list else { idFlag = true; persona.id = availablePersonaSlots.front(); availablePersonaSlots.pop_front(); } pair success = personas.insert(persona); if(!success.second) { debug->notification(3, DATABASE, "Persona ID %i with name %s could not be added to database (name already exists in database?)", persona.id, persona.name.c_str()); availablePersonaSlots.push_back(persona.id); // insert failed so put id into list again return -1; } else { if(idFlag) // an id has been removed from the available id's list so remove it in file too { // filePersonas, personasData size_t pos = 0; string searchString = lexical_cast(persona.id); searchString.append("|"); if((pos = personasData.find(searchString)) > 0 && personasData[pos-1] != '|') // is the result the correct one or should we search again? { searchString.insert(searchString.begin(), '|'); pos = personasData.find(searchString, pos-1); idFlag = false; } if(pos != string::npos) // no need to delete anything if there is nothing (though that shouldn't be) { size_t end = pos+searchString.length(); if(!idFlag) pos++; // +1 because in this case pos points to a | and not the first number of the id if(pos < end && end < personasData.size()) personasData.erase(pos, end-pos); } } if(persona.id > highestPersonaId) highestPersonaId = persona.id; // id updating done, now add (append?) the actual entry personasData.append(lexical_cast(persona.id)); personasData.append("\f"); personasData.append(persona.name); personasData.append("\f"); personasData.append(persona.data[USER_ID]); personasData.append("\f"); personasData.append(persona.data[USER_EMAIL]); personasData.append("\f0\f0\n"); // these 2 values are resetted when reconnecting anyway, no need to save the real values ofstream filePersonas("./database/personas.lst", ofstream::out | ofstream::trunc); filePersonas.write(personasData.c_str(), personasData.size()); filePersonas.close(); return persona.id; } } void Database::removePersona(string name) { list_string& ls = personas.get(); list_string::iterator it = ls.find(name); if(it != ls.end()) { int id = it->id; delete[] it->data; ls.erase(it); size_t pos = 0; string searchString = lexical_cast(id); if(id < highestPersonaId) // <= because we already erased the entry here { availablePersonaSlots.push_back(id); // save id (only if it's not the last one) so we know which ones are usable // save id also in file if((pos = personasData.find("\n\n")) != string::npos) // there must be only one occurence of this { searchString.append("|"); personasData.insert(pos, searchString); searchString.pop_back(); } else debug->notification(4, DATABASE, "could not find \\n\\n in the personas.lst"); } else if(id == highestPersonaId) { bool countDown = true; for(list::iterator iter = availablePersonaSlots.begin(); iter != availablePersonaSlots.end(); iter++) { if((*iter) == highestPersonaId-1) { countDown = false; break; } } if(countDown) // it's safe to set highest id -1 (however I'm not sure if it's save to do nothing when countDown == false...) highestPersonaId--; } else debug->warning(3, DATABASE, "id %i is last one in the list, highestId = %i", id, highestPersonaId); // now remove entry from file searchString.append("\f"); searchString.append(name); if((pos = personasData.find(searchString)) > 0 && personasData[pos-1] != '\n') { searchString.insert(searchString.begin(), '\n'); pos = personasData.find(searchString, pos-1); if(pos != string::npos) pos++; // better to do this here } if(pos != string::npos) { size_t end = personasData.find('\n', pos)+1; // we want the \n also removed if(end != string::npos) personasData.erase(pos, end-pos); else debug->warning(3, DATABASE, "removePersona() something is wrong with Persona %s in file data!", name.c_str()); } ofstream filePersonas("./database/personas.lst", ofstream::out | ofstream::trunc); filePersonas.write(personasData.c_str(), personasData.size()); filePersonas.close(); debug->notification(3, DATABASE, "Persona %s with ID %i was removed from database", name.c_str(), id); } else debug->warning(3, DATABASE, "removePersona() Persona %s was not found in database!", name.c_str()); } bool Database::getPersona(int id, list_entry* persona) { const list_id &li = personas.get(); list_id::iterator it = li.find(id); if(it != li.end()) { persona->id = it->id; persona->name = it->name; persona->data = it->data; return true; } else { persona->id = -1; persona->name = ""; persona->data = NULL; debug->notification(3, DATABASE, "Persona ID %i was not found in the database", id); return false; } } bool Database::getPersona(string name, list_entry* persona) { const list_string &ls = personas.get(); list_string::iterator it = ls.find(name); if(it != ls.end()) { persona->id = it->id; persona->name = it->name; persona->data = it->data; return true; } else { persona->id = -1; persona->name = ""; persona->data = NULL; debug->notification(3, DATABASE, "Persona name %s was not found in the database", name.c_str()); return false; } } /* bool Database::setUserData(int id, int index, string data) { const list_id &li = users.get(); list_id::iterator it = li.find(id); if(it != li.end()) { it->data[index] = data; return true; } else { debug->warning(3, DATABASE, "User ID %i was not found in the database", id); return false; } } bool Database::setUserData(string name, int index, string data) { const list_string &ls = users.get(); list_string::iterator it = ls.find(name); if(it != ls.end()) { it->data[index] = data; return true; } else { debug->warning(3, DATABASE, "User name %s was not found in the database", name.c_str()); return false; } } bool Database::setPersonaData(int id, int index, string data) { const list_id &li = personas.get(); list_id::iterator it = li.find(id); if(it != li.end()) { it->data[index] = data; return true; } else { debug->warning(3, DATABASE, "Persona ID %i was not found in the database", id); return false; } } bool Database::setPersonaData(string name, int index, string data) { const list_string &ls = personas.get(); list_string::iterator it = ls.find(name); if(it != ls.end()) { it->data[index] = data; return true; } else { debug->warning(3, DATABASE, "Persona name %s was not found in the database", name.c_str()); return false; } } bool Database::setGameData(int id, int index, string data, bool gdet) { if(id <= 0 || id > (int)games.size()) { debug->warning(3, DATABASE, "setGameData() - Invalid server ID was passed as parameter - %i", id); return false; } id--; //vector list is null based but our ids are not if(!gdet) games[id].key[index] = data; else games[id].gdet[index] = data; return true; } */ void Database::listMatchingPersonas(int index, string searchTerm, list* filtered) { const list_string &ls = personas.get(); list_string::iterator it; for(it = ls.begin(); it != ls.end(); it++) { //no need to go through gdet struct because we never need to? if(it->data[index].compare(searchTerm) == 0) filtered->push_back((*it)); } debug->notification(3, DATABASE, "Filtering out personas for %s = %s, %i results", personas_text[index].c_str(), searchTerm.c_str(), filtered->size()); //since we used a pointer we dont need to return anything } int Database::addGame(GamesEntry game) { lobby_num_games++; //we add a game so we have a new active entry if(availableGameSlots.empty()) { games.push_back(game); debug->notification(3, DATABASE, "Server was added to database, assigned ID: %i", games.size()); return games.size(); } else { int available_id = availableGameSlots.front(); games[available_id].key = game.key; games[available_id].gdet = game.gdet; availableGameSlots.pop_front(); available_id++; //return plus one because game doesn't like it zero based debug->notification(3, DATABASE, "Server was added to database, assigned ID: %i", available_id); return available_id; } } void Database::removeGame(int id) { if(isValidGid(id)) { id--; if(games[id].key) { delete[] games[id].key; games[id].key = NULL; } if(games[id].gdet) { delete[] games[id].gdet; games[id].gdet = NULL; } availableGameSlots.push_back(id); debug->notification(3, DATABASE, "Server with ID %i was removed from database", id+1); lobby_num_games--; } else debug->warning(3, DATABASE, "removeGame() - Invalid server ID was passed as parameter - %i", id); } bool Database::isValidGid(int id) { if(id > 0 && id <= (int)games.size()) return true; else return false; } string* Database::getGameData(int id, bool gdet) { if(isValidGid(id)) { id--; //vector list is null based but our ids are not if(!gdet) return games[id].key; else return games[id].gdet; } else { debug->warning(3, DATABASE, "getGameData() - Invalid server ID was passed as parameter - %i", id); return NULL; } } void Database::listMatchingGames(list* filters, list* filtered, bool returnFirst) { for(int i = 0; i < (int)games.size(); i++) { if(games[i].key) { list::iterator it; bool match = true; bool name_match = false; bool ugid_match = false; bool check_name = false; bool check_ugid = false; for(it = filters->begin(); it != filters->end(); it++) { switch(it->id) { case ACTIVE_PLAYERS: { if(it->key.compare("1") == 0) { int active_players = lexical_cast(games[i].key[ACTIVE_PLAYERS]); if(active_players < 1) match = false; } break; } case MAX_PLAYERS: { if(it->key.compare("1") == 0) { int active_players = lexical_cast(games[i].key[ACTIVE_PLAYERS]); int max_players = lexical_cast(games[i].key[MAX_PLAYERS]); if(active_players >= max_players) match = false; } break; } case SERVER_NAME: { if(!check_name) check_name = true; if(games[i].key[SERVER_NAME].find(it->key) != string::npos) name_match = true; break; } case UGID: { if(!check_ugid) check_ugid = true; if(games[i].key[UGID].compare(it->key) == 0)// || it->key.compare("frostbite") == 0) ugid_match = true; break; } default: { if(it->key.compare(games[i].key[it->id]) != 0) match = false; break; } } if(!match)// && it->id != SERVER_NAME && it->id != UGID) break; } if(match) { // hopefully all possible cases are covered here if(!check_name && !check_ugid) { filtered->push_back(i+1); if(returnFirst) break; } else if(!check_ugid && check_name && name_match) { filtered->push_back(i+1); if(returnFirst) break; } else if(!check_name && check_ugid && ugid_match) { filtered->push_back(i+1); if(returnFirst) break; } else if(check_name && check_ugid && name_match && ugid_match) { filtered->push_back(i+1); if(returnFirst) break; } } } } debug->notification(3, DATABASE, "Found %i games of %i for the set filters", filtered->size(), games.size()); } void Database::listAllGames(list* allGames) { for(int i = 0; i < (int)games.size(); i++) { if(games[i].key) allGames->push_back(i+1); // we are one-based } debug->notification(3, DATABASE, "Found %i games (no filters)", allGames->size()); } void Database::personaLogin(linked_key persona) { lkeys_assigned.push_back(persona); } int Database::theaterLogin(string lkey) { list::iterator it; for(it = lkeys_assigned.begin(); it != lkeys_assigned.end(); it++) { if(lkey.compare(it->key) == 0) { int id = it->id; lkeys_assigned.erase(it); return id; } } debug->warning(2, DATABASE, "theaterLogin() - no ID found for lkey %s", lkey.c_str()); return -1; } string Database::getLobbyInfo(int index) { return lobby[index]; } int Database::getLobbyGames() { return lobby_num_games; } string Database::listEntryToString(list_entry* entry, const char* state, bool user) { string line = (user) ? "users" : "personas"; line.append(" table "); line.append(state); line.append(" id: "); line.append(lexical_cast(entry->id)); line.append(", name: "); line.append(entry->name); line.append("\n"); if(extended_info) { string border = ""; string text = ""; if(user) { for(int i = 0; i < USER_SIZE; i++) { int cell_length = entry->data[i].size(); if(cell_length == 0) cell_length = 4; //key is empty so we put NULL into cell if(cell_length < (int)users_text[i].size()) { text.append(users_text[i].size() - cell_length, ' '); cell_length = users_text[i].size(); } else line.append(cell_length - users_text[i].size(), ' '); line.append(users_text[i]); border.append(cell_length, '-'); if(!entry->data[i].empty()) text.append(entry->data[i]); else text.append("NULL"); if(i+1 < USER_SIZE) { line.append(" | "); text.append(" | "); border.append("-|-"); } else { line.append("\n"); border.append("\n"); text.append("\n"); } } } else { for(int i = 0; i < PERSONA_SIZE; i++) { int cell_length = entry->data[i].size(); if(cell_length == 0) cell_length = 4; //key is empty so we put NULL into cell if(cell_length < (int)personas_text[i].size()) { text.append(personas_text[i].size() - cell_length, ' '); cell_length = personas_text[i].size(); } else line.append(cell_length - personas_text[i].size(), ' '); line.append(personas_text[i]); border.append(cell_length, '-'); if(!entry->data[i].empty()) text.append(entry->data[i]); else text.append("NULL"); if(i+1 < PERSONA_SIZE) { line.append(" | "); text.append(" | "); border.append("-|-"); } else { line.append("\n"); border.append("\n"); text.append("\n"); } } } line.append(border); line.append(text); } else { int count; if(user) count = USER_SIZE; else count = PERSONA_SIZE; for(int i = 0; i < count; i++) { if(!entry->data[i].empty()) line.append(entry->data[i]); else line.append("NULL"); if(i+1 < count) line.append(", "); else line.append("\n"); } } return line; } string Database::gameToString(int id, const char* state, GamesEntry* game, bool gdet) { string line = (gdet) ? "gdet" : "games"; line.append(" table "); line.append(state); line.append(" gid: "); line.append(lexical_cast(id)); line.append("\n"); //char buffer[36]; //sprintf(buffer, "%s table %s gid: %i\n", (gdet) ? "gdet" : "games", state, id); //string line = buffer; if(extended_info) { string border = ""; string text = ""; if(!gdet) { for(int i = 0; i < GAMES_SIZE; i++) { int cell_length = game->key[i].size(); if(cell_length == 0) cell_length = 4; //key is empty so we put NULL into cell if(cell_length < (int)games_text[i].size()) { text.append(games_text[i].size() - cell_length, ' '); cell_length = games_text[i].size(); } else line.append(cell_length - games_text[i].size(), ' '); line.append(games_text[i]); border.append(cell_length, '-'); if(!game->key[i].empty()) text.append(game->key[i]); else text.append("NULL"); if(i+1 < GAMES_SIZE) { line.append(" | "); text.append(" | "); border.append("-|-"); } else { line.append("\n"); border.append("\n"); text.append("\n"); } } } else { for(int i = 0; i < GDET_SIZE; i++) { int cell_length = game->gdet[i].size(); if(cell_length == 0) cell_length = 4; //key is empty so we put NULL into cell if(cell_length < (int)gdet_text[i].size()) { text.append(gdet_text[i].size() - cell_length, ' '); cell_length = gdet_text[i].size(); } else line.append(cell_length - gdet_text[i].size(), ' '); line.append(gdet_text[i]); border.append(cell_length, '-'); if(!game->gdet[i].empty()) text.append(game->gdet[i]); else text.append("NULL"); if(i+1 < GDET_SIZE) { line.append(" | "); text.append(" | "); border.append("-|-"); } else { line.append("\n"); border.append("\n"); text.append("\n"); } } } line.append(border); line.append(text); } else { if(!gdet) { for(int i = 0; i < GAMES_SIZE; i++) { if(!game->key[i].empty()) line.append(game->key[i]); else line.append("NULL"); if(i+1 < GAMES_SIZE) line.append(", "); else line.append("\n"); } } else { for(int i = 0; i < GDET_SIZE; i++) { if(!game->gdet[i].empty()) line.append(game->gdet[i]); else line.append("NULL"); if(i+1 < GDET_SIZE) line.append(", "); else line.append("\n"); } } } return line; }