1 /*
2 BStone: A Source port of
3 Blake Stone: Aliens of Gold and Blake Stone: Planet Strike
4 
5 Copyright (c) 1992-2013 Apogee Entertainment, LLC
6 Copyright (c) 2013-2015 Boris I. Bendovsky (bibendovsky@hotmail.com)
7 
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
12 
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17 
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the
20 Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
22 */
23 
24 
25 #include "id_pm.h"
26 #include "id_heads.h"
27 
28 
29 // File specific variables
30 std::string PageFileName = "VSWAP.";
31 
32 int ChunksInFile = 0;
33 int PMSpriteStart = 0;
34 int PMSoundStart = 0;
35 
36 
37 namespace {
38 
39 
40 using RawData = std::vector<uint8_t>;
41 
42 bstone::FileStream PageFile;
43 RawData raw_data;
44 uint32_t* chunks_offsets = nullptr;
45 
46 
47 } // namespace
48 
49 
open_page_file(const std::string & file_name)50 static void open_page_file(
51     const std::string& file_name)
52 {
53     PageFile.open(file_name);
54 
55     if (!PageFile.is_open()) {
56         ::Quit("Failed to open page file \"{}\".", file_name);
57     }
58 
59     const auto file_length = PageFile.get_size();
60 
61     if (file_length > 4 * 1024 * 1024) {
62         ::Quit("Page file is too large.");
63     }
64 
65     const auto file_length_32 = static_cast<int32_t>(file_length);
66 
67     raw_data.resize(file_length_32 + PMPageSize);
68 
69     if (PageFile.read(raw_data.data(), file_length_32) != file_length_32)
70     {
71         ::Quit("Page file read error.");
72     }
73 
74     bstone::MemoryBinaryReader reader(raw_data.data(), file_length);
75 
76     ChunksInFile = bstone::Endian::le(reader.read_u16());
77     PMSpriteStart = bstone::Endian::le(reader.read_u16());
78     PMSoundStart = bstone::Endian::le(reader.read_u16());
79 
80     chunks_offsets = reinterpret_cast<uint32_t*>(&raw_data[6]);
81     bstone::Endian::lei(chunks_offsets, ChunksInFile + 1);
82 }
83 
PM_Startup()84 void PM_Startup()
85 {
86     ::PM_Shutdown();
87     ::open_page_file(::data_dir + PageFileName);
88 }
89 
PM_Shutdown()90 void PM_Shutdown()
91 {
92     PageFile.close();
93 
94     ChunksInFile = 0;
95     PMSpriteStart = 0;
96     PMSoundStart = 0;
97 
98     RawData{}.swap(raw_data);
99 
100     chunks_offsets = nullptr;
101 }
102 
PM_GetPage(int page_number)103 void* PM_GetPage(
104     int page_number)
105 {
106     if (page_number >= ChunksInFile) {
107         ::Quit("Invalid page request.");
108     }
109 
110     uint32_t offset = chunks_offsets[page_number];
111 
112     if (offset == 0) {
113         ::Quit("Tried to load a sparse page.");
114     }
115 
116     return &raw_data[offset];
117 }
118 
PM_GetSoundPage(int page_number)119 void* PM_GetSoundPage(
120     int page_number)
121 {
122     return PM_GetPage(PMSoundStart + page_number);
123 }
124 
PM_GetSpritePage(int page_number)125 void* PM_GetSpritePage(
126     int page_number)
127 {
128     return PM_GetPage(PMSpriteStart + page_number);
129 }
130