Skip to content

Commit 1c341cd

Browse files
committed
vtkF3DQuakeMDLImporter: Add CanReadFile support
1 parent d70cb22 commit 1c341cd

File tree

6 files changed

+139
-23
lines changed

6 files changed

+139
-23
lines changed

plugins/native/module/Testing/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ if(VTK_VERSION VERSION_GREATER_EQUAL 9.4.20250501)
77
TestF3DSplatReader.cxx
88
TestF3DPLYReader.cxx
99
TestF3DQuakeMDLImporterStream.cxx
10+
TestF3DQuakeMDLImporterStreamError.cxx
1011
TestF3DQuakeMDLImporterInexistent.cxx
1112
TestF3DQuakeMDLParser.cxx
1213
)

plugins/native/module/Testing/TestF3DQuakeMDLImporterStream.cxx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ int TestF3DQuakeMDLImporterStream(int vtkNotUsed(argc), char* argv[])
1919
return EXIT_FAILURE;
2020
}
2121

22+
if (!vtkF3DQuakeMDLImporter::CanReadFile(stream))
23+
{
24+
std::cerr << "Unexpected CanReadFile failure\n";
25+
return EXIT_FAILURE;
26+
}
27+
2228
vtkNew<vtkF3DQuakeMDLImporter> importer;
2329
importer->SetStream(stream);
2430
importer->Update();
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#include <vtkDataSet.h>
2+
#include <vtkFileResourceStream.h>
3+
#include <vtkMapper.h>
4+
#include <vtkNew.h>
5+
#include <vtkRenderer.h>
6+
#include <vtkTestUtilities.h>
7+
8+
#include "vtkF3DQuakeMDLImporter.h"
9+
10+
#include <iostream>
11+
12+
int TestF3DQuakeMDLImporterStreamError(int vtkNotUsed(argc), char* argv[])
13+
{
14+
if (vtkF3DQuakeMDLImporter::CanReadFile(nullptr))
15+
{
16+
std::cerr << "Unexpected CanReadFile success with nullptr\n";
17+
return EXIT_FAILURE;
18+
}
19+
20+
vtkNew<vtkFileResourceStream> stream;
21+
std::string path = std::string(argv[1]) + "data/invalid.mdl";
22+
if (!stream->Open(path.c_str()))
23+
{
24+
std::cerr << "Cannot open file\n";
25+
return EXIT_FAILURE;
26+
}
27+
28+
if (vtkF3DQuakeMDLImporter::CanReadFile(stream))
29+
{
30+
std::cerr << "Unexpected CanReadFile success invalid file\n";
31+
return EXIT_FAILURE;
32+
}
33+
34+
path = std::string(argv[1]) + "data/w_medkit_hl.mdl";
35+
if (!stream->Open(path.c_str()))
36+
{
37+
std::cerr << "Cannot open file\n";
38+
return EXIT_FAILURE;
39+
}
40+
41+
if (vtkF3DQuakeMDLImporter::CanReadFile(stream))
42+
{
43+
std::cerr << "Unexpected CanReadFile success wrong version file\n";
44+
return EXIT_FAILURE;
45+
}
46+
47+
// No need to read invalid file, already covered
48+
return EXIT_SUCCESS;
49+
}

plugins/native/module/vtkF3DQuakeMDLImporter.cxx

Lines changed: 71 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -156,9 +156,49 @@ struct vtkF3DQuakeMDLImporter::vtkInternals
156156
return reinterpret_cast<const mdl_simpleframe_t*>(buffer.data() + offset);
157157
}
158158

159+
//----------------------------------------------------------------------------
160+
static bool ReadAndCheckHeader(const std::vector<uint8_t>& buffer, vtkObject* object,
161+
size_t& offset, const mdl_header_t*& header)
162+
{
163+
// Read header
164+
try
165+
{
166+
header = vtkInternals::ReadFromVector<mdl_header_t>(buffer, offset);
167+
}
168+
catch (const F3DRangeError&)
169+
{
170+
if (object)
171+
{
172+
vtkErrorWithObjectMacro(object, "Invalid MDL file");
173+
}
174+
return false;
175+
}
176+
177+
// Check magic number for "IPDO" or "IDST"
178+
if (!(header->ident == 0x4F504449 || header->ident == 0x54534449))
179+
{
180+
if (object)
181+
{
182+
vtkErrorWithObjectMacro(object, "Incompatible MDL header");
183+
}
184+
return false;
185+
}
186+
187+
// Check version for v6 exactly
188+
if (header->version != 6)
189+
{
190+
if (object)
191+
{
192+
vtkErrorWithObjectMacro(object, "Unsupported MDL version. Only version 6 is supported");
193+
}
194+
return false;
195+
}
196+
return true;
197+
}
198+
159199
//----------------------------------------------------------------------------
160200
// Safer buffer typecasting with auto offset incrementing with variable length data
161-
const mdl_simpleframe_t* ReadFromVectorSimpleframe(
201+
static const mdl_simpleframe_t* ReadFromVectorSimpleframe(
162202
const std::vector<uint8_t>& buffer, size_t& offset, size_t num_verts = 0)
163203
{
164204
static constexpr auto mdl_simpleframe_t_fixed_size =
@@ -563,34 +603,15 @@ struct vtkF3DQuakeMDLImporter::vtkInternals
563603
stream->Seek(0, vtkResourceStream::SeekDirection::Begin);
564604

565605
// Read stream into buffer
606+
// TODO rework to avoid copying the whole buffer
566607
std::vector<uint8_t> buffer(length);
567608
stream->Read(buffer.data(), length);
568609

569-
// Read header
570-
// XXX: This is completely unsafe, should be rewritten using modern API
610+
// Read Header
571611
size_t offset = 0;
572612
const mdl_header_t* header;
573-
try
574-
{
575-
header = vtkInternals::ReadFromVector<mdl_header_t>(buffer, offset);
576-
}
577-
catch (const F3DRangeError&)
578-
{
579-
vtkErrorWithObjectMacro(this->Parent, "Invalid MDL file");
580-
return false;
581-
}
582-
583-
// Check magic number for "IPDO" or "IDST"
584-
if (!(header->ident == 0x4F504449 || header->ident == 0x54534449))
613+
if (!vtkInternals::ReadAndCheckHeader(buffer, this->Parent, offset, header))
585614
{
586-
vtkErrorWithObjectMacro(this->Parent, "Incompatible MDL header");
587-
return false;
588-
}
589-
590-
// Check version for v6 exactly
591-
if (header->version != 6)
592-
{
593-
vtkErrorWithObjectMacro(this->Parent, "Unsupported MDL version. Only version 6 is supported");
594615
return false;
595616
}
596617

@@ -791,3 +812,30 @@ bool vtkF3DQuakeMDLImporter::GetTemporalInformation(
791812
}
792813
return true;
793814
}
815+
816+
//------------------------------------------------------------------------------
817+
bool vtkF3DQuakeMDLImporter::CanReadFile(vtkResourceStream* stream)
818+
{
819+
if (!stream)
820+
{
821+
return false;
822+
}
823+
824+
// Read header into buffer
825+
std::size_t headerSize = sizeof(vtkInternals::mdl_header_t);
826+
stream->Seek(0, vtkResourceStream::SeekDirection::Begin);
827+
std::vector<uint8_t> buffer(headerSize);
828+
if (stream->Read(buffer.data(), headerSize) != headerSize)
829+
{
830+
return false;
831+
}
832+
833+
// Check header buffer
834+
size_t offset = 0;
835+
const vtkInternals::mdl_header_t* header;
836+
if (!vtkInternals::ReadAndCheckHeader(buffer, nullptr, offset, header))
837+
{
838+
return false;
839+
}
840+
return true;
841+
}

plugins/native/module/vtkF3DQuakeMDLImporter.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,15 @@ class vtkF3DQuakeMDLImporter : public vtkF3DImporter
7070
vtkGetMacro(SkinIndex, unsigned int);
7171
///@}
7272

73+
/**
74+
* Return true if, after a quick check of file header, it looks like the provided stream
75+
* can be read. Return false if it is sure it cannot be read as a strean.
76+
*
77+
* This only checks that the file header contains the right magic ("IPDO" or "IDST") and the
78+
* version is 6.
79+
*/
80+
static bool CanReadFile(vtkResourceStream* stream);
81+
7382
protected:
7483
vtkF3DQuakeMDLImporter();
7584
~vtkF3DQuakeMDLImporter() override = default;

testing/data/invalid.mdl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:28fca28ef02d08bd61931c03999b7a5b822392132867682e88b2db492ee9f087
3+
size 8

0 commit comments

Comments
 (0)