scummvm/common/recorderfile.h
2021-09-09 19:32:02 +02:00

214 lines
5.6 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef COMMON_RECORDERFILE_H
#define COMMON_RECORDERFILE_H
#include "common/scummsys.h"
#include "common/events.h"
#include "common/mutex.h"
#include "common/memstream.h"
#include "common/config-manager.h"
#include "common/savefile.h"
//capacity of records buffer
#define kMaxBufferedRecords 10000
#define kRecordBuffSize sizeof(RecorderEvent) * kMaxBufferedRecords
namespace Common {
enum RecorderEventType {
kRecorderEventTypeNormal = 0,
kRecorderEventTypeTimer = 1,
kRecorderEventTypeTimeDate = 2,
kRecorderEventTypeScreenUpdate = 3,
};
struct RecorderEvent : Event {
RecorderEventType recordedtype;
union {
uint32 time;
TimeDate timeDate;
};
RecorderEvent() {
recordedtype = kRecorderEventTypeNormal;
time = 0;
timeDate.tm_sec = 0;
timeDate.tm_min = 0;
timeDate.tm_hour = 0;
timeDate.tm_mday = 0;
timeDate.tm_mon = 0;
timeDate.tm_year = 0;
timeDate.tm_wday = 0;
}
RecorderEvent(const Event &e) : Event(e) {
recordedtype = kRecorderEventTypeNormal;
time = 0;
timeDate.tm_sec = 0;
timeDate.tm_min = 0;
timeDate.tm_hour = 0;
timeDate.tm_mday = 0;
timeDate.tm_mon = 0;
timeDate.tm_year = 0;
timeDate.tm_wday = 0;
}
};
class PlaybackFile {
typedef HashMap<String, uint32, IgnoreCase_Hash, IgnoreCase_EqualTo> RandomSeedsDictionary;
enum fileMode {
kRead = 0,
kWrite = 1,
kClosed = 2
};
enum PlaybackFileState {
kFileStateCheckFormat,
kFileStateCheckVersion,
kFileStateProcessHash,
kFileStateProcessHeader,
kFileStateProcessRandom,
kFileStateSelectSection,
kFileStateProcessSettings,
kFileStateProcessSave,
kFileStateDone,
kFileStateError
};
enum FileTag {
kFormatIdTag = MKTAG('P','B','C','K'),
kVersionTag = MKTAG('V','E','R','S'),
kHeaderSectionTag = MKTAG('H','E','A','D'),
kHashSectionTag = MKTAG('H','A','S','H'),
kRandomSectionTag = MKTAG('R','A','N','D'),
kEventTag = MKTAG('E','V','N','T'),
kScreenShotTag = MKTAG('T','H','M','B'),
kSettingsSectionTag = MKTAG('S','E','T','T'),
kAuthorTag = MKTAG('H','A','U','T'),
kCommentsTag = MKTAG('H','C','M','T'),
kNameTag = MKTAG('H','N','A','M'),
kHashRecordTag = MKTAG('H','R','C','D'),
kRandomRecordTag = MKTAG('R','R','C','D'),
kSettingsRecordTag = MKTAG('S','R','E','C'),
kSettingsRecordKeyTag = MKTAG('S','K','E','Y'),
kSettingsRecordValueTag = MKTAG('S','V','A','L'),
kSaveTag = MKTAG('S','A','V','E'),
kSaveRecordTag = MKTAG('R','S','A','V'),
kSaveRecordNameTag = MKTAG('S','N','A','M'),
kSaveRecordBufferTag = MKTAG('S','B','U','F'),
kMD5Tag = MKTAG('M','D','5',' ')
};
struct ChunkHeader {
FileTag id;
uint32 len;
};
public:
struct SaveFileBuffer {
byte *buffer;
uint32 size;
};
struct PlaybackFileHeader {
String fileName;
String author;
String name;
String notes;
String description;
StringMap hashRecords;
StringMap settingsRecords;
HashMap<String, SaveFileBuffer> saveFiles;
RandomSeedsDictionary randomSourceRecords;
};
PlaybackFile();
~PlaybackFile();
bool openWrite(const String &fileName);
bool openRead(const String &fileName);
void close();
bool hasNextEvent() const;
RecorderEvent getNextEvent();
void writeEvent(const RecorderEvent &event);
void saveScreenShot(Graphics::Surface &screen, byte md5[16]);
Graphics::Surface *getScreenShot(int number);
int getScreensCount();
bool isEventsBufferEmpty();
PlaybackFileHeader &getHeader() {return _header;}
void updateHeader();
void addSaveFile(const String &fileName, InSaveFile *saveStream);
uint32 getVersion() const {return _version;}
private:
Array<byte> _tmpBuffer;
WriteStream *_recordFile;
WriteStream *_writeStream;
WriteStream *_screenshotsFile;
MemoryReadStream _tmpPlaybackFile;
SeekableReadStream *_readStream;
SeekableMemoryWriteStream _tmpRecordFile;
fileMode _mode;
bool _headerDumped;
int _recordCount;
uint32 _eventsSize;
PlaybackFileHeader _header;
PlaybackFileState _playbackParseState;
uint32 _version;
void skipHeader();
bool parseHeader();
bool processChunk(ChunkHeader &nextChunk);
void returnToChunkHeader();
bool readSaveRecord();
void checkRecordedMD5();
bool readChunkHeader(ChunkHeader &nextChunk);
void processRndSeedRecord(ChunkHeader chunk);
bool processSettingsRecord();
bool checkPlaybackFileVersion();
void dumpHeaderToFile();
void writeSaveFilesSection();
void writeGameSettings();
void writeHeaderSection();
void writeGameHash();
void writeRandomRecords();
void dumpRecordsToFile();
String readString(int len);
void readHashMap(ChunkHeader chunk);
bool skipToNextScreenshot();
void readEvent(RecorderEvent& event);
void readEventsToBuffer(uint32 size);
bool grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]);
};
} // End of namespace Common
#endif