Ticket #8452: scumm_info_v4.patch

File scumm_info_v4.patch, 18.2 KB (added by lordhoto, 16 years ago)

Patch V4 against todays anon CVS

  • common/file.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/common/file.cpp ./scummvm/common/file.cpp
    old new  
    100100        return file;
    101101}
    102102
     103static bool removeNoCase(const char *filename, const char *directory) {
     104        char buf[512];
     105        char *ptr;
     106
     107        assert(directory);
     108        strcpy(buf, directory);
     109
     110#if !defined(__GP32__) && !defined(__PALM_OS__)
     111        // Add a trailing slash, if necessary.
     112        if (buf[0] != 0) {
     113                const int dirLen = strlen(buf);
     114                if (buf[dirLen-1] != ':' && buf[dirLen-1] != '/' && buf[dirLen-1] != '\\')
     115                        strcat(buf, "/");
     116        }
     117#endif
     118
     119        // Append the filename to the path string
     120        const int offsetToFileName = strlen(buf);
     121        strcat(buf, filename);
     122
     123        //
     124        // Try to remove the file normally
     125        //
     126        if (remove(buf) == 0)
     127                        return true;
     128
     129        //
     130        // Try again, with file name converted to upper case
     131        //
     132        ptr = buf + offsetToFileName;
     133        while (*ptr) {
     134                *ptr = toupper(*ptr);
     135                ptr++;
     136        }
     137        if (remove(buf) == 0)
     138                return true;
     139
     140        //
     141        // Try again, with file name converted to lower case
     142        //
     143        ptr = buf + offsetToFileName;
     144        while (*ptr) {
     145                *ptr = tolower(*ptr);
     146                ptr++;
     147        }
     148        if (remove(buf) == 0)
     149                return true;
     150
     151        //
     152        // Try again, with file name capitalized
     153        //
     154        ptr = buf + offsetToFileName;
     155        *ptr = toupper(*ptr);
     156        if (remove(buf) == 0)
     157                return true;
     158
     159        return false;
     160}
     161
    103162void File::addDefaultDirectory(const String &directory) {
    104163        _defaultDirectories.push_back(directory);
    105164}
     
    186245        // FIXME: Ugly ugly hack!
    187246        File tmp;
    188247        return tmp.open(filename, kFileReadMode, directory);
     248}
     249
     250bool File::remove(const char *filename, const char *directory) {
     251        if (!exists(filename, directory))
     252                return false;
     253
     254        bool removed = false;
     255
     256        if (directory) {
     257                if (removeNoCase(filename, directory))
     258                        removed = true;
     259        } else {
     260                // removes all files with this name in the standard directories
     261                StringList::const_iterator x;
     262                for (x = _defaultDirectories.begin(); x != _defaultDirectories.end(); ++x) {
     263                        if (removeNoCase(filename, x->c_str()))
     264                                removed = true;
     265                }
     266        }
     267
     268        if (!removed) {
     269                debug(2, "Coudln't remove file '%s' (specified directory: '%s')", filename, directory);
     270        }
     271
     272        return removed;
    189273}
    190274
    191275void File::close() {
  • common/file.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/common/file.h ./scummvm/common/file.h
    old new  
    6363
    6464        virtual bool open(const char *filename, AccessMode mode = kFileReadMode, const char *directory = NULL);
    6565        static bool exists(const char *filename, const char *directory = NULL);
     66        // this COULD remove whole directories, so use with caution
     67        static bool remove(const char *filename, const char *directory = NULL);
    6668
    6769        virtual void close();
    6870        bool isOpen() const;
  • scumm/dialogs.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/scumm/dialogs.cpp ./scummvm/scumm/dialogs.cpp
    old new  
    2121#include "common/stdafx.h"
    2222
    2323#include "common/config-manager.h"
     24#include "common/savefile.h"
    2425#include "common/system.h"
    2526#include "common/scaler.h"
    2627
     
    2829#include "gui/chooser.h"
    2930#include "gui/newgui.h"
    3031#include "gui/ListWidget.h"
     32#include "gui/message.h"
    3133
    3234#include "scumm/dialogs.h"
    3335#include "scumm/sound.h"
     
    193195
    194196#pragma mark -
    195197
     198Common::StringList generateSavegameList(ScummEngine *scumm, bool saveMode);
     199
    196200enum {
    197201        kSaveCmd = 'SAVE',
    198202        kLoadCmd = 'LOAD',
     203        kRemoveCmd = 'REM ',
    199204        kPlayCmd = 'PLAY',
    200205        kOptionsCmd = 'OPTN',
    201206        kHelpCmd = 'HELP',
     
    208213        typedef Common::StringList StringList;
    209214protected:
    210215        bool _saveMode;
     216        GUI::ButtonWidget       *_removeButton;
     217        ScummEngine             *_scumm;
    211218
    212219public:
    213         SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode);
     220        SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine* scumm);
    214221
    215222        virtual void handleCommand(CommandSender *sender, uint32 cmd, uint32 data);
    216223        const String &getResultString() const;
     
    218225        int runModal() { return GUI_ChooserDialog::runModal(); }
    219226};
    220227
    221 SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode)
    222         : GUI::ChooserDialog(title, buttonLabel, 182), _saveMode(saveMode) {
     228SaveLoadChooser::SaveLoadChooser(const String &title, const String &buttonLabel, bool saveMode, ScummEngine* scumm)
     229        : GUI::ChooserDialog(title, buttonLabel, 182), _saveMode(saveMode), _scumm(scumm) {
    223230
    224231        _list->setEditable(saveMode);
    225232        _list->setNumberingMode(saveMode ? GUI::kListNumberingOne : GUI::kListNumberingZero);
     233
     234        if (!saveMode) {
     235                _removeButton = addButton(this, _x + 10, _h - kButtonHeight - 8, "Remove", kRemoveCmd, 0, GUI::kNormalWidgetSize);
     236                _removeButton->setEnabled(false);
     237        } else
     238                _removeButton = 0;
    226239}
    227240
    228241const Common::String &SaveLoadChooser::getResultString() const {
     
    241254                        }
    242255                }
    243256                break;
     257        case kRemoveCmd: {
     258                if (!_saveMode) {
     259                        GUI::MessageDialog alert("Do you really want to remove this savegame?", "Yes", "No");
     260                        if (alert.runModal() == GUI::kMessageOK) {
     261                                if (_scumm->removeState(selItem)) {
     262                                        GUI::TimedMessageDialog msg("Removed savegame successfully", 1000);
     263                                        msg.runModal();
     264                                        setList(generateSavegameList(_scumm, false));
     265                                } else {
     266                                        GUI::TimedMessageDialog msg("Couldn't remove savegame", 1000);
     267                                        msg.runModal();
     268                                }
     269                        }
     270                        _list->draw();
     271                        _chooseButton->setEnabled(false);
     272                        _chooseButton->draw();
     273                        _removeButton->setEnabled(false);
     274                        _removeButton->draw();
     275                }
     276        } break;
    244277        case GUI::kListSelectionChangedCmd:
    245278                if (_saveMode) {
    246279                        _list->startEditMode();
     
    250283                // because we then just assign a default name.
    251284                _chooseButton->setEnabled(selItem >= 0 && (_saveMode || !getResultString().isEmpty()));
    252285                _chooseButton->draw();
     286
     287                if (!_saveMode) {
     288                        _removeButton->setEnabled(selItem >= 0 && !getResultString().isEmpty());
     289                        _removeButton->draw();
     290                }
    253291                break;
    254292        default:
    255293                GUI_ChooserDialog::handleCommand(sender, cmd, data);
     
    270308        bool _saveMode;
    271309        GUI::ListWidget         *_list;
    272310        GUI::ButtonWidget       *_chooseButton;
     311        GUI::ButtonWidget       *_removeButton;
    273312        GUI::GraphicsWidget     *_gfxWidget;
     313        GUI::StaticTextWidget   *_date;
     314        GUI::StaticTextWidget   *_time;
     315        GUI::StaticTextWidget   *_playtime;
    274316        ScummEngine                     *_scumm;
    275317
    276318public:
     
    300342                        ((_scumm->_system->getHeight() % 200 && _scumm->_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1) + 8);
    301343        _gfxWidget->setFlags(GUI::WIDGET_BORDER);
    302344
     345        int height = 18 + ((_scumm->_system->getHeight() % 200 && _scumm->_system->getHeight() != 350) ? kThumbnailHeight2 : kThumbnailHeight1) + 8;
     346
     347        _date = new StaticTextWidget(this,
     348                                        _w - (kThumbnailWidth + 22),
     349                                        height,
     350                                        kThumbnailWidth + 8,
     351                                        kLineHeight,
     352                                        "Date: 00.00.0000",
     353                                        kTextAlignCenter);
     354        _date->setFlags(GUI::WIDGET_CLEARBG);
     355
     356        height += kLineHeight;
     357
     358        _time = new StaticTextWidget(this,
     359                                        _w - (kThumbnailWidth + 22),
     360                                        height,
     361                                        kThumbnailWidth + 8,
     362                                        kLineHeight,
     363                                        "Time: 00:00",
     364                                        kTextAlignCenter);
     365        _time->setFlags(GUI::WIDGET_CLEARBG);
     366
     367        height += kLineHeight;
     368
     369        _playtime = new StaticTextWidget(this,
     370                                        _w - (kThumbnailWidth + 22),
     371                                        height,
     372                                        kThumbnailWidth + 8,
     373                                        kLineHeight,
     374                                        "Playtime: 00:00",
     375                                        kTextAlignCenter);
     376        _playtime->setFlags(GUI::WIDGET_CLEARBG);
     377
    303378        // Buttons
     379        if (!saveMode) {
     380                _removeButton = addButton(this, _x + 10, _h - kBigButtonHeight - 8, "Remove", kRemoveCmd, 0, GUI::kBigWidgetSize);
     381                _removeButton->setEnabled(false);
     382        } else
     383                _removeButton = 0;
    304384        addButton(this, _w - 2 * (kBigButtonWidth + 10), _h - kBigButtonHeight - 8, "Cancel", kCloseCmd, 0, GUI::kBigWidgetSize);
    305385        _chooseButton = addButton(this, _w - (kBigButtonWidth + 10), _h - kBigButtonHeight - 8, buttonLabel, kChooseCmd, 0, GUI::kBigWidgetSize);
    306386        _chooseButton->setEnabled(false);
     
    338418                setResult(selItem);
    339419                close();
    340420                break;
     421        case kRemoveCmd: {
     422                if (!_saveMode) {
     423                        GUI::MessageDialog alert("Do you really want to remove this savegame?", "Yes", "No");
     424                        if (alert.runModal() == GUI::kMessageOK) {
     425                                if (_scumm->removeState(selItem)) {
     426                                        GUI::TimedMessageDialog msg("Removed savegame successfully", 1000);
     427                                        msg.runModal();
     428                                        setList(generateSavegameList(_scumm, false));
     429                                } else {
     430                                        GUI::TimedMessageDialog msg("Couldn't remove savegame", 1000);
     431                                        msg.runModal();
     432                                }
     433                        }
     434                        _list->draw();
     435                        _chooseButton->setEnabled(false);
     436                        _chooseButton->draw();
     437                        _removeButton->setEnabled(false);
     438                        _removeButton->draw();
     439                }
     440        } break;
    341441        case GUI::kListSelectionChangedCmd: {
    342442                Graphics::Surface *thumb;
    343443                thumb = _scumm->loadThumbnailFromSlot(_saveMode ? selItem + 1 : selItem);
    344444                _gfxWidget->setGfx(thumb);
     445                if (thumb)
     446                        thumb->free();
    345447                delete thumb;
    346448                _gfxWidget->draw();
    347449
     450                InfoStuff infos;
     451                memset(&infos, 0, sizeof(InfoStuff));
     452                char buffer[32];
     453                if (_scumm->loadInfosFromSlot(_saveMode ? selItem + 1 : selItem, &infos)) {
     454                        snprintf(buffer, 32, "Date: %.2d.%.2d.%.4d",
     455                                (infos.date >> 24) & 0xFF, (infos.date >> 16) & 0xFF,
     456                                infos.date & 0xFFFF);
     457                        _date->setLabel(buffer);
     458                        _date->draw();
     459                       
     460                        snprintf(buffer, 32, "Time: %.2d:%.2d",
     461                                (infos.time >> 8) & 0xFF, infos.time & 0xFF);
     462                        _time->setLabel(buffer);
     463                        _time->draw();
     464
     465                        int minutes = infos.playtime / 60;
     466                        int hours = minutes / 60;
     467                        minutes %= 60;
     468
     469                        snprintf(buffer, 32, "Playtime: %.2d:%.2d",
     470                                hours & 0xFF, minutes & 0xFF);
     471                        _playtime->setLabel(buffer);
     472                        _playtime->draw();
     473                } else {
     474                        snprintf(buffer, 32, "No date saved");
     475                        _date->setLabel(buffer);
     476                        _date->draw();
     477                       
     478                        snprintf(buffer, 32, "No time saved");
     479                        _time->setLabel(buffer);
     480                        _time->draw();
     481
     482                        snprintf(buffer, 32, "No playtime saved");
     483                        _playtime->setLabel(buffer);
     484                        _playtime->draw();
     485                }
     486
    348487                if (_saveMode) {
    349488                        _list->startEditMode();
    350489                }
     
    353492                // because we then just assign a default name.
    354493                _chooseButton->setEnabled(selItem >= 0 && (_saveMode || !getResultString().isEmpty()));
    355494                _chooseButton->draw();
     495                // same as above only that in save mode it is also disabled when choosing an
     496                // empty savegame.
     497                if (!_saveMode) {
     498                        _removeButton->setEnabled(selItem >= 0 && !getResultString().isEmpty());
     499                        _removeButton->draw();
     500                }
    356501        } break;
    357502        case kCloseCmd:
    358503                setResult(-1);
     
    452597        _helpDialog = new HelpDialog(scumm);
    453598#endif
    454599        if (scumm->_system->getOverlayWidth() <= 320) {
    455                 _saveDialog = new SaveLoadChooser("Save game:", "Save", true);
    456                 _loadDialog = new SaveLoadChooser("Load game:", "Load", false);
     600                _saveDialog = new SaveLoadChooser("Save game:", "Save", true, scumm);
     601                _loadDialog = new SaveLoadChooser("Load game:", "Load", false, scumm);
    457602        } else {
    458603                _saveDialog = new SaveLoadChooserEx("Save game:", "Save", true, scumm);
    459604                _loadDialog = new SaveLoadChooserEx("Load game:", "Load", false, scumm);
  • scumm/saveload.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/scumm/saveload.cpp ./scummvm/scumm/saveload.cpp
    old new  
    5151        char name[32];
    5252};
    5353
     54struct SaveInfoHeader {
     55        uint32 type;
     56        uint32 size;
     57        byte version;
     58       
     59        uint32 date;
     60        uint16 time;
     61        uint32 playtime;
     62};
     63
     64#define INFOHEADER_VERSION 1
    5465
    5566void ScummEngine::requestSave(int slot, const char *name, bool temporary) {
    5667        _saveLoadSlot = slot;
     
    8495
    8596        out->write(&hdr, sizeof(hdr));
    8697        saveThumbnail(out);
     98        saveInfos(out);
    8799
    88100        Serializer ser(0, out, CURRENT_VER);
    89101        saveOrLoad(&ser, CURRENT_VER);
     
    111123        }
    112124
    113125        // In older versions of ScummVM, the header version was not endian safe.
    114         // We account for that by retrying once with swapped byte order.
     126        // We account for that by retrying once wi_system->getMillis() / 1000th swapped byte order.
    115127        if (hdr.ver > CURRENT_VER)
    116128                hdr.ver = SWAP_BYTES_32(hdr.ver);
    117129        if (hdr.ver < VER(7) || hdr.ver > CURRENT_VER)
     
    144156                in->skip(size - 8);
    145157        }
    146158
     159        // Since version 56 we have informations about the creating of the save game and the save time here
     160        if (hdr.ver >= VER(56)) {
     161                InfoStuff infos;
     162                if (!loadInfos(in, &infos)) {
     163                        delete in;
     164                        return false;
     165                }
     166
     167                _engineStartTime = _system->getMillis() / 1000 - infos.playtime;
     168        } else {
     169                // start time counting
     170                _engineStartTime = _system->getMillis() / 1000;
     171        }
     172
     173        _dialogStartTime = _system->getMillis() / 1000;
     174
    147175        // Due to a bug in scummvm up to and including 0.3.0, save games could be saved
    148176        // in the V8/V9 format but were tagged with a V7 mark. Ouch. So we just pretend V7 == V8 here
    149177        if (hdr.ver == VER(7))
     
    359387
    360388        _sound->pauseSounds(false);
    361389
     390        _engineStartTime += _system->getMillis() / 1000 - _dialogStartTime;
     391        _dialogStartTime = 0;
     392
    362393        return true;
    363394}
    364395
     
    438469
    439470        delete in;
    440471        return thumb;
     472}
     473
     474bool ScummEngine::loadInfosFromSlot(int slot, InfoStuff *stuff) {
     475        char filename[256];
     476        Common::InSaveFile *in;
     477        SaveGameHeader hdr;
     478        int len;
     479
     480        makeSavegameName(filename, slot, false);
     481        if (!(in = _saveFileMan->openForLoading(filename))) {
     482                return false;
     483        }
     484        len = in->read(&hdr, sizeof(hdr));
     485
     486        if (len != sizeof(hdr) || hdr.type != MKID('SCVM')) {
     487                delete in;
     488                return false;
     489        }
     490
     491        if (hdr.ver > CURRENT_VER)
     492                hdr.ver = TO_LE_32(hdr.ver);
     493        if (hdr.ver < VER(56)) {
     494                delete in;
     495                return false;
     496        }
     497
     498        uint32 type;
     499        in->read(&type, 4);
     500
     501        // Check for the THMB header. Also, work around a bug which caused
     502        // the chunk type (incorrectly) to be written in LE on LE machines.
     503        if (! (type == MKID('THMB') || (hdr.ver < VER(55) && type == MKID('BMHT')))){
     504                delete in;
     505                return false;
     506        }
     507        uint32 size = in->readUint32BE();
     508        in->skip(size - 8);
     509
     510        if (!loadInfos(in, stuff)) {
     511                delete in;
     512                return false;
     513        }
     514       
     515        delete in;     
     516        return true;
     517}
     518
     519bool ScummEngine::removeState(int slot) {
     520        const char* savePath = _saveFileMan->getSavePath();
     521        char filename[256];
     522        makeSavegameName(filename, slot, false);
     523        return Common::File::remove(filename, savePath);
     524}
     525
     526bool ScummEngine::loadInfos(Common::InSaveFile *file, InfoStuff *stuff) {
     527        SaveInfoHeader header;
     528        file->read(&header.type, 4);
     529        if (header.type != MKID('INFO')) {
     530                warning("Couldn't load info section");
     531                return false;
     532        }
     533
     534        header.version = file->readByte();
     535        if (header.version > INFOHEADER_VERSION) {
     536                warning("Infoheader version is too high");
     537                return false;
     538        }
     539
     540        header.size = file->readUint32BE();
     541       
     542        header.date = file->readUint32BE();
     543        header.time = file->readUint16BE();
     544        header.playtime = file->readUint32BE();
     545
     546        stuff->date = header.date;
     547        stuff->time = header.time;
     548        stuff->playtime = header.playtime;
     549
     550        return true;
     551}
     552
     553void ScummEngine::saveInfos(Common::OutSaveFile* file) {
     554        SaveInfoHeader header;
     555        header.type = MKID('INFO');
     556        header.version = INFOHEADER_VERSION;
     557        header.size = sizeof(SaveInfoHeader);
     558
     559        time_t curTime_ = time(0);
     560        tm *curTime = localtime(&curTime_);
     561        header.date = (curTime->tm_mday & 0xFF) << 24 | ((curTime->tm_mon + 1) & 0xFF) << 16 | (curTime->tm_year + 1900) & 0xFFFF;
     562        header.time = (curTime->tm_hour & 0xFF) << 8 | curTime->tm_min & 0xFF;
     563        header.playtime = _system->getMillis() / 1000 - _engineStartTime;
     564
     565        file->write(&header.type, 4);
     566        file->writeByte(header.version);
     567        file->writeUint32BE(header.size);
     568        file->writeUint32BE(header.date);
     569        file->writeUint16BE(header.time);
     570        file->writeUint32BE(header.playtime);
    441571}
    442572
    443573void ScummEngine::saveOrLoad(Serializer *s, uint32 savegameVersion) {
  • scumm/saveload.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/scumm/saveload.h ./scummvm/scumm/saveload.h
    old new  
    4545 * only saves/loads those which are valid for the version of the savegame
    4646 * which is being loaded/saved currently.
    4747 */
    48 #define CURRENT_VER 55
     48#define CURRENT_VER 56
    4949
    5050/**
    5151 * An auxillary macro, used to specify savegame versions. We use this instead
  • scumm/scumm.cpp

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/scumm/scumm.cpp ./scummvm/scumm/scumm.cpp
    old new  
    20862086#pragma mark -
    20872087
    20882088int ScummEngine::go() {
     2089        _engineStartTime = _system->getMillis() / 1000;
     2090
    20892091        // If requested, load a save game instead of running the boot script
    20902092        if (_saveLoadFlag != 2 || !loadState(_saveLoadSlot, _saveTemporaryState)) {
    20912093                int args[16];
     
    25222524#pragma mark -
    25232525
    25242526int ScummEngine::runDialog(Dialog &dialog) {
     2527        _dialogStartTime = _system->getMillis() / 1000;
     2528
    25252529        // Pause sound & video
    25262530        bool old_soundsPaused = _sound->_soundsPaused;
    25272531        _sound->pauseSounds(true);
     
    25372541        // Resume sound & video
    25382542        _sound->pauseSounds(old_soundsPaused);
    25392543        _smushPaused = oldSmushPaused;
     2544
     2545        _engineStartTime += (_system->getMillis() / 1000) - _dialogStartTime;
     2546        _dialogStartTime = 0;
    25402547
    25412548        // Return the result
    25422549        return result;
  • scumm/scumm.h

    diff --exclude=.cvsignore --exclude=.deps --exclude=CVS -Pur ./scummvm.cvs/scumm/scumm.h ./scummvm/scumm/scumm.h
    old new  
    309309        int subIndex;
    310310};
    311311
     312struct InfoStuff {
     313        uint32 date;
     314        uint16 time;
     315        uint32 playtime;
     316};
     317
    312318class ResourceManager {
    313319        friend class ScummDebugger;
    314320        friend class ScummEngine;
     
    582588        void requestSave(int slot, const char *name, bool temporary = false);
    583589        void requestLoad(int slot);
    584590
    585 // thumbnail stuff
     591        bool removeState(int slot);
     592
     593// thumbnail + info stuff
    586594public:
    587595        Graphics::Surface *loadThumbnailFromSlot(int slot);
     596        bool loadInfosFromSlot(int slot, InfoStuff *stuff);
    588597
    589598protected:
    590599        Graphics::Surface *loadThumbnail(Common::InSaveFile *file);
     600        bool loadInfos(Common::InSaveFile *file, InfoStuff *stuff);
    591601        void saveThumbnail(Common::OutSaveFile *file);
     602        void saveInfos(Common::OutSaveFile* file);
     603
     604        int32 _engineStartTime;
     605        int32 _dialogStartTime;
    592606
    593607protected:
    594608        /* Script VM - should be in Script class */