2727#include " loadrace.hpp"
2828
2929#include < cstring>
30+ #include < format>
31+ #include < optional>
3032#include < stdexcept>
3133
3234#include " reader.hpp"
3335// #include "writer.hpp"
3436
37+ namespace
38+ {
39+ decltype (auto ) at(auto & values, std::uint32_t index, std::string_view name, ESM4::Reader& reader)
40+ {
41+ if (index >= values.size ())
42+ reader.fail (std::format (" {} index is out of range: {} >= {}" , name, index, values.size ()));
43+ return values[index];
44+ }
45+ }
46+
3547void ESM4::Race::load (ESM4::Reader& reader)
3648{
3749 mId = reader.getFormIdFromHeader ();
@@ -44,7 +56,7 @@ void ESM4::Race::load(ESM4::Reader& reader)
4456
4557 bool isMale = false ;
4658 int currPart = -1 ; // 0 = head, 1 = body, 2 = egt, 3 = hkx
47- std::uint32_t currentIndex = 0xffffffff ;
59+ std::optional<std:: uint32_t > currentIndex;
4860
4961 while (reader.getSubRecordHeader ())
5062 {
@@ -293,12 +305,14 @@ void ESM4::Race::load(ESM4::Reader& reader)
293305 mHeadPartIdsFemale .resize (5 );
294306 }
295307
296- currentIndex = 0xffffffff ;
308+ currentIndex. reset () ;
297309 break ;
298310 }
299311 case ESM::fourCC (" INDX" ):
300312 {
301- reader.get (currentIndex);
313+ std::uint32_t value = 0 ;
314+ reader.get (value);
315+ currentIndex = value;
302316 // FIXME: below check is rather useless
303317 // if (headpart)
304318 // {
@@ -315,25 +329,26 @@ void ESM4::Race::load(ESM4::Reader& reader)
315329 }
316330 case ESM::fourCC (" MODL" ):
317331 {
318- if (currentIndex == 0xffffffff )
332+ if (! currentIndex. has_value () )
319333 {
320334 reader.skipSubRecordData ();
321335 }
322336 else if (currPart == 0 ) // head part
323337 {
324338 if (isMale || isTES4)
325- reader.getZString (mHeadParts [ currentIndex] .mesh );
339+ reader.getZString (at ( mHeadParts , * currentIndex, " head parts " , reader) .mesh );
326340 else
327- reader.getZString (mHeadPartsFemale [currentIndex].mesh ); // TODO: check TES4
341+ // TODO: check TES4
342+ reader.getZString (at (mHeadPartsFemale , *currentIndex, " head parts female" , reader).mesh );
328343
329344 // TES5 keeps head part formid in mHeadPartIdsMale and mHeadPartIdsFemale
330345 }
331346 else if (currPart == 1 ) // body part
332347 {
333348 if (isMale)
334- reader.getZString (mBodyPartsMale [ currentIndex] .mesh );
349+ reader.getZString (at ( mBodyPartsMale , * currentIndex, " body parts male " , reader) .mesh );
335350 else
336- reader.getZString (mBodyPartsFemale [ currentIndex] .mesh );
351+ reader.getZString (at ( mBodyPartsFemale , * currentIndex, " body parts female " , reader) .mesh );
337352
338353 // TES5 seems to have no body parts at all, instead keep EGT models
339354 }
@@ -355,23 +370,24 @@ void ESM4::Race::load(ESM4::Reader& reader)
355370 break ; // always 0x0000?
356371 case ESM::fourCC (" ICON" ):
357372 {
358- if (currentIndex == 0xffffffff )
373+ if (! currentIndex. has_value () )
359374 {
360375 reader.skipSubRecordData ();
361376 }
362377 else if (currPart == 0 ) // head part
363378 {
364379 if (isMale || isTES4)
365- reader.getZString (mHeadParts [ currentIndex] .texture );
380+ reader.getZString (at ( mHeadParts , * currentIndex, " head parts " , reader) .texture );
366381 else
367- reader.getZString (mHeadPartsFemale [currentIndex].texture ); // TODO: check TES4
382+ // TODO: check TES4
383+ reader.getZString (at (mHeadPartsFemale , *currentIndex, " head parts female" , reader).texture );
368384 }
369385 else if (currPart == 1 ) // body part
370386 {
371387 if (isMale)
372- reader.getZString (mBodyPartsMale [ currentIndex] .texture );
388+ reader.getZString (at ( mBodyPartsMale , * currentIndex, " body parts male " , reader) .texture );
373389 else
374- reader.getZString (mBodyPartsFemale [ currentIndex] .texture );
390+ reader.getZString (at ( mBodyPartsFemale , * currentIndex, " body parts female " , reader) .texture );
375391 }
376392 else
377393 reader.skipSubRecordData (); // FIXME TES5
@@ -402,7 +418,7 @@ void ESM4::Race::load(ESM4::Reader& reader)
402418 if (isTES4)
403419 currentIndex = 4 ; // FIXME: argonian tail mesh without preceeding INDX
404420 else
405- currentIndex = 0xffffffff ;
421+ currentIndex. reset () ;
406422
407423 break ;
408424 }
@@ -589,20 +605,20 @@ void ESM4::Race::load(ESM4::Reader& reader)
589605 ESM::FormId formId;
590606 reader.getFormId (formId);
591607
592- if (currentIndex != 0xffffffff )
608+ if (currentIndex. has_value () )
593609 {
594610 // FIXME: no order? head, mouth, eyes, brow, hair
595611 if (isMale)
596612 {
597613 if (currentIndex >= mHeadPartIdsMale .size ())
598- mHeadPartIdsMale .resize (currentIndex + 1 );
599- mHeadPartIdsMale [currentIndex] = formId;
614+ mHeadPartIdsMale .resize (* currentIndex + 1 );
615+ mHeadPartIdsMale [* currentIndex] = formId;
600616 }
601617 else
602618 {
603619 if (currentIndex >= mHeadPartIdsFemale .size ())
604- mHeadPartIdsFemale .resize (currentIndex + 1 );
605- mHeadPartIdsFemale [currentIndex] = formId;
620+ mHeadPartIdsFemale .resize (* currentIndex + 1 );
621+ mHeadPartIdsFemale [* currentIndex] = formId;
606622 }
607623 }
608624
0 commit comments