Initial setup for saving game states

(code may or may not compile at this point)
This commit is contained in:
2014-04-19 22:37:40 -04:00
parent 3f54c63193
commit 60d1ce3be9
7 changed files with 268 additions and 525 deletions

View File

@@ -501,6 +501,8 @@
91B3EF5B0F969F3000BF5B67 /* scen.dlgutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EEF60F969BA700BF5B67 /* scen.dlgutil.cpp */; }; 91B3EF5B0F969F3000BF5B67 /* scen.dlgutil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EEF60F969BA700BF5B67 /* scen.dlgutil.cpp */; };
91B3F1850F97894A00BF5B67 /* scen.graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EEF30F969BA700BF5B67 /* scen.graphics.cpp */; }; 91B3F1850F97894A00BF5B67 /* scen.graphics.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91B3EEF30F969BA700BF5B67 /* scen.graphics.cpp */; };
91BFA3D71901B18F001686E4 /* mask.vert in Copy Shaders */ = {isa = PBXBuildFile; fileRef = 91BFA3D61901B024001686E4 /* mask.vert */; }; 91BFA3D71901B18F001686E4 /* mask.vert in Copy Shaders */ = {isa = PBXBuildFile; fileRef = 91BFA3D61901B024001686E4 /* mask.vert */; };
91BFA3DA1902B13D001686E4 /* tarball.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3D81902AD78001686E4 /* tarball.cpp */; };
91BFA3DB1902B13F001686E4 /* tarball.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3D81902AD78001686E4 /* tarball.cpp */; };
91BFA3E919033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; }; 91BFA3E919033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; };
91BFA3EA19033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; }; 91BFA3EA19033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; };
91BFA3EB19033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; }; 91BFA3EB19033E01001686E4 /* gzstream.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 91BFA3DE19033E01001686E4 /* gzstream.cpp */; };
@@ -1607,6 +1609,8 @@
91B3F11D0F97801F00BF5B67 /* mathutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mathutil.h; sourceTree = "<group>"; }; 91B3F11D0F97801F00BF5B67 /* mathutil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mathutil.h; sourceTree = "<group>"; };
91B3F11E0F97801F00BF5B67 /* mathutil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mathutil.cpp; sourceTree = "<group>"; }; 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = mathutil.cpp; sourceTree = "<group>"; };
91BFA3D61901B024001686E4 /* mask.vert */ = {isa = PBXFileReference; explicitFileType = sourcecode.glsl; fileEncoding = 4; path = mask.vert; sourceTree = "<group>"; }; 91BFA3D61901B024001686E4 /* mask.vert */ = {isa = PBXFileReference; explicitFileType = sourcecode.glsl; fileEncoding = 4; path = mask.vert; sourceTree = "<group>"; };
91BFA3D81902AD78001686E4 /* tarball.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tarball.cpp; sourceTree = "<group>"; };
91BFA3D91902ADD5001686E4 /* tarball.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tarball.hpp; sourceTree = "<group>"; };
91BFA3DE19033E01001686E4 /* gzstream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gzstream.cpp; sourceTree = "<group>"; }; 91BFA3DE19033E01001686E4 /* gzstream.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gzstream.cpp; sourceTree = "<group>"; };
91BFA3DF19033E01001686E4 /* gzstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gzstream.h; sourceTree = "<group>"; }; 91BFA3DF19033E01001686E4 /* gzstream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gzstream.h; sourceTree = "<group>"; };
91C688E60FD702B9000F6D01 /* cursors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cursors.h; sourceTree = "<group>"; }; 91C688E60FD702B9000F6D01 /* cursors.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cursors.h; sourceTree = "<group>"; };
@@ -2097,11 +2101,12 @@
91B3F10A0F9779C300BF5B67 /* graphtool.cpp */, 91B3F10A0F9779C300BF5B67 /* graphtool.cpp */,
91B3F11E0F97801F00BF5B67 /* mathutil.cpp */, 91B3F11E0F97801F00BF5B67 /* mathutil.cpp */,
913D005A0F9FEEC200184C18 /* porting.cpp */, 913D005A0F9FEEC200184C18 /* porting.cpp */,
91EC481018FBABB100BB1E86 /* prefs.mac.mm */,
91F6F8F518F8DE6300E3EA15 /* qdpict.cpp */, 91F6F8F518F8DE6300E3EA15 /* qdpict.cpp */,
91B3F10F0F9779D000BF5B67 /* soundtool.cpp */, 91B3F10F0F9779D000BF5B67 /* soundtool.cpp */,
91BFA3D81902AD78001686E4 /* tarball.cpp */,
912283C80FD0E16C00B21642 /* undo.cpp */, 912283C80FD0E16C00B21642 /* undo.cpp */,
919145FF18E63B70005CF3A4 /* winutil.mac.mm */, 919145FF18E63B70005CF3A4 /* winutil.mac.mm */,
91EC481018FBABB100BB1E86 /* prefs.mac.mm */,
91A0B15A1900F73E00EF438F /* mask.frag */, 91A0B15A1900F73E00EF438F /* mask.frag */,
91BFA3D61901B024001686E4 /* mask.vert */, 91BFA3D61901B024001686E4 /* mask.vert */,
); );
@@ -2116,10 +2121,11 @@
91B3F1090F9779C300BF5B67 /* graphtool.h */, 91B3F1090F9779C300BF5B67 /* graphtool.h */,
91B3F11D0F97801F00BF5B67 /* mathutil.h */, 91B3F11D0F97801F00BF5B67 /* mathutil.h */,
913D00590F9FEEC200184C18 /* porting.h */, 913D00590F9FEEC200184C18 /* porting.h */,
91EC480E18FBAA8700BB1E86 /* prefs.hpp */,
91B3F10E0F9779D000BF5B67 /* soundtool.h */, 91B3F10E0F9779D000BF5B67 /* soundtool.h */,
91BFA3D91902ADD5001686E4 /* tarball.hpp */,
917B573F100B956C0096C978 /* undo.h */, 917B573F100B956C0096C978 /* undo.h */,
919145FE18E63B41005CF3A4 /* winutil.h */, 919145FE18E63B41005CF3A4 /* winutil.h */,
91EC480E18FBAA8700BB1E86 /* prefs.hpp */,
); );
name = headers; name = headers;
sourceTree = "<group>"; sourceTree = "<group>";
@@ -2820,6 +2826,7 @@
91F6F8F618F8DE6300E3EA15 /* qdpict.cpp in Sources */, 91F6F8F618F8DE6300E3EA15 /* qdpict.cpp in Sources */,
91EC483B18FBAD8000BB1E86 /* prefs.mac.mm in Sources */, 91EC483B18FBAD8000BB1E86 /* prefs.mac.mm in Sources */,
91FCC8F218FEEFE0007026CE /* pc.editors.cpp in Sources */, 91FCC8F218FEEFE0007026CE /* pc.editors.cpp in Sources */,
91BFA3DA1902B13D001686E4 /* tarball.cpp in Sources */,
91BFA3E919033E01001686E4 /* gzstream.cpp in Sources */, 91BFA3E919033E01001686E4 /* gzstream.cpp in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
@@ -2872,6 +2879,7 @@
91FCC8DC18FE2CE8007026CE /* pc.menus.mac.mm in Sources */, 91FCC8DC18FE2CE8007026CE /* pc.menus.mac.mm in Sources */,
91FCC8F118FEEDC6007026CE /* winutil.mac.mm in Sources */, 91FCC8F118FEEDC6007026CE /* winutil.mac.mm in Sources */,
91FCC8F418FF0866007026CE /* pc.appleevents.mm in Sources */, 91FCC8F418FF0866007026CE /* pc.appleevents.mm in Sources */,
91BFA3DB1902B13F001686E4 /* tarball.cpp in Sources */,
91BFA3EA19033E01001686E4 /* gzstream.cpp in Sources */, 91BFA3EA19033E01001686E4 /* gzstream.cpp in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;

View File

@@ -86,7 +86,7 @@ void add_outdoor_maps();
short specials_res_id,data_dump_file_id; short specials_res_id,data_dump_file_id;
char start_name[256]; char start_name[256];
short start_volume,data_volume; short start_volume,data_volume;
fs::path progDir; extern fs::path progDir;
//outdoor_record_type dummy_out;//// //outdoor_record_type dummy_out;////
//town_record_type dummy_town; //town_record_type dummy_town;
@@ -99,44 +99,6 @@ fs::path progDir;
cCustomGraphics spec_scen_g; cCustomGraphics spec_scen_g;
std::ofstream flog("bladeslog.txt"); std::ofstream flog("bladeslog.txt");
// TODO: Move this to the common fileio.cpp
void init_directories()
{
char cPath[768];
CFBundleRef mainBundle=CFBundleGetMainBundle();
CFStringRef progURL = CFURLCopyFileSystemPath(CFBundleCopyBundleURL(mainBundle), kCFURLPOSIXPathStyle);
const char* tmp = CFStringGetCStringPtr(progURL, kCFStringEncodingASCII);//kCFStringEncodingUTF8);
if(tmp == NULL){
bool success = CFStringGetCString(progURL, cPath, sizeof(cPath), kCFStringEncodingUTF8);
if(success) {
progDir = cPath;
std::cout << cPath << "\n\n" << progDir << "\n\n";
} else {
std::cout << "Couldn't retrieve application path.\n";
exit(1);
}
}else progDir = tmp;
progDir = progDir.parent_path();
std::cout<<progDir<<'\n';
// Initialize the resource manager paths
ResMgr::pushPath<ImageRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac");
ResMgr::pushPath<CursorRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac"/"cursors");
ResMgr::pushPath<FontRsrc>(progDir/"data"/"fonts");
ResMgr::pushPath<StringRsrc>(progDir/"data"/"strings");
ResMgr::pushPath<SoundRsrc>(progDir/"Scenario Editor"/"sounds.exa");
// now I generate the directory ID of the folder which contains the scenarios
// code copied from Mac Prog FAQ book
// myCPB.dirInfo.ioNamePtr = folder_name;
// myCPB.dirInfo.ioVRefNum = start_volume;
// myCPB.dirInfo.ioFDirIndex = 0;
// myCPB.dirInfo.ioDrDirID = start_dir;
// error = PBGetCatalogInfoSync(&myCPB); // false means not async
//
// scen_dir = myCPB.dirInfo.ioDrDirID;
}
void finish_load_party(){ void finish_load_party(){
bool town_restore = (univ.town.num < 200) ? true : false; bool town_restore = (univ.town.num < 200) ? true : false;

View File

@@ -3,7 +3,6 @@
namespace fs = boost::filesystem; // TODO: Centralize this alias! namespace fs = boost::filesystem; // TODO: Centralize this alias!
void init_directories();
//void load_file(); //void load_file();
//void save_file(short mode); //void save_file(short mode);
void change_rect_terrain(RECT r,ter_num_t terrain_type,short probability,bool hollow); void change_rect_terrain(RECT r,ter_num_t terrain_type,short probability,bool hollow);

View File

@@ -11,7 +11,6 @@
#include <map> #include <map>
#include <sstream> #include <sstream>
#include <zlib.h>
//#include "scen.global.h" //#include "scen.global.h"
#include <fstream> #include <fstream>
#include "classes.h" #include "classes.h"
@@ -25,6 +24,8 @@
#include "porting.h" #include "porting.h"
#include "dlogutil.h" #include "dlogutil.h"
#include "restypes.hpp" #include "restypes.hpp"
#include "tarball.hpp"
#include "gzstream.h"
extern bool cur_scen_is_mac, mac_is_intel; extern bool cur_scen_is_mac, mac_is_intel;
extern cScenario scenario; extern cScenario scenario;
@@ -36,66 +37,53 @@ extern cUniverse univ;
//extern unsigned char borders[4][50]; //extern unsigned char borders[4][50];
//extern cOutdoors current_terrain; //extern cOutdoors current_terrain;
//extern cTown* town; //extern cTown* town;
extern fs::path progDir; fs::path progDir, tempDir;
//extern short overall_mode; //extern short overall_mode;
struct header_posix_ustar {
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char checksum[8];
char typeflag[1];
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char pad[12];
};
#include <stdexcept> #include <stdexcept>
// TODO: Try to find a way to get our path without using CoreFoundation, and also replace cout with printf
#include <CoreFoundation/CoreFoundation.h>
static header_posix_ustar generateTarHeader(const std::string& fileName, unsigned long long fileSize,bool directory=false){ void init_directories() {
if(fileSize>077777777777LL) char cPath[768];
throw std::length_error("Specified file size >= 8 GB"); CFBundleRef mainBundle = CFBundleGetMainBundle();
if(fileName.length()>=100)
throw std::length_error("Specified file name longer than 99 characters.");
header_posix_ustar header;
char* init = (char*) &header;
for(unsigned int i = 0; i < sizeof(header); i++) init[i] = 0;
sprintf(header.name,"%s",fileName.c_str()); CFStringRef progURL = CFURLCopyFileSystemPath(CFBundleCopyBundleURL(mainBundle), kCFURLPOSIXPathStyle);
sprintf(header.mode,"%07o",0600); const char* tmp = CFStringGetCStringPtr(progURL, kCFStringEncodingASCII);
//leave uid filled with NULs if(tmp == NULL){
//leave gid filled with NULs bool success = CFStringGetCString(progURL, cPath, sizeof(cPath), kCFStringEncodingUTF8);
sprintf(header.size,"%011llo",fileSize); if(success) {
sprintf(header.mtime,"%011lo",time(NULL)); progDir = cPath;
memset(header.checksum,' ',8); std::cout << cPath << "\n\n" << progDir << "\n\n";
header.typeflag[0]=directory?'5':'0'; } else {
//leave linkname filled with NULs std::cout << "Couldn't retrieve application path.\n";
sprintf(header.magic,"ustar "); //overwrites header with " \0" exit(1);
//leave uname filled with NULs }
//leave gname filled with NULs } else progDir = tmp;
//leave devmajor filled with NULs progDir = progDir.parent_path();
//leave devminor filled with NULs // TODO: If this places us in the "Scenario Editor" folder, back out one more directory
//leave prefix filled with NULs std::cout << progDir << '\n';
//leave pad filled with NULs // Initialize the resource manager paths
ResMgr::pushPath<ImageRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac");
ResMgr::pushPath<CursorRsrc>(progDir/"Scenario Editor"/"graphics.exd"/"mac"/"cursors");
ResMgr::pushPath<FontRsrc>(progDir/"data"/"fonts");
ResMgr::pushPath<StringRsrc>(progDir/"data"/"strings");
ResMgr::pushPath<SoundRsrc>(progDir/"Scenario Editor"/"sounds.exa");
unsigned int sum=0; // We need a location for temporary files, primarily for loading and saving operations
unsigned char* ptr=reinterpret_cast<unsigned char*>(&header); // The scenario editor may also use this location as "scratch space"
for(unsigned int i=0; i<sizeof(header); i++){ #if defined(_WIN32) || defined(_WIN64)
sum+=ptr[i]; tempDir = getenv("APPDATA");
} tempDir /= "Blades of Exile";
if(sum>0777777) #else
throw std::runtime_error("Checksum overflow"); tempDir = getenv("HOME");
sprintf(header.checksum,"%o",sum); #ifdef __APPLE__
return(header); tempDir /= "Library/Application Support/Blades of Exile";
#else
tempDir /= ".oboe/blades";
#endif // __APPLE__
#endif // _Win32||_Win64
tempDir /= "Temporary Files";
} }
bool load_scenario(fs::path file_to_load, bool skip_strings){ bool load_scenario(fs::path file_to_load, bool skip_strings){
@@ -1264,450 +1252,85 @@ bool load_party_v2(fs::path file_to_load, bool town_restore, bool in_scen, bool
bool save_party(fs::path dest_file) bool save_party(fs::path dest_file)
//mode; // 0 - normal 1 - save as //mode; // 0 - normal 1 - save as
{ {
//printf("Saving is currently disabled.\n"); if(!fs::exists(tempDir)) fs::create_directories(tempDir);
bool in_scen = univ.party.scen_name != ""; bool in_scen = univ.party.scen_name != "";
bool in_town = univ.town.num < 200; bool in_town = univ.town.num < 200;
bool save_maps = !univ.party.stuff_done[306][0]; bool save_maps = !univ.party.stuff_done[306][0];
// TODO: Strip off the header and save the remainder to a temporary file, then use gzip on that; this should fix the issue of the header being interpreted as compressed. tarball partyOut;
/* Open the GZip file and write the (uncompressed) header */
std::ofstream fout(dest_file.c_str(), std::ios_base::binary); // First, write the main party data
univ.party.writeTo(partyOut.newFile("save/party.txt"));
{
std::ostream& fout = partyOut.newFile("save/setup.dat");
static uint16_t magic = 0x0B0E;
fout.write((char*)&magic, 2);
fout.write((char*)&univ.party.setup, sizeof(cParty::setup));
}
// Then write the data for each of the party members
for(int i = 0; i < 6; i++) {
static char fname[] = "save/pc1.txt";
fname[7] = i + '1';
univ.party[i].writeTo(partyOut.newFile(fname));
}
if(in_scen) {
if(in_town) {
// Write the current town data
univ.town.writeTo(partyOut.newFile("save/town.txt"));
if(save_maps) {
// Write the town map data
std::ostream& fout = partyOut.newFile("save/townmaps.dat");
for(int i = 0; i < 200; i++)
for(int j = 0; j < 8; j++)
for(int k = 0; k < 64; k++)
fout.put(univ.town_maps[i][j][k]);
}
}
// Write the current outdoors data
univ.out.writeTo(partyOut.newFile("save/out.txt"));
if(save_maps) {
// Write the outdoors map data
std::ostream& fout = partyOut.newFile("save/outmaps.dat");
for(int i = 0; i < 100; i++)
for(int j = 0; j < 6; j++)
for(int k = 0; k < 48; k++)
fout.put(univ.out_maps[i][j][k]);
}
}
// TODO: Add the party graphics sheet
// Write out the compressed data
fs::path tempPath = tempDir/"savetemp.exg";
ogzstream zout(tempPath.c_str());
partyOut.writeTo(zout);
zout.close();
// Now add the header. We use the temporary file because we want the header to be uncompressed.
short flags[] = { short flags[] = {
0x0B0E, // to indicate new format 0x0B0E, // to indicate new format
static_cast<short>(in_town ? 1342 : 5790), // is the party in town? static_cast<short>(in_town ? 1342 : 5790), // is the party in town?
static_cast<short>(in_scen ? 100 : 200), // is the party in a scenario? static_cast<short>(in_scen ? 100 : 200), // is the party in a scenario?
static_cast<short>(save_maps ? 5567 : 3422), // is the save maps feature enabled? static_cast<short>(save_maps ? 5567 : 3422), // is the save maps feature enabled?
0x0100, // current version number, major and minor revisions only 0x0100, // current version number, major and minor revisions only
// Version 1 indicates a beta format that won't be supported in the final release // Version 1 indicates a beta format that may not be supported in the final release
}; };
if(!mac_is_intel) // must flip all the flags to little-endian if(!mac_is_intel) // must flip all the flags to little-endian
for(int i = 0; i < 5; i++) for(int i = 0; i < 5; i++)
flip_short(&flags[i]); flip_short(&flags[i]);
//fwrite(flags, sizeof(short), 5, f);
//gzFile party_file = gzdopen(fileno(f),"wb0"); // 0 indicates no compression; this is temporary std::ifstream fin(tempPath.c_str(), std::ios_base::binary);
//gzwrite(party_file, flags, sizeof(short)*5); std::ofstream fout(dest_file.c_str(), std::ios_base::binary);
//int q = gzflush(party_file, Z_FULL_FLUSH); // required in order to avoid the header getting compressed
//gzsetparams(party_file, Z_DEFAULT_COMPRESSION, Z_DEFAULT_STRATEGY);
fout.write((char*) flags, 5*sizeof(short)); fout.write((char*) flags, 5*sizeof(short));
fout << fin.rdbuf();
/* Initialize buffer and other variables */ fin.close();
header_posix_ustar header;
static char footer[2*sizeof(header_posix_ustar)] = {0};
std::ostringstream sout("");
std::ostringstream bout("",std::ios_base::binary);
std::string tar_entry;
size_t tar_size, y;
int x;
sout << x;
/* Write main party data to a buffer, and then to the file */
univ.party.writeTo(sout);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
header = generateTarHeader("save/party.txt",tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
sout.str(""); // clear the stream (I think)
/* Write player character data to a buffer, and then to the file */
for(int i = 0; i < 6; i++){
char f_name[20];
univ.party[i].writeTo(sout);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
sprintf(f_name,"save/pc%i.txt",i+1);
header = generateTarHeader(f_name,tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
sout.str(""); // clear the stream (I think)
}
if(in_scen){
if(in_town){
/* Write current town data to a buffer, and then to the file */
univ.town.writeTo(sout);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
header = generateTarHeader("save/town.txt",tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
sout.str(""); // clear the stream (I think)
if(save_maps){
/* Write town maps data to a buffer, and then to the file */
for(int i = 0; i < 200; i++)
for(int j = 0; j < 8; j++)
for(int k = 0; k < 64; k++)
sout.put(univ.town_maps[i][j][k]);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
header = generateTarHeader("save/townmaps.dat",tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
sout.str(""); // clear the stream (I think)
}
}
/* Write current outdoors data to a buffer, and then to the file */
univ.out.writeTo(sout);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
header = generateTarHeader("save/out.txt",tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
sout.str(""); // clear the stream (I think)
if(save_maps){
/* Write outdoor maps data to a buffer, and then to the file */
for(int i = 0; i < 100; i++)
for(int j = 0; j < 6; j++)
for(int k = 0; k < 48; k++)
sout.put(univ.out_maps[i][j][k]);
//write the footer to end the file
// for(unsigned int j=0; j<2*sizeof(header_posix_ustar); j++)
// sout.put('\0');
tar_entry = sout.str();
y = tar_size = tar_entry.length();
while(y % 512){
y++;
tar_entry += '\0';
}
header = generateTarHeader("save/outmaps.dat",tar_size);
bout.write((char*) &header, sizeof(header));
bout.write(tar_entry.c_str(), y);
// x = gzwrite(party_file, (char*) &header, sizeof(header));
// x = gzwrite(party_file, tar_entry.c_str(), y);
// //x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
// if(x == 0) { // error
// gzerror(party_file, &x);
// oops_error((x == Z_ERRNO) ? Z_ERRNO + 1000 : 1, (x == Z_ERRNO) ? errno : x, 1);
// gzclose(party_file);
// return false;
// }
// sout.str(""); // clear the stream (I think)
}
}
//x = gzwrite(party_file, footer, 2*sizeof(header_posix_ustar));
//gzclose(party_file);
bout.write(footer, 2*sizeof(header_posix_ustar));
tar_entry = bout.str();
tar_size = tar_entry.length();
unsigned char* buf = new unsigned char[tar_size];
compress(buf, &tar_size, (unsigned char*) tar_entry.data(), tar_size);
fout.write((char*)buf, tar_size);
delete buf;
fout.close(); fout.close();
// NavReplyRecord reply;
// OSErr error;
// short file_id;
// bool town_save = false;
// Str63 store_name;
// FSSpec to_load;
//
// short i;
//
// long len,store_len,count;
// flag_type flag;
// flag_type *store;
// party_record_type *party_ptr;
// setup_save_type *setup_ptr;
// pc_record_type *pc_ptr;
// // out_info_type store_explored;
// current_town_type *town_ptr;
// big_tr_type *town_data_ptr;
// town_item_list *item_ptr;
// stored_items_list_type *items_ptr;
// stored_town_maps_type *maps_ptr;
// stored_outdoor_maps_type *o_maps_ptr;
//
// char *party_encryptor;
//
// if ((in_startup_mode == false) && (is_town()))
// town_save = true;
//
// strcpy ((char *) store_name, (char *) last_load_file);
//
//
// if ((mode == 1) || (loaded_yet == false)) {
// NavPutFile(NULL,&reply,NULL,NULL,'beSV','blx!',NULL);
// if (reply.validRecord == false)
// return;
//
// AEKeyword keyword;
// DescType descType;
// Size actualSize;
//
// AEGetNthPtr(&reply.selection,1,typeFSS,&keyword,&descType,&to_load,sizeof(FSSpec),&actualSize);
// loaded_yet = true;
// }
// else to_load = store_file_reply;
//
// error = FSpCreate(&to_load,'blx!','beSV',reply.keyScript);
// if ((error != 0) && (error != dupFNErr)) {
// add_string_to_buf("Save: Couldn't create file. ");
// SysBeep(2);
// return;
// }
// if ((error = FSpOpenDF(&to_load,3,&file_id)) != 0) {
// add_string_to_buf("Save: Couldn't open file. ");
// SysBeep(2);
// return;
// }
// strcpy ((char *) last_load_file, (char *) to_load.name);
// store_file_reply = to_load;
//
//
// store = &flag;
//
// len = sizeof(flag_type);
//
// flag.i = (town_save == true) ? 1342 : 5790;
// if ((error = FSWrite(file_id, &len, (char *) store)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// }
// flag.i = (in_startup_mode == false) ? 100 : 200;
// if ((error = FSWrite(file_id, &len, (char *) store)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// flag.i = (save_maps == true) ? 5567 : 3422;
// if ((error = FSWrite(file_id, &len, (char *) store)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
//
// // SAVE PARTY
// party_ptr = &party;
// len = sizeof(party_record_type);
//
// store_len = len;
// party_encryptor = (char *) party_ptr;
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x5C;
// if ((error = FSWrite(file_id, &len, (char *) party_ptr)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x5C;
// SysBeep(2);
// return;
// }
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x5C;
//
// // SAVE SETUP
// setup_ptr = &setup_save;
// len = sizeof(setup_save_type);
// if ((error = FSWrite(file_id, &len, (char *) setup_ptr)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
//
// // SAVE PCS
// store_len = sizeof(pc_record_type);
// for (i = 0; i < 6; i++) {
// pc_ptr = &adven[i];
//
// len = store_len;
// party_encryptor = (char *) pc_ptr;
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x6B;
// if ((error = FSWrite(file_id, &len, (char *) pc_ptr)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x6B;
// SysBeep(2);
// return;
// }
// for (count = 0; count < store_len; count++)
// party_encryptor[count] ^= 0x6B;
// }
//
// if (in_startup_mode == false) {
//
// // SAVE OUT DATA
// len = sizeof(out_info_type);
// if ((error = FSWrite(file_id, &len, (char *) out_e)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
//
// if (town_save == true) {
// town_ptr = &c_town;
// len = sizeof(current_town_type);
// if ((error = FSWrite(file_id, &len, (char *) town_ptr)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// town_data_ptr = &t_d;
// len = sizeof(big_tr_type);
// if ((error = FSWrite(file_id, &len, (char *) town_data_ptr)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// item_ptr = &t_i;
// len = sizeof(town_item_list);
// if ((error = FSWrite(file_id, &len, (char *) item_ptr)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// }
//
// // Save stored items
// for (i = 0; i < 3; i++) {
// items_ptr = &stored_items[i];
// len = (long) sizeof(stored_items_list_type);
// if ((error = FSWrite(file_id, &len, (char *) items_ptr)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// }
//
// // If saving maps, save maps
// if (save_maps == true) {
// maps_ptr = &(town_maps);
// len = (long) sizeof(stored_town_maps_type);
// if ((error = FSWrite(file_id, &len, (char *) maps_ptr)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
//
// o_maps_ptr = &o_maps;
// len = (long) sizeof(stored_outdoor_maps_type);
// if ((error = FSWrite(file_id, &len, (char *) o_maps_ptr)) != 0) {
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// }
//
// // SAVE SFX and MISC_I
// len = (long) (64 * 64);
// if ((error = FSWrite(file_id, &len, (char *) sfx)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
// if ((error = FSWrite(file_id, &len, (char *) misc_i)) != 0){
// add_string_to_buf("Save: Couldn't write to file. ");
// FSClose(file_id);
// SysBeep(2);
// return;
// }
//
//
//
// }
//
// if ((error = FSClose(file_id)) != 0) {
// add_string_to_buf("Save: Couldn't close file. ");
// SysBeep(2);
// return;
// }
// if (in_startup_mode == false)
// add_string_to_buf("Save: Game saved. ");
return true; return true;
} }

View File

@@ -27,3 +27,5 @@ std::vector<std::string> load_strings(std::string which);
bool load_party(fs::path file_to_load); bool load_party(fs::path file_to_load);
bool save_party(fs::path dest_file); bool save_party(fs::path dest_file);
void init_directories();

98
osx/tools/tarball.cpp Normal file
View File

@@ -0,0 +1,98 @@
//
// tarball.cpp
// BoE
//
// Created by Celtic Minstrel on 14-04-19.
//
//
#include "tarball.hpp"
#include <boost/lexical_cast.hpp>
tarball::header_posix_ustar tarball::generateTarHeader(const std::string& fileName, unsigned long long fileSize, bool directory){
static_assert(sizeof(header_posix_ustar) == 512, "Uh-oh! Padding in the tarball header!");
if(fileSize > 077777777777LL)
throw std::length_error("Specified file size >= 8 GB");
if(fileName.length() >= 100)
throw std::length_error("Specified file name longer than 99 characters.");
header_posix_ustar header;
char* init = (char*) &header;
for(unsigned int i = 0; i < sizeof(header); i++) init[i] = 0;
snprintf(header.name,100,"%s",fileName.c_str());
snprintf(header.mode,8,"%07o",0600);
// leave uid filled with NULs
// leave gid filled with NULs
snprintf(header.size,12,"%011llo",fileSize);
snprintf(header.mtime,12,"%011lo",time(NULL));
memset(header.checksum,' ',8);
header.typeflag[0] = directory ? '5' : '0';
// leave linkname filled with NULs
snprintf(header.magic,6,"ustar ");
snprintf(header.version,2," ");
// leave uname filled with NULs
// leave gname filled with NULs
// leave devmajor filled with NULs
// leave devminor filled with NULs
// leave prefix filled with NULs
// leave pad filled with NULs
unsigned int sum = 0;
unsigned char* ptr = reinterpret_cast<unsigned char*>(&header);
for(unsigned int i = 0; i < sizeof(header); i++){
sum += ptr[i];
}
if(sum > 0777777)
throw std::runtime_error("Checksum overflow");
snprintf(header.checksum,8,"%o",sum);
return header;
}
void tarball::writeTo(std::ostream& out) {
static const char padding[512] = {0};
for(tarfile& entry : files) {
entry.contents.seekg(0, std::ios_base::end);
unsigned long long size = entry.contents.tellg();
unsigned long long padLength = 512 - size % 512;
entry.contents.seekg(0);
entry.header = generateTarHeader(entry.filename, size);
out.write((char*)&entry.header, sizeof(header_posix_ustar));
out << entry.contents.rdbuf();
out.write(padding, padLength);
}
}
void tarball::readFrom(std::istream& in) {
static char buf[513];
while(!in.eof()) {
files.push_back(tarfile());
header_posix_ustar& header = files.back().header;
in.read((char*)&header, sizeof(header_posix_ustar));
files.back().filename = header.name;
unsigned long long size = boost::lexical_cast<unsigned long long>(header.size);
unsigned long long padLength = 512 - size % 512;
in.read(buf, size);
files.back().contents.write(buf, size);
in.seekg(padLength, std::ios_base::cur);
}
}
std::ostream& tarball::newFile(std::string fname) {
files.push_back(tarfile());
files.back().filename = fname;
return files.back().contents;
}
std::istream& tarball::getFile(std::string fname) {
for(tarfile& entry : files) {
if(entry.filename == fname) {
entry.contents.seekg(0);
return entry.contents;
}
}
// If the file doesn't exist, return an empty stream
static std::istringstream empty;
empty.clear();
empty.seekg(0);
return empty;
}

51
osx/tools/tarball.hpp Normal file
View File

@@ -0,0 +1,51 @@
//
// tarball.hpp
// BoE
//
// Created by Celtic Minstrel on 14-04-19.
//
//
#ifndef BoE_tarball_hpp
#define BoE_tarball_hpp
#include <sstream>
#include <deque>
class tarball {
struct header_posix_ustar {
char name[100];
char mode[8];
char uid[8];
char gid[8];
char size[12];
char mtime[12];
char checksum[8];
char typeflag[1];
char linkname[100];
char magic[6];
char version[2];
char uname[32];
char gname[32];
char devmajor[8];
char devminor[8];
char prefix[155];
char pad[12];
};
struct tarfile {
header_posix_ustar header;
std::string filename;
std::stringstream contents;
};
std::deque<tarfile> files;
static header_posix_ustar generateTarHeader(const std::string& fileName, unsigned long long fileSize, bool directory=false);
public:
void writeTo(std::ostream& out);
void readFrom(std::istream& in);
std::ostream& newFile(std::string fname);
void newDirectory(std::string dname);
std::istream& getFile(std::string fname);
};
#endif