MDL/HL1: bounds-checked buffers and safer parsing (#6445)

This commit is contained in:
tyler92
2026-01-19 22:25:09 +02:00
committed by GitHub
parent d1e6bcff6b
commit 129c1333e6
5 changed files with 298 additions and 88 deletions

View File

@@ -0,0 +1,182 @@
/*
---------------------------------------------------------------------------
Open Asset Import Library (assimp)
---------------------------------------------------------------------------
Copyright (c) 2006-2026, assimp team
All rights reserved.
Redistribution and use of this software in source and binary forms,
with or without modification, are permitted provided that the following
conditions are met:
* Redistributions of source code must retain the above
copyright notice, this list of conditions and the
following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the
following disclaimer in the documentation and/or other
materials provided with the distribution.
* Neither the name of the assimp team, nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
---------------------------------------------------------------------------
*/
/** @file HL1DataBuffer.h
* @brief Declaration of the Half-Life 1 data buffer.
*/
#ifndef AI_HL1DATABUFFER_INCLUDED
#define AI_HL1DATABUFFER_INCLUDED
#include <assimp/Exceptional.h>
#include <assimp/defs.h>
#include <cstddef>
#include <memory>
namespace Assimp {
namespace MDL {
namespace HalfLife {
/**
* \brief Lightweight byte buffer wrapper for HL1 binary parsing.
*
* Acts as either:
* - a non-owning view into external memory, or
* - an owning buffer backed by a unique_ptr.
*
* Copy is disabled to avoid accidental double-ownership; move is supported.
*/
class HL1DataBuffer {
public:
/** \brief Construct an empty buffer (null view). */
HL1DataBuffer() AI_NO_EXCEPT : data_(nullptr),
length_(0),
owner_(nullptr) {}
/** \brief Non-copyable (buffer may own memory). */
HL1DataBuffer(const HL1DataBuffer &) = delete;
/** \brief Non-copyable (buffer may own memory). */
HL1DataBuffer &operator=(const HL1DataBuffer &) = delete;
/** \brief Move-construct, transferring ownership/view state. */
HL1DataBuffer(HL1DataBuffer &&other) AI_NO_EXCEPT : data_(other.data_),
length_(other.length_),
owner_(std::move(other.owner_)) {
other.data_ = nullptr;
other.length_ = 0;
other.owner_ = nullptr;
}
/** \brief Move-assign, transferring ownership/view state. */
HL1DataBuffer &operator=(HL1DataBuffer &&other) AI_NO_EXCEPT {
if (this != &other) {
data_ = other.data_;
length_ = other.length_;
owner_ = std::move(other.owner_);
other.data_ = nullptr;
other.length_ = 0;
other.owner_ = nullptr;
}
return *this;
}
/**
* \brief Create a non-owning view into external bytes.
*
* \param[in] data Pointer to raw bytes (must outlive the view).
* \param[in] length Size in bytes.
*/
static HL1DataBuffer view(const unsigned char *data, size_t length) {
HL1DataBuffer b;
b.data_ = data;
b.length_ = length;
b.owner_ = nullptr;
return b;
}
/**
* \brief Create a non-owning view of another buffer.
*
* \param[in] other Source buffer.
*/
static HL1DataBuffer view(const HL1DataBuffer &other) {
HL1DataBuffer b;
b.data_ = other.data_;
b.length_ = other.length_;
b.owner_ = nullptr;
return b;
}
/**
* \brief Create an owning buffer by taking ownership of allocated storage.
*
* \param[in] buffer Unique buffer storage.
* \param[in] length Size in bytes.
*/
static HL1DataBuffer owning(std::unique_ptr<unsigned char[]> buffer, size_t length) {
HL1DataBuffer b;
b.data_ = buffer.get();
b.length_ = length;
b.owner_ = std::move(buffer);
return b;
}
/**
* \brief Return a typed pointer into the buffer with bounds checks.
*
* \param[in] offset Byte offset from the start of the buffer.
* \param[in] elements Number of elements to access.
* \return Pointer to the requested typed data inside the buffer.
* \throws DeadlyImportError if the request is out of range.
*/
template <typename DataType>
const DataType *get_data(int offset, int elements) const {
if (offset < 0 || elements < 0) {
throw DeadlyImportError("MDL file contains invalid data");
}
const size_t uoffset = static_cast<size_t>(offset);
const size_t uelements = static_cast<size_t>(elements);
if (uoffset > length_ || uelements > (length_ - uoffset) / sizeof(DataType)) {
throw DeadlyImportError("MDL file contains invalid data");
}
return reinterpret_cast<const DataType *>(data_ + uoffset);
}
private:
/** Raw byte pointer (points to owner_.get() when owning, otherwise external). */
const unsigned char *data_;
/** Buffer length in bytes. */
size_t length_;
/** Owning storage (null for views). */
std::unique_ptr<unsigned char[]> owner_;
};
} // namespace HalfLife
} // namespace MDL
} // namespace Assimp
#endif // AI_HL1DATABUFFER_INCLUDED

View File

@@ -78,18 +78,19 @@ HL1MDLLoader::HL1MDLLoader(
aiScene *scene,
IOSystem *io,
const unsigned char *buffer,
size_t buffer_length,
const std::string &file_path,
const HL1ImportSettings &import_settings) :
scene_(scene),
io_(io),
buffer_(buffer),
buffer_(HL1DataBuffer::view(buffer, buffer_length)),
file_path_(file_path),
import_settings_(import_settings),
header_(nullptr),
texture_header_(nullptr),
anim_headers_(nullptr),
texture_buffer_(nullptr),
anim_buffers_(nullptr),
anim_headers_(),
texture_buffer_(),
anim_buffers_(),
num_sequence_groups_(0),
rootnode_children_(),
unique_name_generator_(),
@@ -108,28 +109,6 @@ HL1MDLLoader::~HL1MDLLoader() {
// ------------------------------------------------------------------------------------------------
void HL1MDLLoader::release_resources() {
if (buffer_ != texture_buffer_) {
delete[] texture_buffer_;
texture_buffer_ = nullptr;
}
if (num_sequence_groups_ && anim_buffers_) {
for (int i = 1; i < num_sequence_groups_; ++i) {
if (anim_buffers_[i]) {
delete[] anim_buffers_[i];
anim_buffers_[i] = nullptr;
}
}
delete[] anim_buffers_;
anim_buffers_ = nullptr;
}
if (anim_headers_) {
delete[] anim_headers_;
anim_headers_ = nullptr;
}
// Root has some children nodes. so let's proceed them
if (!rootnode_children_.empty()) {
// Here, it means that the nodes were not added to the
@@ -147,7 +126,7 @@ void HL1MDLLoader::release_resources() {
// ------------------------------------------------------------------------------------------------
void HL1MDLLoader::load_file() {
try {
header_ = (const Header_HL1 *)buffer_;
header_ = get_buffer_data<Header_HL1>(0, 1);
validate_header(header_, false);
// Create the root scene node.
@@ -286,10 +265,10 @@ void HL1MDLLoader::load_texture_file() {
load_file_into_buffer<Header_HL1>(texture_file_path, texture_buffer_);
} else {
// Model has no external texture file. This means the texture is stored inside the main MDL file.
texture_buffer_ = const_cast<unsigned char *>(buffer_);
texture_buffer_ = HL1DataBuffer::view(buffer_);
}
texture_header_ = (const Header_HL1 *)texture_buffer_;
texture_header_ = get_texture_buffer_data<Header_HL1>(0, 1);
// Validate texture header.
validate_header(texture_header_, true);
@@ -318,12 +297,8 @@ void HL1MDLLoader::load_sequence_groups_files() {
num_sequence_groups_ = header_->numseqgroups;
anim_buffers_ = new unsigned char *[num_sequence_groups_];
anim_headers_ = new SequenceHeader_HL1 *[num_sequence_groups_];
for (int i = 0; i < num_sequence_groups_; ++i) {
anim_buffers_[i] = nullptr;
anim_headers_[i] = nullptr;
}
anim_buffers_.resize(num_sequence_groups_);
anim_headers_.resize(num_sequence_groups_, nullptr);
std::string file_path_without_extension =
DefaultIOSystem::absolutePath(file_path_) +
@@ -340,14 +315,14 @@ void HL1MDLLoader::load_sequence_groups_files() {
load_file_into_buffer<SequenceHeader_HL1>(sequence_file_path, anim_buffers_[i]);
anim_headers_[i] = (SequenceHeader_HL1 *)anim_buffers_[i];
anim_headers_[i] = get_anim_buffer_data<SequenceHeader_HL1>(i, 0, 1);
}
}
// ------------------------------------------------------------------------------------------------
// Read an MDL texture.
void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture,
uint8_t *data, uint8_t *pal, aiTexture *pResult,
const uint8_t *data, const uint8_t *pal, aiTexture *pResult,
aiColor3D &last_palette_color) {
pResult->mFilename = ptexture->name;
pResult->mWidth = static_cast<unsigned int>(ptexture->width);
@@ -381,24 +356,24 @@ void HL1MDLLoader::read_texture(const Texture_HL1 *ptexture,
// ------------------------------------------------------------------------------------------------
void HL1MDLLoader::read_textures() {
const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex);
unsigned char *pin = texture_buffer_;
scene_->mTextures = new aiTexture *[texture_header_->numtextures];
scene_->mMaterials = new aiMaterial *[texture_header_->numtextures];
scene_->mNumTextures = scene_->mNumMaterials = texture_header_->numtextures;
scene_->mTextures = new aiTexture *[scene_->mNumTextures];
scene_->mMaterials = new aiMaterial *[scene_->mNumMaterials];
const Texture_HL1 *ptexture = get_texture_buffer_data<Texture_HL1>(texture_header_->textureindex, texture_header_->numtextures);
for (int i = 0; i < texture_header_->numtextures; ++i) {
scene_->mTextures[i] = new aiTexture();
++scene_->mNumTextures;
const uint8_t *data = get_texture_buffer_data<uint8_t>(ptexture[i].index, ptexture[i].width * ptexture[i].height);
const uint8_t *pal = get_texture_buffer_data<uint8_t>(ptexture[i].index + ptexture[i].width * ptexture[i].height, 256 * 3);
aiColor3D last_palette_color;
read_texture(&ptexture[i],
pin + ptexture[i].index,
pin + ptexture[i].width * ptexture[i].height + ptexture[i].index,
scene_->mTextures[i],
last_palette_color);
read_texture(&ptexture[i], data, pal, scene_->mTextures[i], last_palette_color);
aiMaterial *scene_material = scene_->mMaterials[i] = new aiMaterial();
aiMaterial *scene_material = new aiMaterial();
scene_->mMaterials[i] = scene_material;
++scene_->mNumMaterials;
const aiTextureType texture_type = aiTextureType_DIFFUSE;
aiString texture_name(ptexture[i].name);
@@ -435,10 +410,14 @@ void HL1MDLLoader::read_skins() {
}
// Pointer to base texture index.
short *default_skin_ptr = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex);
const short *default_skin_ptr = get_texture_buffer_data<short>(
texture_header_->skinindex,
texture_header_->numskinref);
// Start at first replacement skin.
short *replacement_skin_ptr = default_skin_ptr + texture_header_->numskinref;
const short *replacement_skin_ptr = get_texture_buffer_data<short>(
texture_header_->skinindex + texture_header_->numskinref * sizeof(short),
(texture_header_->numskinfamilies - 1) * texture_header_->numskinref);
for (int i = 1; i < texture_header_->numskinfamilies; ++i, replacement_skin_ptr += texture_header_->numskinref) {
for (int j = 0; j < texture_header_->numskinref; ++j) {
@@ -457,7 +436,7 @@ void HL1MDLLoader::read_bones() {
return;
}
const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex);
const Bone_HL1 *pbone = get_buffer_data<Bone_HL1>(header_->boneindex, header_->numbones);
std::vector<std::string> unique_bones_names(header_->numbones);
for (int i = 0; i < header_->numbones; ++i) {
@@ -589,12 +568,12 @@ void HL1MDLLoader::read_meshes() {
int total_triangles = 0;
total_models_ = 0;
const Bodypart_HL1 *pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
const Bodypart_HL1 *pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
const Model_HL1 *pmodel = nullptr;
const Mesh_HL1 *pmesh = nullptr;
const Texture_HL1 *ptexture = (const Texture_HL1 *)((uint8_t *)texture_header_ + texture_header_->textureindex);
short *pskinref = (short *)((uint8_t *)texture_header_ + texture_header_->skinindex);
const Texture_HL1 *ptexture = get_texture_buffer_data<Texture_HL1>(texture_header_->textureindex, texture_header_->numtextures);
const short *pskinref = get_texture_buffer_data<short>(texture_header_->skinindex, texture_header_->numskinref);
scene_->mNumMeshes = 0;
@@ -606,7 +585,7 @@ void HL1MDLLoader::read_meshes() {
for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
unique_bodyparts_names[i] = pbodypart->name;
pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel) {
scene_->mNumMeshes += pmodel->nummesh;
total_verts += pmodel->numverts;
@@ -633,7 +612,7 @@ void HL1MDLLoader::read_meshes() {
unique_name_generator_.make_unique(unique_bodyparts_names);
// Now do the same for each model.
pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
// Prepare template name for bodypart models.
std::vector<std::string> unique_models_names;
@@ -642,7 +621,7 @@ void HL1MDLLoader::read_meshes() {
unsigned int model_index = 0;
for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart) {
pmodel = (Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
for (int j = 0; j < pbodypart->nummodels; ++j, ++pmodel, ++model_index)
unique_models_names[model_index] = pmodel->name;
}
@@ -654,7 +633,7 @@ void HL1MDLLoader::read_meshes() {
scene_->mMeshes = new aiMesh *[scene_->mNumMeshes];
pbodypart = (const Bodypart_HL1 *)((uint8_t *)header_ + header_->bodypartindex);
pbodypart = get_buffer_data<Bodypart_HL1>(header_->bodypartindex, header_->numbodyparts);
/* Create a node that will represent the mesh hierarchy.
@@ -738,7 +717,7 @@ void HL1MDLLoader::read_meshes() {
model_index = 0;
for (int i = 0; i < header_->numbodyparts; ++i, ++pbodypart, ++bodyparts_node_ptr) {
pmodel = (const Model_HL1 *)((uint8_t *)header_ + pbodypart->modelindex);
pmodel = get_buffer_data<Model_HL1>(pbodypart->modelindex, pbodypart->nummodels);
// Create bodypart node for the mesh tree hierarchy.
aiNode *bodypart_node = (*bodyparts_node_ptr) = new aiNode(unique_bodyparts_names[i]);
@@ -753,12 +732,12 @@ void HL1MDLLoader::read_meshes() {
for (int j = 0; j < pbodypart->nummodels;
++j, ++pmodel, ++bodypart_models_ptr, ++model_index) {
pmesh = (const Mesh_HL1 *)((uint8_t *)header_ + pmodel->meshindex);
pmesh = get_buffer_data<Mesh_HL1>(pmodel->meshindex, pmodel->nummesh);
uint8_t *pvertbone = ((uint8_t *)header_ + pmodel->vertinfoindex);
uint8_t *pnormbone = ((uint8_t *)header_ + pmodel->norminfoindex);
vec3_t *pstudioverts = (vec3_t *)((uint8_t *)header_ + pmodel->vertindex);
vec3_t *pstudionorms = (vec3_t *)((uint8_t *)header_ + pmodel->normindex);
const uint8_t *pvertbone = get_buffer_data<uint8_t>(pmodel->vertinfoindex, pmodel->numverts);
const uint8_t *pnormbone = get_buffer_data<uint8_t>(pmodel->norminfoindex, pmodel->numnorms);
const vec3_t *pstudioverts = get_buffer_data<vec3_t>(pmodel->vertindex, pmodel->numverts);
const vec3_t *pstudionorms = get_buffer_data<vec3_t>(pmodel->normindex, pmodel->numnorms);
// Each vertex and normal is in local space, so transform
// each of them to bring them in bind pose.
@@ -964,7 +943,7 @@ void HL1MDLLoader::read_animations() {
return;
}
const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
const SequenceDesc_HL1 *pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
const SequenceGroup_HL1 *pseqgroup = nullptr;
const AnimValueOffset_HL1 *panim = nullptr;
const AnimValue_HL1 *panimvalue = nullptr;
@@ -990,22 +969,22 @@ void HL1MDLLoader::read_animations() {
// Get the number of available blend controllers for global info.
get_num_blend_controllers(highest_num_blend_animations, num_blend_controllers_);
pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
aiAnimation **scene_animations_ptr = scene_->mAnimations = new aiAnimation *[scene_->mNumAnimations];
for (int sequence = 0; sequence < header_->numseq; ++sequence, ++pseqdesc) {
pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex) + pseqdesc->seqgroup;
pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex + pseqdesc->seqgroup * sizeof(SequenceGroup_HL1), 1);
if (pseqdesc->seqgroup == 0) {
panim = (const AnimValueOffset_HL1 *)((uint8_t *)header_ + pseqgroup->unused2 + pseqdesc->animindex);
panim = get_buffer_data<AnimValueOffset_HL1>(pseqgroup->unused2 + pseqdesc->animindex, pseqdesc->numblends * header_->numbones);
} else {
panim = (const AnimValueOffset_HL1 *)((uint8_t *)anim_headers_[pseqdesc->seqgroup] + pseqdesc->animindex);
panim = get_anim_buffer_data<AnimValueOffset_HL1>(pseqdesc->seqgroup, pseqdesc->animindex, pseqdesc->numblends * header_->numbones);
}
for (int blend = 0; blend < pseqdesc->numblends; ++blend, ++scene_animations_ptr) {
const Bone_HL1 *pbone = (const Bone_HL1 *)((uint8_t *)header_ + header_->boneindex);
const Bone_HL1 *pbone = get_buffer_data<Bone_HL1>(header_->boneindex, header_->numbones);
aiAnimation *scene_animation = (*scene_animations_ptr) = new aiAnimation();
@@ -1074,7 +1053,7 @@ void HL1MDLLoader::read_sequence_groups_info() {
sequence_groups_node->mNumChildren = static_cast<unsigned int>(header_->numseqgroups);
sequence_groups_node->mChildren = new aiNode *[sequence_groups_node->mNumChildren];
const SequenceGroup_HL1 *pseqgroup = (const SequenceGroup_HL1 *)((uint8_t *)header_ + header_->seqgroupindex);
const SequenceGroup_HL1 *pseqgroup = get_buffer_data<SequenceGroup_HL1>(header_->seqgroupindex, header_->numseqgroups);
unique_sequence_groups_names_.resize(header_->numseqgroups);
for (int i = 0; i < header_->numseqgroups; ++i) {
@@ -1106,7 +1085,7 @@ void HL1MDLLoader::read_sequence_infos() {
return;
}
const SequenceDesc_HL1 *pseqdesc = (const SequenceDesc_HL1 *)((uint8_t *)header_ + header_->seqindex);
const SequenceDesc_HL1 *pseqdesc = get_buffer_data<SequenceDesc_HL1>(header_->seqindex, header_->numseq);
aiNode *sequence_infos_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_INFOS);
rootnode_children_.push_back(sequence_infos_node);
@@ -1178,7 +1157,7 @@ void HL1MDLLoader::read_sequence_infos() {
pseqdesc->numevents, "animation events");
}
const AnimEvent_HL1 *pevent = (const AnimEvent_HL1 *)((uint8_t *)header_ + pseqdesc->eventindex);
const AnimEvent_HL1 *pevent = get_buffer_data<AnimEvent_HL1>(pseqdesc->eventindex, pseqdesc->numevents);
aiNode *pEventsNode = new aiNode(AI_MDL_HL1_NODE_ANIMATION_EVENTS);
sequence_info_node_children.push_back(pEventsNode);
@@ -1215,7 +1194,7 @@ void HL1MDLLoader::read_sequence_transitions() {
aiNode *transition_graph_node = new aiNode(AI_MDL_HL1_NODE_SEQUENCE_TRANSITION_GRAPH);
rootnode_children_.push_back(transition_graph_node);
uint8_t *ptransitions = ((uint8_t *)header_ + header_->transitionindex);
const uint8_t *ptransitions = get_buffer_data<uint8_t>(header_->transitionindex, header_->numtransitions * header_->numtransitions);
aiMetadata *md = transition_graph_node->mMetaData = aiMetadata::Alloc(header_->numtransitions * header_->numtransitions);
for (unsigned int i = 0; i < md->mNumProperties; ++i)
md->Set(i, std::to_string(i), static_cast<int>(ptransitions[i]));
@@ -1226,7 +1205,7 @@ void HL1MDLLoader::read_attachments() {
return;
}
const Attachment_HL1 *pattach = (const Attachment_HL1 *)((uint8_t *)header_ + header_->attachmentindex);
const Attachment_HL1 *pattach = get_buffer_data<Attachment_HL1>(header_->attachmentindex, header_->numattachments);
aiNode *attachments_node = new aiNode(AI_MDL_HL1_NODE_ATTACHMENTS);
rootnode_children_.push_back(attachments_node);
@@ -1250,7 +1229,7 @@ void HL1MDLLoader::read_hitboxes() {
return;
}
const Hitbox_HL1 *phitbox = (const Hitbox_HL1 *)((uint8_t *)header_ + header_->hitboxindex);
const Hitbox_HL1 *phitbox = get_buffer_data<Hitbox_HL1>(header_->hitboxindex, header_->numhitboxes);
aiNode *hitboxes_node = new aiNode(AI_MDL_HL1_NODE_HITBOXES);
rootnode_children_.push_back(hitboxes_node);
@@ -1277,7 +1256,9 @@ void HL1MDLLoader::read_bone_controllers() {
return;
}
const BoneController_HL1 *pbonecontroller = (const BoneController_HL1 *)((uint8_t *)header_ + header_->bonecontrollerindex);
const BoneController_HL1 *pbonecontroller = get_buffer_data<BoneController_HL1>(
header_->bonecontrollerindex,
header_->numbonecontrollers);
aiNode *bones_controller_node = new aiNode(AI_MDL_HL1_NODE_BONE_CONTROLLERS);
rootnode_children_.push_back(bones_controller_node);

View File

@@ -47,6 +47,7 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#define AI_HL1MDLLOADER_INCLUDED
#include "HL1FileData.h"
#include "HL1DataBuffer.h"
#include "HL1ImportSettings.h"
#include "UniqueNameGenerator.h"
@@ -74,6 +75,7 @@ public:
aiScene *scene,
IOSystem *io,
const unsigned char *buffer,
size_t buffer_length,
const std::string &file_path,
const HL1ImportSettings &import_settings);
@@ -109,10 +111,32 @@ private:
/** \brief Load a file and copy it's content to a buffer.
* \param file_path The path to the file to be loaded.
* \param buffer A pointer to a buffer to receive the data.
* \param buffer A buffer to receive the data.
*/
template <typename MDLFileHeader>
void load_file_into_buffer(const std::string &file_path, unsigned char *&buffer);
void load_file_into_buffer(const std::string &file_path, HL1DataBuffer &buffer);
/** \brief Get a pointer to the specified data type in texture buffer.
* \param offset Offset in bytes.
* \param elements Elements count.
*/
template <typename DataType>
const DataType *get_texture_buffer_data(int offset, int elements);
/** \brief Get a pointer to the specified data type in animation buffer.
* \param animation Animation index.
* \param offset Offset in bytes.
* \param elements Elements count.
*/
template <typename DataType>
const DataType *get_anim_buffer_data(int animation, int offset, int elements);
/** \brief Get a pointer to the specified data type in MDL buffer.
* \param offset Offset in bytes.
* \param elements Elements count.
*/
template <typename DataType>
const DataType *get_buffer_data(int offset, int elements);
/** \brief Read an MDL texture.
* \param[in] ptexture A pointer to an MDL texture.
@@ -122,7 +146,7 @@ private:
* \param[in,out] last_palette_color The last color from the image palette.
*/
void read_texture(const Texture_HL1 *ptexture,
uint8_t *data, uint8_t *pal, aiTexture *pResult,
const uint8_t *data, const uint8_t *pal, aiTexture *pResult,
aiColor3D &last_palette_color);
/** \brief This method reads a compressed anim value.
@@ -158,7 +182,7 @@ private:
IOSystem *io_;
/** Buffer from MDLLoader class. */
const unsigned char *buffer_;
const HL1DataBuffer buffer_;
/** The full file path to the MDL file we are trying to load.
* Used to locate other MDL files since MDL may store resources
@@ -176,13 +200,13 @@ private:
/** External MDL animation headers.
* One for each loaded animation file. */
SequenceHeader_HL1 **anim_headers_;
std::vector<const SequenceHeader_HL1*> anim_headers_;
/** Texture file data. */
unsigned char *texture_buffer_;
HL1DataBuffer texture_buffer_;
/** Animation files data. */
unsigned char **anim_buffers_;
std::vector<HL1DataBuffer> anim_buffers_;
/** The number of sequence groups. */
int num_sequence_groups_;
@@ -226,7 +250,7 @@ private:
// ------------------------------------------------------------------------------------------------
template <typename MDLFileHeader>
void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned char *&buffer) {
void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, HL1DataBuffer &buffer) {
if (!io_->Exists(file_path))
throw DeadlyImportError("Missing file ", DefaultIOSystem::fileName(file_path), ".");
@@ -241,9 +265,30 @@ void HL1MDLLoader::load_file_into_buffer(const std::string &file_path, unsigned
throw DeadlyImportError("MDL file is too small.");
}
buffer = new unsigned char[1 + file_size];
file->Read((void *)buffer, 1, file_size);
buffer[file_size] = '\0';
std::unique_ptr<unsigned char[]> data(new unsigned char[1 + file_size]);
file->Read(data.get(), 1, file_size);
data[file_size] = '\0';
buffer = HL1DataBuffer::owning(std::move(data), file_size);
}
template <typename DataType>
const DataType *HL1MDLLoader::get_texture_buffer_data(int offset, int elements) {
return texture_buffer_.get_data<DataType>(offset, elements);
}
template <typename DataType>
const DataType *HL1MDLLoader::get_anim_buffer_data(int animation, int offset, int elements) {
if (animation < 0 || animation >= num_sequence_groups_) {
throw DeadlyImportError("MDL file contains invalid sequence group index (", animation, ")");
}
return anim_buffers_[animation].get_data<DataType>(offset, elements);
}
template <typename DataType>
const DataType *HL1MDLLoader::get_buffer_data(int offset, int elements) {
return buffer_.get_data<DataType>(offset, elements);
}
} // namespace HalfLife

View File

@@ -2001,6 +2001,7 @@ void MDLImporter::InternReadFile_HL1(const std::string &pFile, const uint32_t iM
pScene,
mIOHandler,
mBuffer,
iFileSize,
pFile,
mHL1ImportSettings);
}

View File

@@ -457,6 +457,7 @@ ADD_ASSIMP_IMPORTER( MDL
AssetLib/MDL/MDLLoader.h
AssetLib/MDL/MDLMaterialLoader.cpp
AssetLib/MDL/HalfLife/HalfLifeMDLBaseHeader.h
AssetLib/MDL/HalfLife/HL1DataBuffer.h
AssetLib/MDL/HalfLife/HL1FileData.h
AssetLib/MDL/HalfLife/HL1MDLLoader.cpp
AssetLib/MDL/HalfLife/HL1MDLLoader.h