/* 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. * */ #include "glk/magnetic/magnetic.h" namespace Glk { namespace Magnetic { static const char *no_hints = "[Hints are not available.]\n"; static const char *not_supported = "[This function is not supported.]\n"; int Magnetic::ms_init(bool restarting) { byte header[42]; uint32 i, j, dict_size, string2_size, code_size, dec; ms_stop(); if (restarting) { if (!restart) return 0; else { memcpy(code, restart, undo_size); undo_stat[0] = undo_stat[1] = 0; ms_showpic(0, 0); } } else { undo_stat[0] = undo_stat[1] = 0; if (_gameFile.read(header, 42) != 42 || READ_BE_UINT32(header) != MKTAG('M', 'a', 'S', 'c') || READ_LE_UINT32(header + 8) != 42) return 0; ms_freemem(); version = header[13]; code_size = READ_LE_UINT32(header + 14); string_size = READ_LE_UINT32(header + 18); string2_size = READ_LE_UINT32(header + 22); dict_size = READ_LE_UINT32(header + 26); undo_size = READ_LE_UINT32(header + 34); undo_pc = READ_LE_UINT32(header + 38); if ((version < 4) && (code_size < 65536)) mem_size = 65536; else mem_size = code_size; sd = (byte)((dict_size != 0L) ? 1 : 0); // if (sd) => separate dict if (!(code = new byte[mem_size]) || !(string2 = new byte[string2_size]) || !(restart = new byte[undo_size]) || (sd && !(dict = new byte[dict_size]))) { ms_freemem(); return 0; } if (string_size > MAX_STRING_SIZE) { if (!(string = new byte[MAX_STRING_SIZE]) || !(string3 = new byte[string_size - MAX_STRING_SIZE])) { ms_freemem(); return 0; } } else { if (!(string = new byte[string_size])) { ms_freemem(); return 0; } } if (!(undo[0] = new byte[undo_size]) || !(undo[1] = new byte[undo_size])) { ms_freemem(); return 0; } if (_gameFile.read(code, code_size) != code_size) { ms_freemem(); return 0; } memcpy(restart, code, undo_size); // fast restarts if (string_size > MAX_STRING_SIZE) { if (_gameFile.read(string, MAX_STRING_SIZE) != MAX_STRING_SIZE) { ms_freemem(); return 0; } if (_gameFile.read(string3, string_size - MAX_STRING_SIZE) != (string_size - MAX_STRING_SIZE)) { ms_freemem(); return 0; } } else { if (_gameFile.read(string, string_size) != string_size) { ms_freemem(); return 0; } } if (_gameFile.read(string2, string2_size) != string2_size) { ms_freemem(); return 0; } if (sd && _gameFile.read(dict, dict_size) != dict_size) { ms_freemem(); return 0; } dec = READ_LE_UINT32(header + 30); if (dec >= string_size) { decode_table = string2 + dec - string_size; } else { if (dec >= MAX_STRING_SIZE) decode_table = string3 + dec - MAX_STRING_SIZE; else decode_table = string + dec; } } for (i = 0; i < 8; i++) dreg[i] = areg[i] = 0; write_reg(8 + 7, 2, 0xfffe); // Stack-pointer, -2 due to MS-DOS segments pc = 0; zflag = nflag = cflag = vflag = 0; i_count = 0; running = 1; if (restarting) return (byte)(gfx_buf ? 2 : 1); // Restarted if (version == 4) { // Try loading a hint file if (_hintFile.isOpen()) { _hintFile.seek(0); if (_hintFile.readUint32BE() == MKTAG('M', 'a', 'H', 't')) { uint16 blkcnt, elcnt, ntype, elsize, conidx; // Allocate memory for hints hints = new ms_hint[MAX_HINTS]; hint_contents = new byte[MAX_HCONTENTS]; if ((hints != 0) && (hint_contents != 0)) { // Read number of blocks blkcnt = _hintFile.readUint16LE(); conidx = 0; for (i = 0; i < blkcnt; i++) { // Read number of elements elcnt = _hintFile.readUint16LE(); hints[i].elcount = elcnt; // Read node type ntype = _hintFile.readUint16LE(); hints[i].nodetype = ntype; hints[i].content = hint_contents + conidx; for (j = 0; j < elcnt; j++) { elsize = _hintFile.readUint16LE(); if (_hintFile.read(hint_contents + conidx, elsize) != elsize || _hintFile.eos()) return 0; hint_contents[conidx + elsize - 1] = '\0'; conidx += elsize; } // Do we need a jump table? if (ntype == 1) { for (j = 0; j < elcnt; j++) { hints[i].links[j] = _hintFile.readUint16LE(); } } // Read the parent block hints[i].parent = _hintFile.readUint16LE(); } } else { delete[] hints; delete[] hint_contents; hints = nullptr; hint_contents = nullptr; } } } // Try loading a music file if (_sndFile.isOpen() && _sndFile.size() >= 8) { _sndFile.seek(0); if (_sndFile.readUint32BE() != MKTAG('M', 'a', 'S', 'd')) return 0; init_snd(_sndFile.readUint32LE()); } } if (!_gfxFile.isOpen() || _gfxFile.size() < 8) return 1; _gfxFile.seek(0); uint tag = _gfxFile.readUint32BE(); if (version < 4 && tag == MKTAG('M', 'a', 'P', 'i')) return init_gfx1(_gfxFile.readUint32LE() - 8); else if (version == 4 && tag == MKTAG('M', 'a', 'P', '2')) return init_gfx2(_gfxFile.readUint16LE()); return 1; } void Magnetic::ms_freemem() { delete[] code; delete[] string; delete[] string2; delete[] string3; delete[] dict; delete[] undo[0]; delete[] undo[1]; delete[] restart; code = string = string2 = string3 = dict = nullptr; undo[0] = undo[1] = restart = nullptr; delete[] gfx_data; delete[] gfx_buf; delete[] gfx2_hdr; delete[] gfx2_buf; gfx_data = gfx_buf = gfx2_hdr = gfx2_buf = 0; gfx_fp.close(); gfx2_name.clear(); gfx_ver = 0; gfxtable = table_dist = 0; pos_table_size = 0; command_index = 0; anim_repeat = 0; pos_table_index = -1; pos_table_max = -1; lastchar = 0; delete[] hints; delete[] hint_contents; hints = nullptr; hint_contents = nullptr; delete[] snd_hdr; delete[] snd_buf; snd_hdr = nullptr; snd_hsize = 0; snd_buf = nullptr; } } // End of namespace Magnetic } // End of namespace Glk