00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #ifndef COMMON_RECORDERFILE_H
00024 #define COMMON_RECORDERFILE_H
00025
00026 #include "common/scummsys.h"
00027 #include "common/events.h"
00028 #include "common/mutex.h"
00029 #include "common/memstream.h"
00030 #include "common/config-manager.h"
00031 #include "common/savefile.h"
00032
00033
00034 #define kMaxBufferedRecords 10000
00035 #define kRecordBuffSize sizeof(RecorderEvent) * kMaxBufferedRecords
00036
00037 namespace Common {
00038
00039 enum RecorderEventType {
00040 kRecorderEventTypeNormal = 0,
00041 kRecorderEventTypeTimer = 1
00042 };
00043
00044 struct RecorderEvent : Event {
00045 RecorderEventType recordedtype;
00046 uint32 time;
00047 };
00048
00049
00050
00051 class PlaybackFile {
00052 typedef HashMap<String, uint32, IgnoreCase_Hash, IgnoreCase_EqualTo> RandomSeedsDictionary;
00053 enum fileMode {
00054 kRead = 0,
00055 kWrite = 1,
00056 kClosed = 2
00057 };
00058 enum PlaybackFileState {
00059 kFileStateCheckFormat,
00060 kFileStateCheckVersion,
00061 kFileStateProcessHash,
00062 kFileStateProcessHeader,
00063 kFileStateProcessRandom,
00064 kFileStateSelectSection,
00065 kFileStateProcessSettings,
00066 kFileStateProcessSave,
00067 kFileStateDone,
00068 kFileStateError
00069 };
00070 enum FileTag {
00071 kFormatIdTag = MKTAG('P','B','C','K'),
00072 kVersionTag = MKTAG('V','E','R','S'),
00073 kHeaderSectionTag = MKTAG('H','E','A','D'),
00074 kHashSectionTag = MKTAG('H','A','S','H'),
00075 kRandomSectionTag = MKTAG('R','A','N','D'),
00076 kEventTag = MKTAG('E','V','N','T'),
00077 kScreenShotTag = MKTAG('B','M','H','T'),
00078 kSettingsSectionTag = MKTAG('S','E','T','T'),
00079 kAuthorTag = MKTAG('H','A','U','T'),
00080 kCommentsTag = MKTAG('H','C','M','T'),
00081 kNameTag = MKTAG('H','N','A','M'),
00082 kHashRecordTag = MKTAG('H','R','C','D'),
00083 kRandomRecordTag = MKTAG('R','R','C','D'),
00084 kSettingsRecordTag = MKTAG('S','R','E','C'),
00085 kSettingsRecordKeyTag = MKTAG('S','K','E','Y'),
00086 kSettingsRecordValueTag = MKTAG('S','V','A','L'),
00087 kSaveTag = MKTAG('S','A','V','E'),
00088 kSaveRecordTag = MKTAG('R','S','A','V'),
00089 kSaveRecordNameTag = MKTAG('S','N','A','M'),
00090 kSaveRecordBufferTag = MKTAG('S','B','U','F'),
00091 kMD5Tag = MKTAG('M','D','5',' ')
00092 };
00093 struct ChunkHeader {
00094 FileTag id;
00095 uint32 len;
00096 };
00097 public:
00098 struct SaveFileBuffer {
00099 byte *buffer;
00100 uint32 size;
00101 };
00102 struct PlaybackFileHeader {
00103 String fileName;
00104 String author;
00105 String name;
00106 String notes;
00107 String description;
00108 StringMap hashRecords;
00109 StringMap settingsRecords;
00110 HashMap<String, SaveFileBuffer> saveFiles;
00111 RandomSeedsDictionary randomSourceRecords;
00112 };
00113 PlaybackFile();
00114 ~PlaybackFile();
00115
00116 bool openWrite(const String &fileName);
00117 bool openRead(const String &fileName);
00118 void close();
00119
00120 RecorderEvent getNextEvent();
00121 void writeEvent(const RecorderEvent &event);
00122
00123 void saveScreenShot(Graphics::Surface &screen, byte md5[16]);
00124 Graphics::Surface *getScreenShot(int number);
00125 int getScreensCount();
00126
00127 bool isEventsBufferEmpty();
00128 PlaybackFileHeader &getHeader() {return _header;}
00129 void updateHeader();
00130 void addSaveFile(const String &fileName, InSaveFile *saveStream);
00131 private:
00132 WriteStream *_recordFile;
00133 WriteStream *_writeStream;
00134 WriteStream *_screenshotsFile;
00135 MemoryReadStream _tmpPlaybackFile;
00136 SeekableReadStream *_readStream;
00137 SeekableMemoryWriteStream _tmpRecordFile;
00138
00139 fileMode _mode;
00140 bool _headerDumped;
00141 int _recordCount;
00142 uint32 _eventsSize;
00143 byte _tmpBuffer[kRecordBuffSize];
00144 PlaybackFileHeader _header;
00145 PlaybackFileState _playbackParseState;
00146
00147 void skipHeader();
00148 bool parseHeader();
00149 bool processChunk(ChunkHeader &nextChunk);
00150 void returnToChunkHeader();
00151
00152 bool readSaveRecord();
00153 void checkRecordedMD5();
00154 bool readChunkHeader(ChunkHeader &nextChunk);
00155 void processRndSeedRecord(ChunkHeader chunk);
00156 bool processSettingsRecord();
00157
00158 bool checkPlaybackFileVersion();
00159
00160 void dumpHeaderToFile();
00161 void writeSaveFilesSection();
00162 void writeGameSettings();
00163 void writeHeaderSection();
00164 void writeGameHash();
00165 void writeRandomRecords();
00166
00167 void dumpRecordsToFile();
00168
00169 String readString(int len);
00170 void readHashMap(ChunkHeader chunk);
00171
00172 bool skipToNextScreenshot();
00173 void readEvent(RecorderEvent& event);
00174 void readEventsToBuffer(uint32 size);
00175 bool grabScreenAndComputeMD5(Graphics::Surface &screen, uint8 md5[16]);
00176 };
00177
00178 }
00179
00180 #endif