1 /* ScummVM - Graphic Adventure Engine 2 * 3 * ScummVM is the legal property of its developers, whose names 4 * are too numerous to list here. Please refer to the COPYRIGHT 5 * file distributed with this source distribution. 6 * 7 * This program is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU General Public License 9 * as published by the Free Software Foundation; either version 2 10 * of the License, or (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 */ 22 23 #ifndef GLK_QUETZAL 24 #define GLK_QUETZAL 25 26 #include "common/array.h" 27 #include "common/endian.h" 28 #include "common/memstream.h" 29 #include "common/stream.h" 30 #include "engines/savestate.h" 31 #include "glk/blorb.h" 32 #include "glk/glk_types.h" 33 34 namespace Glk { 35 36 enum QueztalTag { 37 ID_IFSF = MKTAG('I', 'F', 'S', 'F'), 38 ID_IFZS = MKTAG('I', 'F', 'Z', 'S'), 39 ID_IFhd = MKTAG('I', 'F', 'h', 'd'), 40 ID_UMem = MKTAG('U', 'M', 'e', 'm'), 41 ID_CMem = MKTAG('C', 'M', 'e', 'm'), 42 ID_Stks = MKTAG('S', 't', 'k', 's'), 43 ID_SCVM = MKTAG('S', 'C', 'V', 'M') 44 }; 45 46 class QuetzalBase { 47 public: 48 static uint32 getInterpreterTag(InterpreterType interpType); 49 }; 50 51 /** 52 * Quetzal save file reader 53 */ 54 class QuetzalReader : public QuetzalBase { 55 struct Chunk { 56 uint32 _id; 57 size_t _offset, _size; 58 }; 59 public: 60 /** 61 * Iterator for the chunks list 62 */ 63 struct Iterator { 64 private: 65 Common::SeekableReadStream *_stream; 66 Common::Array<Chunk> &_chunks; 67 int _index; 68 public: 69 /** 70 * Constructor 71 */ IteratorIterator72 Iterator(Common::SeekableReadStream *stream, Common::Array<Chunk> &chunks, int index) : 73 _stream(stream), _chunks(chunks), _index(index) {} 74 75 /** 76 * Deference 77 */ 78 Chunk &operator*() const { return _chunks[_index]; } 79 80 /** 81 * Incrementer 82 */ 83 Iterator &operator++() { 84 ++_index; 85 return *this; 86 } 87 88 /** 89 * Decrementer 90 */ 91 Iterator &operator--() { 92 --_index; 93 return *this; 94 } 95 96 /** 97 * Equality test 98 */ 99 bool operator==(const Iterator &rhs) { return _index == rhs._index; } 100 101 /** 102 * Inequality test 103 */ 104 bool operator!=(const Iterator &rhs) { return _index != rhs._index; } 105 106 /** 107 * Get a read stream for the contents of a chunk 108 */ getStreamIterator109 Common::SeekableReadStream *getStream() { 110 _stream->seek(_chunks[_index]._offset); 111 return (_chunks[_index]._size == 0) ? 112 new Common::MemoryReadStream((byte *)malloc(0), 0, DisposeAfterUse::YES) : 113 _stream->readStream(_chunks[_index]._size); 114 } 115 }; 116 private: 117 Common::SeekableReadStream *_stream; 118 Common::Array<Chunk> _chunks; 119 public: 120 /** 121 * Constructor 122 */ QuetzalReader()123 QuetzalReader() : _stream(nullptr) {} 124 125 /** 126 * Clear 127 */ 128 void clear(); 129 130 /** 131 * Opens a Quetzal file for access 132 */ 133 bool open(Common::SeekableReadStream *stream, uint32 formType = 0); 134 135 /** 136 * Return an iterator for the beginning of the chunks list 137 */ begin()138 Iterator begin() { return Iterator(_stream, _chunks, 0); } 139 140 /** 141 * Return an iterator for the beginning of the chunks list 142 */ end()143 Iterator end() { return Iterator(_stream, _chunks, _chunks.size()); } 144 145 /** 146 * Loads a Quetzal save and extracts it's description from an ANNO chunk 147 */ 148 static bool getSavegameDescription(Common::SeekableReadStream *rs, Common::String &saveName); 149 150 /** 151 * Loads a Quetzal save and extract's it's description and meta info 152 */ 153 static bool getSavegameMetaInfo(Common::SeekableReadStream *rs, SaveStateDescriptor &ssd); 154 155 /** 156 * Support method for reading a string from a stream 157 */ 158 static Common::String readString(Common::ReadStream *src); 159 }; 160 161 /** 162 * Quetzal save file writer 163 */ 164 class QuetzalWriter : public QuetzalBase { 165 /** 166 * Chunk entry 167 */ 168 struct Chunk { 169 uint32 _id; 170 Common::MemoryWriteStreamDynamic _stream; 171 172 /** 173 * Constructor 174 */ ChunkChunk175 Chunk() : _id(0), _stream(DisposeAfterUse::YES) {} 176 177 /** 178 * Constructor 179 */ ChunkChunk180 Chunk(uint32 id) : _id(id), _stream(DisposeAfterUse::YES) {} 181 }; 182 private: 183 Common::Array<Chunk> _chunks; 184 185 /** 186 * Add chunks common to all Glk savegames 187 */ 188 void addCommonChunks(const Common::String &saveName); 189 public: 190 /** 191 * Clear 192 */ clear()193 void clear() { _chunks.clear(); } 194 195 /** 196 * Add a chunk 197 */ 198 Common::WriteStream &add(uint32 chunkId); 199 200 /** 201 * Save the added chunks to file 202 */ 203 void save(Common::WriteStream *out, const Common::String &saveName, uint32 formType = ID_IFSF); 204 }; 205 206 } // End of namespace Glk 207 208 #endif 209