@@ -11,7 +11,17 @@ constexpr int32_t MDL_ID = parser::binary::makeFourCC("IDST");
1111
1212namespace {
1313
14+ // boundary check before seeking
15+ inline bool seekAndValidate (BufferStreamReadOnly& stream, uint64_t offset) {
16+ if (offset >= stream.size ()) {
17+ return false ;
18+ }
19+ stream.seek_u (offset);
20+ return true ;
21+ }
22+
1423// TODO: Decompress RLE animation data into frame values
24+ // TODO: Make lambda return bool for the boundary check?
1525void readAnimValueRLE (BufferStreamReadOnly& stream, int frameCount, std::vector<AnimValue>& outData) {
1626 AnimValue val{};
1727 int framesCovered = 0 ;
@@ -225,7 +235,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
225235
226236 for (int j = 0 ; j < hitboxCount; j++) {
227237 const auto hitboxPos = hitboxOffset + j * (sizeof (int32_t ) * 11 + sizeof (math::Vec3f) * 2 );
228- stream.seek_u (hitboxSetPos + hitboxPos);
238+ if (!seekAndValidate (stream, hitboxSetPos + hitboxPos)) {
239+ return false ;
240+ }
229241
230242 auto & hitbox = hitboxSet.hitboxes .emplace_back ();
231243
@@ -289,8 +301,10 @@ bool MDL::open(const std::byte* data, std::size_t size) {
289301 // TODO: Load external animations if animBlock != 0
290302 if (animDesc.animIndex != 0 && animDesc.animBlock == 0 ) {
291303 const auto animDataPos = animDescPos + animDesc.animIndex ;
304+ if (!seekAndValidate (stream, animDataPos)) {
305+ return false ;
306+ }
292307 const auto savedPos = stream.tell ();
293- stream.seek_u (animDataPos);
294308
295309 // LL of mstudioanim_t structures
296310 // bone, flags, nextoffset (2 bytes), then var data
@@ -331,7 +345,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
331345 // pitch/yaw/roll
332346 for (short comp : rotPtr) {
333347 if (comp > 0 ) {
334- stream.seek_u (ptrPos - sizeof (AnimValuePtr) + comp);
348+ if (!seekAndValidate (stream, ptrPos - sizeof (AnimValuePtr) + comp)) {
349+ return false ;
350+ }
335351 readAnimValueRLE (stream, animDesc.frameCount , boneAnim.animRotationData );
336352 }
337353 }
@@ -350,7 +366,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
350366 // x/y/z
351367 for (short comp : posPtr) {
352368 if (comp > 0 ) {
353- stream.seek_u (ptrPos - sizeof (AnimValuePtr) + comp);
369+ if (!seekAndValidate (stream, ptrPos - sizeof (AnimValuePtr) + comp)) {
370+ return false ;
371+ }
354372 readAnimValueRLE (stream, animDesc.frameCount , boneAnim.animPositionData );
355373 }
356374 }
@@ -361,14 +379,18 @@ bool MDL::open(const std::byte* data, std::size_t size) {
361379 if (nextOffset == 0 ) {
362380 break ;
363381 }
364- stream.seek_u (boneAnimPos + nextOffset);
382+ if (!seekAndValidate (stream, boneAnimPos + nextOffset)) {
383+ return false ;
384+ }
365385 }
366386
367387 stream.seek_u (savedPos);
368388 }
369389
370390 const auto movementDataPos = animDescPos + movementIndex;
371- stream.seek_u (movementDataPos);
391+ if (!seekAndValidate (stream, movementDataPos)) {
392+ return false ;
393+ }
372394
373395 for (int j = 0 ; j < movementCount; j++) {
374396 auto & movement = animDesc.movements .emplace_back ();
@@ -386,7 +408,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
386408
387409 if (ikRuleCount > 0 && ikRuleIndex != 0 && animDesc.animBlock == 0 ) {
388410 const auto ikRuleDataPos = animDescPos + ikRuleIndex;
389- stream.seek_u (ikRuleDataPos);
411+ if (!seekAndValidate (stream, ikRuleDataPos)) {
412+ return false ;
413+ }
390414
391415 for (int j = 0 ; j < ikRuleCount; j++) {
392416 const auto ikRulePos = ikRuleDataPos + j * (sizeof (int32_t ) * 20 + sizeof (float ) * 11 + sizeof (math::Vec3f) + sizeof (math::Quat));
@@ -446,7 +470,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
446470 const auto compErrorDataPos = stream.tell ();
447471 for (short k : ikRule.compressedIKError ->offset ) {
448472 if (k > 0 ) {
449- stream.seek_u (compErrorDataPos + k);
473+ if (!seekAndValidate (stream, compErrorDataPos + k)) {
474+ return false ;
475+ }
450476 readAnimValueRLE (stream, animDesc.frameCount , ikRule.compressedIKError ->animValues );
451477 }
452478 }
@@ -634,7 +660,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
634660
635661 for (int j = 0 ; j < modelsCount; j++) {
636662 auto modelPos = modelsOffset + j * (64 + sizeof (float ) + sizeof (int32_t ) * 20 );
637- stream.seek_u (bodyPartPos + modelPos);
663+ if (!seekAndValidate (stream, bodyPartPos + modelPos)) {
664+ return false ;
665+ }
638666
639667 auto & model = bodyPart.models .emplace_back ();
640668
@@ -659,7 +687,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
659687
660688 for (int k = 0 ; k < meshesCount; k++) {
661689 const auto meshPos = meshesOffset + k * (sizeof (int32_t ) * (18 + MAX_LOD_COUNT) + sizeof (math::Vec3f));
662- stream.seek_u (bodyPartPos + modelPos + meshPos);
690+ if (!seekAndValidate (stream, bodyPartPos + modelPos + meshPos)) {
691+ return false ;
692+ }
663693
664694 auto & mesh = model.meshes .emplace_back ();
665695
@@ -686,7 +716,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
686716
687717 for (int m = 0 ; m < meshFlexCount; m++) {
688718 const auto flexPos = meshFlexOffset + m * (sizeof (int32_t ) * 10 + sizeof (float ) * 4 + sizeof (uint8_t ) * 4 );
689- stream.seek_u (bodyPartPos + modelPos + meshPos + flexPos);
719+ if (!seekAndValidate (stream, bodyPartPos + modelPos + meshPos + flexPos)) {
720+ return false ;
721+ }
690722
691723 auto & flex = mesh.flexes .emplace_back ();
692724
@@ -707,7 +739,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
707739 if (numverts > 0 && vertindex != 0 ) {
708740 // vertindex is relative to the flex structure base
709741 const auto vertAnimPos = bodyPartPos + modelPos + meshPos + flexPos + vertindex;
710- stream.seek_u (vertAnimPos);
742+ if (!seekAndValidate (stream, vertAnimPos)) {
743+ return false ;
744+ }
711745
712746 if (flex.vertanimtype == 0 ) {
713747 // normal vertex animations
@@ -743,7 +777,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
743777 if (eyeballsCount > 0 && eyeballsOffset != 0 ) {
744778 for (int k = 0 ; k < eyeballsCount; k++) {
745779 const auto eyeballPos = eyeballsOffset + k * (sizeof (int32_t ) * 24 + sizeof (float ) * 9 + sizeof (math::Vec3f) * 3 + sizeof (uint8_t ) * 4 );
746- stream.seek_u (bodyPartPos + modelPos + eyeballPos);
780+ if (!seekAndValidate (stream, bodyPartPos + modelPos + eyeballPos)) {
781+ return false ;
782+ }
747783
748784 auto & eyeball = model.eyeballs .emplace_back ();
749785
@@ -779,7 +815,9 @@ bool MDL::open(const std::byte* data, std::size_t size) {
779815 if (modelAttachmentsCount > 0 && modelAttachmentsOffset != 0 ) {
780816 for (int k = 0 ; k < modelAttachmentsCount; k++) {
781817 const auto attachmentPos = modelAttachmentsOffset + k * (sizeof (int32_t ) + sizeof (uint32_t ) + sizeof (int32_t ) + sizeof (math::Mat3x4f) + sizeof (int32_t ) * 8 );
782- stream.seek_u (bodyPartPos + modelPos + attachmentPos);
818+ if (!seekAndValidate (stream, bodyPartPos + modelPos + attachmentPos)) {
819+ return false ;
820+ }
783821
784822 auto & attachment = model.attachments .emplace_back ();
785823
@@ -862,7 +900,10 @@ bool MDL::open(const std::byte* data, std::size_t size) {
862900 auto readStringAtRelativeOffset = [&](std::string& target) {
863901 if (const auto offset = stream.read <int32_t >(); offset != 0 ) {
864902 const auto savedPos = stream.tell ();
865- stream.seek_u (includeModelPos + offset);
903+ // skips if fail
904+ if (!seekAndValidate (stream, includeModelPos + offset)) {
905+ return ;
906+ }
866907 stream.read (target);
867908 stream.seek_u (savedPos);
868909 }
@@ -890,7 +931,10 @@ bool MDL::open(const std::byte* data, std::size_t size) {
890931 auto readStringAtRelativeOffset = [&](std::string& target) {
891932 if (const auto offset = stream.read <int32_t >(); offset != 0 ) {
892933 const auto savedPos = stream.tell ();
893- stream.seek_u (flexControllerPos + offset);
934+ // ditto skip
935+ if (!seekAndValidate (stream, flexControllerPos + offset)) {
936+ return ;
937+ }
894938 stream.read (target);
895939 stream.seek_u (savedPos);
896940 }
@@ -1031,7 +1075,10 @@ bool MDL::open(const std::byte* data, std::size_t size) {
10311075 stream.seek_u (flexControllerUIPos + szindex);
10321076 stream.skip <int32_t >();
10331077 if (const auto controllerNameOffset = stream.read <int32_t >(); controllerNameOffset != 0 ) {
1034- stream.seek_u (flexControllerUIPos + szindex + controllerNameOffset);
1078+ // skips if fail
1079+ if (!seekAndValidate (stream, flexControllerUIPos + szindex + controllerNameOffset)) {
1080+ return ;
1081+ }
10351082 stream.read (targetName);
10361083 }
10371084 stream.seek_u (savedPos);
0 commit comments