allegro 5 writing files when using physfs - c++

i am currently trying to figure out a way to write a file (an allegro configuration file to be exact) to a mounted zip-file using physfs and allegro 5.
reading the config file works fine, but when it comes to writing the changed config, nothing happens (e.g. the file is not re-written and thus remains in it's old state).
also, when not using physfs, everything works perfectly.
here's the code i use:
Game::Game(int height, int width, int newDifficulty)
{
PHYSFS_init(NULL);
if (!PHYSFS_addToSearchPath("Data.zip", 1)) {
// error handling
}
al_set_physfs_file_interface();
cfg = al_load_config_file("cfg.cfg");
if (cfg != NULL) // file exists, read from it
{
const char *score = al_get_config_value(cfg, "", "highScore");
highScore = atoi(score); // copy value
}
else // file does not exist, create it and init highScore to 0
{
cfg = al_create_config();
al_set_config_value(cfg, "", "highScore", "0");
highScore = 0;
al_save_config_file("cfg.cfg", cfg);
}
...
}
and in another function:
void Game::resetGame()
{
// high score
if (player->getScore() > highScore)
{
highScore = player->getScore();
// convert new highScore to char* that can be saved
stringstream strs;
strs << highScore;
string temp_str = strs.str();
char const* pchar = temp_str.c_str();
if (cfg != NULL) // file exists, read from it
{
al_set_config_value(cfg, "", "highScore", pchar);
al_save_config_file("cfg.cfg", cfg);
}
}
...
}
since the code works without physfs, i guess i handle the config file itself correctly.
any help would be highly appreciated!
cheers,
hannes

in the meantime, i solved the issue myself.
apparently, physfs has no ability to write to an archive.
therefore, i need to PHYSFS_setWriteDir("jhdsaf"), save the cfg-file in that folder and then replace the original zip-file by an updated version with the cfg-file, just before the game closes (after all resources are unloaded because the zip is otherwise still in use).
if anyone is interested in the code to do this, just reply to this post!
hannes

Related

ifstream - monitor updates to file

I am using ifstream to open a file and read line by line and print to console.
Now, I also want to make sure that if the file gets updated, it reflects. My code should handle that.
I tried setting fseek to end of the file and then looking for new entries by using peek. However, that did not work.
Here's some code I used
bool ifRead = true;
while (1)
{
if (ifRead)
{
if (!file2read.eof())
{
//valid file. not end of file.
while (getline(file2read, line))
printf("Line: %s \n", line.c_str());
}
else
{
file2read.seekg(0, file2read.end);
ifRead = false;
}
}
else
{
//I thought this would check if new content is added.
//in which case, "peek" will return a non-EOF value. else it will always be EOF.
if (file2read.peek() != EOF)
ifRead = true;
}
}
}
Any suggestions on what could be wrong or how I could do this.

Losing a value from pointer vector after loop that reads the file (using dirent)

I'm writing a program in C++ that behaves like a Twitter Service. The program is supposed to store data in files as follows:
f_username (stores the users that username follows), so it creates a file for each user that follows someone. I have the function load_users() that reads each file to populate all clients (users) information in a vector called client_db (global variable) of type struct (defined below). So, when a f_username file is read, the vectors client_followers and client_following are populated for each user. The function works perfectly, except for the first file it reads. It saves the information in client_followers and client_following in the while loop that reads the file, but the entries for both vectors are deleted somehow after this loop. I added the comments in the code where I'm facing this issue only for the first f_username file it reads.
I believe it has something to do with the fact I'm using pointers, but I have no clue how to fix this issue. This is the first time ever I have this weird logic error. How is possible that it only "deletes" the data from the vectors that is read from first file, but not from the other files (I have 3 files)?
Any help would be really appreciated, I tried my best to explain this problem.
**UPDATE: Problem fixed by replacing the types of vectors client_followers and client_following with a string type without declaring them as pointers, and making sure the actual entries in client_db are updated correctly. **
//Client struct that holds a user's username, followers, and users they follow
struct Client {
std::string username;
bool connected = false;
int following_file_size = 0;
std::vector<Client*> client_followers;
std::vector<Client*> client_following;
ServerReaderWriter<Message, Message>* stream = 0;
bool operator==(const Client& c1) const{
return (username == c1.username);
}
};
void load_users()
{
//load users (followers and following)
DIR *dir;
struct dirent *ent;
if ((dir = opendir ("./")) != NULL) {
while ((ent = readdir (dir)) != NULL) {
std::string filename = ent->d_name;
int index = filename.find("f_");
if(index != std::string::npos)
{
std::ifstream in; //read following file of username
//get username
std::string user = filename.substr(index+2);
int txt_index = user.find(".txt");
user.erase(txt_index,4);
int user_index = find_user(user); //check if user is in client's db already
//client_db is a global variable
if(user_index < 0){ //if not, add client to client_db
Client c;
c.username = user;
client_db.push_back(c);
}
Client* user1 = &client_db[find_user(user)];
std::string username2;
in.open("./" + filename);
while(!in.eof())
{
getline(in,username2);
int following_index = find_user(username2);
if(following_index < 0) //create entry for the user
{
Client c2;
c2.username = username2;
client_db.push_back(c2);
}
Client* user2 = &client_db[find_user(username2)];
//it adds the information for the first file, but entries in client_followers
//and client_following is deleted after this loop ends, how is this possible?
user2->client_followers.push_back(user1);
user1->client_following.push_back(user2);
}
//When I print information of client_following and client_followers, the information obtained from the first file is not printed (e.g. size of client_following is 0).
in.close();
//break;
}
}
closedir (dir);
} else {
/* could not open directory */
//perror ("");
//return EXIT_FAILURE;
return;
}
}

LibXL load file failure

Here is the code to load the xls/xlsx file:
int main()
{
BookHandle book = xlCreateBook();
if(book)
{
if(xlBookLoad(book, L"Slice.xlsx"))
{
SheetHandle sheet = xlBookGetSheet(book, 0);
if(sheet)
{
double d;
const wchar_t* s = xlSheetReadStr(sheet, 2, 1, 0);
if(s) wprintf(L"%s\n", s);
d = xlSheetReadNum(sheet, 3, 1, 0);
printf("%g\n", d);
}
}
xlBookRelease(book);
}
printf("\nPress any key to exit...");
_getch();
return 0;
}
These are actually the example code. the xlBookLoad() fails so that the if statement is skipped.
However, if I load its own file example1.xls, it succeeded.
Slice.xlsx and example.xls are in the same folder. I am 100% sure the file path is correct. It was the loading functionality that failed.
Now, I don't know why. Was that because the Slice.xlsx is kinda special? or LibXL is not the tool to load it? If so how can I read it?
I am attaching it here. Thanks a lot in advance to anyone that helps.
Slice.xlsx:
https://dl.dropboxusercontent.com/u/7949206/Slice.xlsx
From the documentation, it is stated that you should use xlCreateBook to work with a *.xls file and xlCreateXMLBook to work with a *.xlsx file. Thus, for Slice.xlsx, use xlCreateXMLBook in the place of xlCreateBook. http://www.libxl.com/documentation.html

replace some value in text line in c++

Hi guys i use this code to find the line included seta r_fullscreen "0" and if the value for this line is 0 return MessageBox but my question is if the value of seta r_fullscreenis "0" so how i can replace this value to "1" in this line ?
ifstream cfgm2("players\\config_m2.cfg",ios::in);
string cfgLine;
Process32First(proc_Snap , &pe32);
do{
while (getline(cfgm2,cfgLine)) {
if (string::npos != cfgLine.find("seta r_fullscreen")){
if (cfgLine.at(19) == '0'){
MessageBox(NULL,"run in full Screen mod.","ERROR", MB_OK | MB_ICONERROR);
...
You can use std::string::find() and std::string::replace() to do this. After you have located the line containing the configuration specifier seta r_fullscreen you can do something like the following.
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
cfgLine.replace(pos, 3, "\"1\"");
}
You should not assume that the configuration value "0" is at a specific offset as there may be additional spaces between r_fullscreen and "0".
After seeing your additional comments you need to update the configuration file after the changes have been made. The changes you make to the string only apply to the copy in memory and are not automatically saved to the file. You will need to save each line after it has been loaded and changed and then save the updates out to the file. You should also move the process of updating the config file outside of do/while loop. If yo don't you will read/update the file for each process you check.
The example below should get you started.
#include <fstream>
#include <string>
#include <vector>
std::ifstream cfgm2("players\\config_m2.cfg", std::ios::in);
if(cfgm2.is_open())
{
std::string cfgLine;
bool changed = false;
std::vector<std::string> cfgContents;
while (std::getline(cfgm2,cfgLine))
{
// Check if this is a line that can be changed
if (std::string::npos != cfgLine.find("seta r_fullscreen"))
{
// Find the value we want to change
std::string::size_type pos = cfgLine.find("\"0\"");
if(pos != std::string::npos)
{
// We found it, not let's change it and set a flag indicating the
// configuration needs to be saved back out.
cfgLine.replace(pos, 3, "\"1\"");
changed = true;
}
}
// Save the line for later.
cfgContents.push_back(cfgLine);
}
cfgm2.close();
if(changed == true)
{
// In the real world this would be saved to a temporary and the
// original replaced once saving has successfully completed. That
// step is omitted for simplicity of example.
std::ofstream outCfg("players\\config_m2.cfg", std::ios::out);
if(outCfg.is_open())
{
// iterate through every line we have saved in the vector and save it
for(auto it = cfgContents.begin();
it != cfgContents.end();
++it)
{
outCfg << *it << std::endl;
}
}
}
}
// Rest of your code
Process32First(proc_Snap , &pe32);
do {
// some loop doing something I don't even want to know about
} while ( /*...*/ );

Heap allocation error within static library

I have a working Visual Studio project.
I've created a static library with the files of the original project (except main.cpp), also
I've created a "tester" project (with the static lib linked to it) with only a main.cpp file from the original project.
Both compiles without any relevant error.
And tester runs appropriately.
But! At testing the "tester" I am getting a heap allocation error at a (not the first)
new[] operator invoked in a constructor implemented in the library.
That line working fine in the original project without any error.
The "little" version of the code:
//the staticlib
void test() {
manager* m = new manager;
m->open();
}
//....
class manager {
public:
open() {
PRAWINPUTDEVICELIST lDevList;
UINT lDevCount;
GetRawInputDeviceList(NULL, &lDevCount, sizeof(RAWINPUTDEVICELIST));
lDevList = (PRAWINPUTDEVICELIST) malloc(sizeof(RAWINPUTDEVICELIST)*lDevCount);
GetRawInputDeviceList(lDevList, &lDevCount, sizeof(RAWINPUTDEVICELIST));
if(lDevCount) {
for(UINT i = 0; i < lDevCount; i++) {
HIDP_CAPS mCaps;
PHIDP_BUTTON_CAPS mButtonCaps;
PHIDP_VALUE_CAPS mValueCaps;
UINT size;
GetRawInputDeviceInfo(lDevList[i].hDevice, RIDI_DEVICENAME, NULL, &size);
char* name = new char[size+1];
//just to be sure
memset(name, 0, size+1);
//surely sure
name[size] = '\0';
GetRawInputDeviceInfo(lDevList[i].hDevice, RIDI_DEVICENAME, name, &size);
HANDLE lDev = CreateFile((LPCWSTR)name, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, 0, NULL);;
PHIDP_PREPARSED_DATA lPrep;
HidD_GetPreparsedData(lDev, &lPrep);
HidP_GetCaps(lPrep, &mCaps);
if(mCaps.NumberInputButtonCaps) {
//crash is here below
//mCaps.NumberInputButtonCaps ~1
mButtonCaps = new HIDP_BUTTON_CAPS[mCaps.NumberInputButtonCaps];
HidP_GetButtonCaps(HidP_Input, mButtonCaps, &mCaps.NumberInputButtonCaps, lPrep);
}
if(mCaps.NumberInputValueCaps) {
//if the first "crash-line" is commented, then
//the crash is here
mValueCaps = new HIDP_VALUE_CAPS[mCaps.NumberInputValueCaps];
HidP_GetValueCaps(HidP_Input, mValueCaps, &mCaps.NumberInputValueCaps, lPrep);
}
CloseHandle(lDev);
}
}
}
};
//the app
test();
Where I am wrong? Is it a typical novice commission I am not afraid of?
Sorry for my English, and thanks ahead for your time!
The error is that you should be allocating wide chars when you call GetRawInputDeviceInfo. From the manual
RIDI_DEVICENAME 0x20000007
pData points to a string that contains the device name.
For this uiCommand only, the value in pcbSize is the character count
(not the byte count).
In other words you should write
wchar_t* name = new wchar_t[size];
GetRawInputDeviceInfo(lDevList[i].hDevice, RIDI_DEVICENAME, name, &size);
Just from reading the manual, I have no actual experience with this API, but it seems a likely explanation.
Add logic that checks for error return states on every Win32 call you make. Possibly one of them is failing and when you remedy that, the rest will work. Always check for and handle errors when you are using Win32 APIs.