Ticket #8624: dialog_save_memory.patch

File dialog_save_memory.patch, 9.5 KB (added by SF/tobigun, 15 years ago)

RAM buffer version

  • engines/scumm/input.cpp

     
    410410        // Fall back to default behavior
    411411        ScummEngine::processKeyboard(lastKeyHit);
    412412
     413        // On Alt-F5 prepare savegame for the original save/load dialog.
     414        if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.flags == Common::KBD_ALT) {
     415                prepareSavegame();
     416        }
     417
    413418        if (VAR_KEYPRESS != 0xFF && _mouseAndKeyboardStat) {            // Key Input
    414419                if (315 <= _mouseAndKeyboardStat && _mouseAndKeyboardStat <= 323) {
    415420                        // Convert F-Keys for V1/V2 games (they start at 1)
     
    424429        // Fall back to default behavior
    425430        ScummEngine::processKeyboard(lastKeyHit);
    426431
    427         // 'i' brings up an IQ dialog in Indy3
    428         if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3) {
     432        // On Alt-F5 prepare savegame for the original save/load dialog.
     433        if (lastKeyHit.keycode == Common::KEYCODE_F5 && lastKeyHit.flags == Common::KBD_ALT) {
     434                prepareSavegame();
     435        }
     436
     437        // 'i' brings up an IQ dialog in Indy3 (disabled in save/load dialog for input)
     438        if (lastKeyHit.ascii == 'i' && _game.id == GID_INDY3 && _currentRoom != 14) {
    429439                // SCUMM var 244 is the episode score
    430440                // and var 245 is the series score
    431441                char text[50];
  • engines/scumm/saveload.cpp

     
    2828#include "common/config-manager.h"
    2929#include "common/savefile.h"
    3030#include "common/system.h"
     31#include "common/zlib.h"
    3132
    3233#include "scumm/actor.h"
    3334#include "scumm/charset.h"
     
    129130        return true;
    130131}
    131132
     133bool ScummEngine::saveState(Common::OutSaveFile *out, bool writeHeader) {
     134        SaveGameHeader hdr;
     135
     136        if (writeHeader) {
     137                memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
     138                saveSaveGameHeader(out, hdr);
     139        }
     140#if !defined(__DS__)
     141        Graphics::saveThumbnail(*out);
     142#endif
     143        saveInfos(out);
     144
     145        Serializer ser(0, out, CURRENT_VER);
     146        saveOrLoad(&ser);
     147        return true;
     148}
     149
    132150bool ScummEngine::saveState(int slot, bool compat) {
     151        bool saveFailed;
    133152        Common::String filename;
    134153        Common::OutSaveFile *out;
    135         SaveGameHeader hdr;
    136154
    137155        if (_saveLoadSlot == 255) {
    138156                // Allow custom filenames for save game system in HE Games
     
    143161        if (!(out = _saveFileMan->openForSaving(filename.c_str())))
    144162                return false;
    145163
    146         memcpy(hdr.name, _saveLoadName, sizeof(hdr.name));
    147         saveSaveGameHeader(out, hdr);
    148 #if !defined(__DS__)
    149         Graphics::saveThumbnail(*out);
    150 #endif
    151         saveInfos(out);
     164        saveFailed = false;
     165        if (!saveState(out))
     166                saveFailed = true;
    152167
    153         Serializer ser(0, out, CURRENT_VER);
    154         saveOrLoad(&ser);
    155168        out->finalize();
    156         if (out->err()) {
    157                 delete out;
     169        if (out->err())
     170                saveFailed = true;
     171        delete out;
     172
     173        if (saveFailed) {
    158174                debug(1, "State save as '%s' FAILED", filename.c_str());
    159175                return false;
    160176        }
    161         delete out;
    162177        debug(1, "State saved as '%s'", filename.c_str());
    163178        return true;
    164179}
    165180
     181
     182void ScummEngine::prepareSavegame() {
     183        Common::MemoryWriteStreamDynamic *memStream;
     184        Common::WriteStream *writeStream;
     185
     186        // free memory of the last prepared savegame
     187        delete _savePreparedSavegame;
     188        _savePreparedSavegame = NULL;
     189
     190        // store headerless savegame in a compressed memory stream
     191        memStream = new Common::MemoryWriteStreamDynamic();
     192        writeStream = Common::wrapCompressedWriteStream(memStream);
     193        if (saveState(writeStream, false)) {
     194                // we have to finalize the compression-stream first, otherwise the internal
     195                // memory-stream pointer will be zero (Important: flush() does not work here!).
     196                writeStream->finalize();
     197                if (!writeStream->err()) {
     198                        // wrap uncompressing MemoryReadStream around the savegame data
     199                        _savePreparedSavegame = Common::wrapCompressedReadStream(
     200                                new Common::MemoryReadStream(memStream->getData(), memStream->size(), true));
     201                }
     202        }
     203        // free the CompressedWriteStream and MemoryWriteStreamDynamic
     204        // but not the memory stream's internal buffer
     205        delete writeStream;
     206}
     207
     208bool ScummEngine::savePreparedSavegame(int slot, char *desc) {
     209        bool success;
     210        Common::String filename;
     211        Common::OutSaveFile *out;
     212        SaveGameHeader hdr;
     213        uint32 nread, nwritten;
     214        byte buffer[1024];
     215
     216        out = 0;
     217        success = true;
     218
     219        // check if savegame was successfully stored in memory
     220        if (!_savePreparedSavegame)
     221                success = false;
     222
     223        // open savegame file
     224        if (success) {
     225                filename = makeSavegameName(slot, false);
     226                if (!(out = _saveFileMan->openForSaving(filename.c_str()))) {
     227                        success = false;
     228                }
     229        }
     230
     231        // write header to file
     232        if (success) {
     233                memset(hdr.name, 0, sizeof(hdr.name));
     234                strncpy(hdr.name, desc, sizeof(hdr.name)-1);
     235                success = saveSaveGameHeader(out, hdr);
     236        }
     237
     238        // copy savegame from memory-stream to file
     239        if (success) {
     240                _savePreparedSavegame->seek(0, SEEK_SET);
     241                while (nread = _savePreparedSavegame->read(buffer, sizeof(buffer))) {
     242                        nwritten = out->write(buffer, nread);
     243                        if (nwritten < nread) {
     244                                success = false;
     245                                break;
     246                        }
     247                }
     248        }
     249
     250        if (out) {
     251                out->finalize();
     252                if (out->err())
     253                        success = false;
     254                delete out;
     255        }
     256
     257        if (!success) {
     258                debug(1, "State save as '%s' FAILED", filename.c_str());
     259                return false;
     260        } else {
     261                debug(1, "State saved as '%s'", filename.c_str());
     262                return true;
     263        }
     264}
     265
    166266static bool loadSaveGameHeader(Common::SeekableReadStream *in, SaveGameHeader &hdr) {
    167267        hdr.type = in->readUint32BE();
    168268        hdr.size = in->readUint32LE();
  • engines/scumm/script_v5.cpp

     
    869869        // which matches the original Indy3 save/load code. See also the notes
    870870        // on Feature Request #1666521.
    871871        STRINGID_IQ_EPISODE = 7,
    872         STRINGID_IQ_SERIES = 9
     872        STRINGID_IQ_SERIES = 9,
     873        // The string IDs of the first savegame name, used as an offset to determine
     874        // the IDs of all savenames.
     875        // Loom is the only game whose savenames start with a different ID.
     876        STRINGID_SAVENAME1 = 10,
     877        STRINGID_SAVENAME1_LOOM = 9
    873878};
    874879
    875880void ScummEngine_v5::o5_saveLoadVars() {
     
    12351240                result = 100;
    12361241                break;
    12371242        case 0x20: // drive
    1238                 if (_game.id == GID_INDY3) {
    1239                         // 0 = hard drive
    1240                         // 1 = disk drive
    1241                         result = 0;
     1243                if (_game.version <= 3) {
     1244                        // 0 = ???
     1245                        // [1,2] = disk drive [A:,B:]
     1246                        // 3 = hard drive
     1247                        result = 3;
    12421248                } else {
    12431249                        // set current drive
    12441250                        result = 1;
    12451251                }
    12461252                break;
    12471253        case 0x40: // load
    1248                 if (loadState(slot, _saveTemporaryState))
     1254                if (loadState(slot, false))
    12491255                        result = 3; // sucess
    12501256                else
    12511257                        result = 5; // failed to load
    12521258                break;
    12531259        case 0x80: // save
    1254                 //if (saveState(slot, _saveTemporaryState))
    1255                 //      result = 0; // sucess
    1256                 //else
     1260                if (_game.version <= 3) {
     1261                        char name[32];
     1262                        if (_game.version <= 2) {
     1263                                // use generic name
     1264                                sprintf(name, "Game %c", 'A'+slot-1);
     1265                        } else {
     1266                                // use name entered by the user
     1267                                char* ptr;
     1268                                int firstSlot = (_game.id == GID_LOOM) ? STRINGID_SAVENAME1_LOOM : STRINGID_SAVENAME1;
     1269                                ptr = (char*)getStringAddress(slot + firstSlot - 1);
     1270                                strncpy(name, ptr, sizeof(name));
     1271                        }
     1272
     1273                        if(savePreparedSavegame(slot, name))
     1274                                result = 0;
     1275                        else
     1276                                result = 2;
     1277                } else {
    12571278                        result = 2; // failed to save
     1279                }
    12581280                break;
    12591281        case 0xC0: // test if save exists
    12601282                {
  • engines/scumm/scumm.cpp

     
    198198        _saveLoadSlot = 0;
    199199        _lastSaveTime = 0;
    200200        _saveTemporaryState = false;
     201        _savePreparedSavegame = NULL;
    201202        memset(_saveLoadFileName, 0, sizeof(_saveLoadFileName));
    202203        memset(_saveLoadName, 0, sizeof(_saveLoadName));
    203204        memset(_localScriptOffsets, 0, sizeof(_localScriptOffsets));
     
    569570        delete _costumeLoader;
    570571        delete _costumeRenderer;
    571572
     573        delete _savePreparedSavegame;
     574
    572575        _textSurface.free();
    573576
    574577        free(_shadowPalette);
     
    14161419                _keyDownMap[i] = false;
    14171420
    14181421        _lastSaveTime = _system->getMillis();
     1422
     1423        delete _savePreparedSavegame;
     1424        _savePreparedSavegame = NULL;
    14191425}
    14201426
    14211427void ScummEngine_v0::resetScumm() {
  • engines/scumm/scumm.h

     
    2929#include "engines/engine.h"
    3030#include "common/endian.h"
    3131#include "common/file.h"
     32#include "common/savefile.h"
    3233#include "common/keyboard.h"
    3334#include "common/rect.h"
    3435#include "common/str.h"
     
    626627        char _saveLoadFileName[32];
    627628        char _saveLoadName[32];
    628629
     630        // Prepared savegame used by the orginal save/load dialog.
     631        // Must be valid as long as the savescreen is active. As we are not
     632        // notified when the savescreen is closed, memory is only freed on a game
     633        // reset, at the destruction of the engine or when the original save/load dialog
     634        // is entered the next time.
     635        Common::SeekableReadStream* _savePreparedSavegame;
     636
     637        bool saveState(Common::OutSaveFile *out, bool writeHeader = true);
    629638        bool saveState(int slot, bool compat);
    630639        bool loadState(int slot, bool compat);
    631640        virtual void saveOrLoad(Serializer *s);
     
    633642        void saveResource(Serializer *ser, int type, int index);
    634643        void loadResource(Serializer *ser, int type, int index);
    635644
     645        void prepareSavegame();
     646        bool savePreparedSavegame(int slot, char *desc);
     647
    636648        Common::String makeSavegameName(int slot, bool temporary) const {
    637649                return makeSavegameName(_targetName, slot, temporary);
    638650        }