30#include <wx/filename.h>
45#include <decompress.hpp>
47#include <Standard_Failure.hxx>
64class COM_ALLOCATED_PATH
67 ~COM_ALLOCATED_PATH() { CoTaskMemFree( value ); }
69 PWSTR value =
nullptr;
72bool IsLowIntegrityProcess()
76 if( !OpenProcessToken( GetCurrentProcess(), TOKEN_QUERY, &token.value ) )
80 GetTokenInformation( token.value, TokenIntegrityLevel,
nullptr, 0, &size );
81 std::vector<BYTE> buffer( size );
82 bool lowIntegrity =
false;
84 if( size > 0 && GetTokenInformation( token.value, TokenIntegrityLevel, buffer.data(), size, &size ) )
86 const auto* label =
reinterpret_cast<const TOKEN_MANDATORY_LABEL*
>( buffer.data() );
87 PSID sid = label->Label.Sid;
88 DWORD count = *GetSidSubAuthorityCount( sid );
91 lowIntegrity = *GetSidSubAuthority( sid, count - 1 ) < SECURITY_MANDATORY_MEDIUM_RID;
103 if( !IsLowIntegrityProcess() )
104 return wxFileName::CreateTempFileName( aPrefix );
106 COM_ALLOCATED_PATH localLowPath;
107 HRESULT
result = SHGetKnownFolderPath( FOLDERID_LocalAppDataLow, KF_FLAG_CREATE,
nullptr, &localLowPath.value );
112 wxFileName
directory( localLowPath.value, wxEmptyString );
113 directory.AppendDir( wxS(
"KiCadPreview" ) );
119 return wxFileName::CreateTempFileName( wxFileName(
directory.GetFullPath(), aPrefix ).GetFullPath() );
121 return wxFileName::CreateTempFileName( aPrefix );
126 std::uint64_t aMaxExpandedBytes, std::string& aExpanded )
128 const std::size_t cap =
static_cast<std::size_t
>(
129 std::min<std::uint64_t>( aMaxExpandedBytes, std::numeric_limits<std::size_t>::max() ) );
133 aExpanded = gzip::decompress( aData, aSize, cap, std::min<std::size_t>( cap, 64U * 1024U ) );
135 catch(
const gzip::limit_error& )
153 explicit SCENE_OWNER( SCENEGRAPH* aScene ) :
157 ~SCENE_OWNER() {
S3D::DestroyNode(
reinterpret_cast<SGNODE*
>( m_scene ) ); }
159 SCENEGRAPH* Get()
const {
return m_scene; }
172bool addBudget( std::uint64_t& aTotal, std::uint64_t aCount, std::uint64_t aElementSize, std::uint64_t aLimit )
174 if( aTotal > aLimit || ( aCount && aElementSize > ( aLimit - aTotal ) / aCount ) )
177 aTotal += aCount * aElementSize;
182bool isFinite(
const SFVEC3F& aValue )
184 return std::isfinite( aValue.x ) && std::isfinite( aValue.y ) && std::isfinite( aValue.z );
190 std::uint64_t total = 0;
191 bool hasValidFaces =
false;
192 unsigned int outputMesh = 0;
195 return VALIDATION_RESULT::INVALID;
199 return VALIDATION_RESULT::TOO_LARGE;
209 return VALIDATION_RESULT::INVALID;
228 return VALIDATION_RESULT::TOO_LARGE;
230 bool finiteVertices =
true;
232 for(
unsigned int vertex = 0; vertex < mesh.
m_VertexSize; ++vertex )
238 || !std::isfinite( mesh.
m_Texcoords[vertex].y ) ) ) )
240 finiteVertices =
false;
245 if( !finiteVertices )
251 unsigned int output = 0;
253 for(
unsigned int triangle = 0; triangle + 3 <= mesh.
m_FaceIdxSize; triangle += 3 )
264 hasValidFaces = hasValidFaces || output > 0;
272 if( outputMesh != i )
283 return hasValidFaces && outputMesh > 0 ? VALIDATION_RESULT::VALID : VALIDATION_RESULT::INVALID;
293 aOther.m_model =
nullptr;
299 if(
this != &aOther )
305 aOther.m_model =
nullptr;
318S3D::MODEL_IMPORT_RESULT::operator bool() const noexcept
360 wxFileName fileName( wxString::FromUTF8( aFileName ) );
362 if( !fileName.FileExists() || !fileName.IsFileReadable() )
365 result.m_diagnostic =
"Model file is missing or unreadable";
374 result.m_diagnostic =
"Invalid model import options";
378 wxULongLong inputSize = fileName.GetSize();
380 if( inputSize == wxInvalidSize || inputSize.GetValue() > aOptions.
maxExpandedBytes )
383 result.m_diagnostic =
"Model input exceeds the configured limit";
387 std::string extension = fileName.GetExt().Lower().ToStdString();
388 std::string lowerName = fileName.GetFullName().Lower().ToStdString();
393 if( extension ==
"stp" || extension ==
"step" || extension ==
"stpz" || extension ==
"stepz"
394 || lowerName.ends_with(
".stp.gz" ) || lowerName.ends_with(
".step.gz" ) )
396 else if( extension ==
"igs" || extension ==
"iges" )
398 else if( extension ==
"wrl" || extension ==
"wrz" )
400 else if( extension ==
"x3d" )
405 result.m_diagnostic =
"Unsupported model format";
414 scene =
LoadModel( aFileName.c_str(), &aOptions, &status );
416 scene =
LoadVRMLModel( aFileName.c_str(), &aOptions, &status );
428 if(
result.m_diagnostic.empty() )
429 result.m_diagnostic =
"Model parser rejected the file";
434 SCENE_OWNER sceneOwner( scene );
445 result.m_model ? validateModel( *
result.m_model, aOptions ) : VALIDATION_RESULT::INVALID;
447 if( validation != VALIDATION_RESULT::VALID )
452 result.m_diagnostic = validation == VALIDATION_RESULT::TOO_LARGE
453 ?
"Model exceeds the configured mesh limit"
454 :
"Model contains invalid or no renderable geometry";
461 catch(
const std::bad_alloc& )
471 catch(
const Standard_Failure& e )
478 result.m_diagnostic = e.GetMessageString() ? e.GetMessageString() :
"OCCT import failure";
484 catch(
const std::exception& e )
491 result.m_diagnostic = e.what();
bool IsTriangleInRange(const unsigned int *aFaceIdx, unsigned int aTriangleIdx, unsigned int aVertexCount)
Test whether the three face indices of a triangle all reference valid vertices.
Scoped holder for the recursive model import lock.
MODEL_IMPORT_ERROR m_error
const S3DMODEL * GetModel() const noexcept
MODEL_IMPORT_ERROR GetError() const noexcept
std::string_view GetDiagnostic() const noexcept
MODEL_IMPORT_RESULT(MODEL_IMPORT_RESULT &&aOther) noexcept
MODEL_IMPORT_RESULT() noexcept=default
MODEL_IMPORT_RESULT & operator=(MODEL_IMPORT_RESULT &&aOther) noexcept
Define the basic data set required to represent a 3D model.
collects header files for all SG* wrappers and the API
defines the API calls for the manipulation of SG* classes
SCENEGRAPH * LoadModel(char const *filename, const S3D::MODEL_IMPORT_OPTIONS *aOptions, MODEL_IMPORT_STATUS *aStatus)
wxString CreateModelImportTempFileName(const wxString &aPrefix)
MODEL_IMPORT_GZIP_RESULT DecompressBoundedModel(const char *aData, std::size_t aSize, std::uint64_t aMaxExpandedBytes, std::string &aExpanded)
Expand a gzip stream into aExpanded, refusing anything over aMaxExpandedBytes.
KICAD_3D_IMPORT_API MODEL_IMPORT_RESULT ImportModel(const std::string &aFileName, const MODEL_IMPORT_OPTIONS &aOptions={}) noexcept
Import and flatten one model without invoking GUI facilities.
SGLIB_API void Free3DMesh(SMESH &aMesh)
Free memory used internally by an SMESH structure.
SGLIB_API void Init3DMesh(SMESH &aMesh)
Create and initialize an SMESH structure.
SGLIB_API void DestroyNode(SGNODE *aNode) noexcept
Delete the given SG* class node.
SGLIB_API S3DMODEL * GetModel(SCENEGRAPH *aNode)
Create an S3DMODEL representation of aNode (raw data, no transforms).
SGLIB_API void Destroy3DModel(S3DMODEL **aModel)
Free memory used by an S3DMODEL structure and sets the pointer to the structure to NULL.
S3D::MODEL_IMPORT_ERROR error
Store the a model based on meshes and materials.
SMATERIAL * m_Materials
The materials list of this model.
unsigned int m_MeshesSize
Number of meshes in the array.
SMESH * m_Meshes
The meshes list of this model.
unsigned int m_MaterialsSize
Number of materials in the material array.
bool IsCanceled() const noexcept
double stepLinearDeflection
MODEL_IMPORT_FORMAT format
std::uint64_t maxExpandedBytes
std::uint64_t maxMeshBytes
double stepAngularDeflectionDegrees
float m_Transparency
1.0 is completely transparent, 0.0 completely opaque
SFVEC3F m_Diffuse
Default diffuse color if m_Color is NULL.
Per-vertex normal/color/texcoors structure.
unsigned int * m_FaceIdx
Triangle Face Indexes.
SFVEC3F * m_Normals
Vertex normals array.
unsigned int m_MaterialIdx
Material Index to be used in this mesh (must be < m_MaterialsSize )
unsigned int m_VertexSize
Number of vertex in the arrays.
SFVEC2F * m_Texcoords
Vertex texture coordinates array, can be NULL.
unsigned int m_FaceIdxSize
Number of elements of the m_FaceIdx array.
SFVEC3F * m_Color
Vertex color array, can be NULL.
SFVEC3F * m_Positions
Vertex position array.
Result of a validation operation.
wxString result
Test unit parsing edge cases and error handling.
KICAD_3D_IMPORT_API SCENEGRAPH * LoadVRMLModel(const char *aFileName, const S3D::MODEL_IMPORT_OPTIONS *aOptions=nullptr)