1
- // /--------------------------------------------------------------------------------
1
+ // /--------------------------------------------------------------------------------
2
2
// /-- Author ReactiioN
3
3
// /-- Copyright 2016-2020, ReactiioN
4
4
// /-- License MIT
7
7
8
8
#include < valve-bsp-parser/core/valve_structs.hpp>
9
9
#include < shared_mutex>
10
+ #include < LzmaLib.h>
11
+ #include < cstring>
12
+ #include < cassert>
13
+ #include < mutex>
14
+ #include < optional>
10
15
11
16
namespace rn {
12
17
class bsp_parser final
@@ -39,21 +44,34 @@ class bsp_parser final
39
44
std::string& file_path
40
45
);
41
46
47
+
42
48
bool parse_planes (
43
- std::ifstream& file
49
+ std::ifstream& file,
50
+ std::optional<valve::lumpfileheader_t > lumpFileHeader
51
+ );
52
+ bool parse_entities (
53
+ std::ifstream& file,
54
+ std::optional<valve::lumpfileheader_t > lumpFileHeader
44
55
);
45
56
46
57
bool parse_nodes (
47
- std::ifstream& file
58
+ std::ifstream& file,
59
+ std::optional<valve::lumpfileheader_t > lumpFileHeader
48
60
);
49
61
50
62
bool parse_leaffaces (
51
- std::ifstream& file
63
+ std::ifstream& file,
64
+ std::optional<valve::lumpfileheader_t > lumpFileHeader
52
65
);
53
66
54
67
bool parse_leafbrushes (
55
- std::ifstream& file
56
- );
68
+ std::ifstream& file,
69
+ std::optional<valve::lumpfileheader_t > lumpFileHeader
70
+ );
71
+
72
+ // bool parse_entities(
73
+ // std::ifstream& file
74
+ // );
57
75
58
76
bool parse_polygons ();
59
77
@@ -81,26 +99,104 @@ class bsp_parser final
81
99
)const ;
82
100
83
101
template <typename type>
84
- _NODISCARD
102
+ NODISCARD
85
103
bool parse_lump (
86
104
std::ifstream& file,
87
105
const valve::lump_index lump_index,
88
- std::vector<type>& out
106
+ std::vector<type>& out,
107
+ std::optional<valve::lumpfileheader_t > fileLump = std::nullopt
89
108
) const
90
109
{
110
+ using rn::valve::lzma_header_t ;
111
+ using rn::valve::has_valid_lzma_ident;
91
112
const auto index = static_cast <std::underlying_type_t <valve::lump_index>>( lump_index );
92
- if ( index >= _bsp_header.lumps .size () ) {
113
+
114
+
115
+
116
+ if ( index >= bsp_header.lumps .size () ) {
93
117
return false ;
94
118
}
119
+ // TODO: decompress lump here if compressed
120
+ // Default behavior is casting data to underlying types.
121
+ // It doesn't handle compression
122
+
123
+
124
+ // There are two exceptions though: Game lumps (35) (yes, multiple; compressed individually), and PAK Lump (40) (basically a zip file)
125
+
126
+
127
+ const auto & lump = bsp_header.lumps .at ( index );
128
+
129
+ std::size_t lumpOffset,lumpSize;
130
+
131
+ valve::lumpfileheader_t lumpPatch;
132
+ if (fileLump.has_value ()) {
133
+ lumpPatch = fileLump.value ();
134
+ lumpOffset = lumpPatch.file_offset ;
135
+ lumpSize = lumpPatch.file_size ;
136
+ } else {
137
+
138
+ lumpOffset = lump.file_offset ;
139
+ lumpSize = lump.file_size ;
140
+ }
141
+
142
+ auto size = static_cast <std::size_t >( lumpSize ) / sizeof ( type );
143
+ // out.resize( size );
144
+
145
+
146
+ char * tmpData = new char [lumpSize + sizeof (lzma_header_t ) + 1 ]; // lump.file_size doesn't count size of the header
147
+ file.seekg ( lumpOffset );
148
+ // Temporarily make this array. This data may be compressed.
149
+
150
+ memset (tmpData, 0 , lumpSize + sizeof (lzma_header_t ) + 1 );
151
+
152
+ file.read (tmpData, lumpSize);
95
153
96
- const auto & lump = _bsp_header. lumps . at ( index ) ;
97
- const auto size = static_cast <std:: size_t >( lump. file_size ) / sizeof ( type );
154
+ lzma_header_t lzma_header ;
155
+ memcpy (&lzma_header, tmpData, sizeof (lzma_header) );
98
156
99
- out.resize ( size );
100
157
101
- file.seekg ( lump.file_offset );
102
- file.read ( reinterpret_cast <char *>( out.data () ), size * static_cast <std::size_t >( sizeof ( type ) ) );
158
+ if (has_valid_lzma_ident (lzma_header.id ))
159
+ {
160
+ assert (lump_index != valve::lump_index::game_lump || lump_index != valve::lump_index::pak_file); // Those have special rules regarding compression.
103
161
162
+
163
+
164
+ // This section below was BEFORE if check. This resulted on malloc pulling array size from garbage data
165
+ // without checking if data were actually compressed.
166
+
167
+
168
+ char * tmpUncompressedData;
169
+ // bool isCompressed = false;
170
+
171
+
172
+ tmpUncompressedData = new char [lzma_header.actualSize + 1 ];
173
+
174
+
175
+ size_t lzmaSize = lzma_header.lzmaSize ,realSize = lzma_header.actualSize ;
176
+
177
+
178
+ LzmaUncompress (reinterpret_cast <unsigned char *>(tmpUncompressedData),
179
+ &realSize,
180
+ reinterpret_cast <unsigned char *>(tmpData+sizeof (lzma_header_t )), // point to actual data, not the header
181
+ &lzmaSize,
182
+ reinterpret_cast <unsigned char *>(lzma_header.properties .data ()),
183
+ LZMA_PROPS_SIZE);
184
+ out.resize (static_cast <std::size_t >(lzma_header.actualSize ) / sizeof (type));
185
+ out.assign (reinterpret_cast <type*>(tmpUncompressedData),reinterpret_cast <type*>(tmpUncompressedData+realSize));
186
+ delete[] tmpUncompressedData;
187
+
188
+ }
189
+ else
190
+ {
191
+ out.resize (size/sizeof (type));
192
+ out.assign (reinterpret_cast <type*>(tmpData),reinterpret_cast <type*>(tmpData+lumpSize));
193
+ }
194
+
195
+
196
+
197
+
198
+ // file.read( reinterpret_cast<char*>( out.data() ), size * static_cast<std::size_t>( sizeof( type ) ) );
199
+ delete[] tmpData;
104
200
return true ;
105
201
}
106
202
@@ -120,23 +216,31 @@ class bsp_parser final
120
216
const vector3& final ,
121
217
valve::trace_t * out
122
218
);
219
+ void unload_map ();
123
220
221
+
222
+
223
+
224
+ // TODO: Cannot remove leading underscores as some code relies on it.
225
+ public:
226
+ std::string map_name;
227
+ valve::dheader_t bsp_header;
228
+ // entities go here
229
+ std::vector<valve::mvertex_t > vertices;
230
+ std::vector<valve::cplane_t > planes;
231
+ std::vector<valve::dedge_t > edges;
232
+ std::vector<std::int32_t > surf_edges;
233
+ std::vector<valve::dleaf_t > leaves;
234
+ std::vector<valve::snode_t > nodes;
235
+ std::vector<valve::dface_t > surfaces;
236
+ std::vector<valve::texinfo_t > tex_infos;
237
+ std::vector<valve::dbrush_t > brushes;
238
+ std::vector<valve::dbrushside_t > brush_sides;
239
+ std::vector<std::uint16_t > leaf_faces;
240
+ std::vector<std::uint16_t > leaf_brushes;
241
+ std::vector<valve::polygon> polygons;
242
+ std::vector<valve::entity_t > entities;
124
243
private:
125
- std::string _map_name;
126
- valve::dheader_t _bsp_header;
127
- std::vector<valve::mvertex_t > _vertices;
128
- std::vector<valve::cplane_t > _planes;
129
- std::vector<valve::dedge_t > _edges;
130
- std::vector<std::int32_t > _surf_edges;
131
- std::vector<valve::dleaf_t > _leaves;
132
- std::vector<valve::snode_t > _nodes;
133
- std::vector<valve::dface_t > _surfaces;
134
- std::vector<valve::texinfo_t > _tex_infos;
135
- std::vector<valve::dbrush_t > _brushes;
136
- std::vector<valve::dbrushside_t > _brush_sides;
137
- std::vector<std::uint16_t > _leaf_faces;
138
- std::vector<std::uint16_t > _leaf_brushes;
139
- std::vector<valve::polygon> _polygons;
140
244
mutable std::shared_timed_mutex _mutex;
141
245
};
142
246
}
0 commit comments