+ i64 size;
+ mdl_header *header = vg_asset_read_s( path, &size );
+
+ /*
+ * Check file is valid
+ */
+ if( !header )
+ {
+ vg_error( "Could not open '%s'\n", path );
+ return NULL;
+ }
+
+ if( size < sizeof(mdl_header) )
+ {
+ free( header );
+ vg_error( "Invalid file '%s' (too small for header)\n", path );
+ return NULL;
+ }
+
+ if( header->file_length != size )
+ {
+ vg_error( "Invalid file '%s'"
+ "(wrong .file_length, %ub != real file size %ub)\n",
+ path, header->file_length, size );
+ free( header );
+ return NULL;
+ }
+
+ /*
+ * Validate offsets and memory sections, to ensure all arrays are in-bounds,
+ * and that they do not overlap.
+ */
+
+ struct memregion
+ {
+ const char *desc;
+ u32 count, max_count, size, offset;
+ }
+ regions[] = {
+ {
+ "Vertices",
+ header->vertex_count, MDL_VERT_MAX,
+ sizeof(mdl_vert), header->vertex_offset
+ },
+ {
+ "Indices",
+ header->indice_count, MDL_INDICE_MAX,
+ sizeof(u32), header->indice_offset
+ },
+ {
+ "Submesh",
+ header->submesh_count, MDL_SUBMESH_MAX,
+ sizeof(mdl_submesh), header->submesh_offset
+ },
+ {
+ "Materials",
+ header->material_count, MDL_MATERIAL_MAX,
+ sizeof(mdl_material), header->material_offset
+ },
+ {
+ "Nodes",
+ header->node_count, MDL_NODE_MAX,
+ sizeof(mdl_node), header->node_count
+ }
+ };
+
+ for( int i=0; i<vg_list_size(regions); i++ )
+ {
+ struct memregion *ri = ®ions[i];
+
+ if( ri->count == 0 )
+ continue;
+
+ if( ri->count > ri->max_count )
+ {
+ free( header );
+ vg_error( "'%s': '%s' buffer exceeds the maximum (%u/%u)\n",
+ path, ri->desc, ri->count, ri->max_count );
+ return NULL;
+ }
+
+ if( ri->offset >= header->file_length )
+ {
+ free( header );
+ vg_error( "'%s': '%s' buffer offset is out of range\n",
+ path, ri->desc );
+ return NULL;
+ }
+
+ if( ri->offset + ri->size*ri->count > header->file_length )
+ {
+ free( header );
+ vg_error( "'%s': '%s' buffer size is out of range\n",
+ path, ri->desc );
+ return NULL;
+ }
+
+ for( int j=0; j<vg_list_size(regions); j++ )
+ {
+ struct memregion *rj = ®ions[j];
+ if( rj->count == 0 )
+ continue;
+
+ if( ri->offset >= rj->offset &&
+ (ri->offset+ri->size*ri->count < rj->offset+rj->size*rj->count))
+ {
+ free( header );
+ vg_error( "'%s': '%s' buffer overlaps '%s'\n",
+ path, ri->desc, rj->desc );
+ return NULL;
+ }
+ }
+ }
+
+ /*
+ * Pointer validation TODO(workshop)
+ */
+
+ /*
+ * strings TODO(workshop)
+ */
+
+ return header;