diff --git a/Source/items.cpp b/Source/items.cpp index 3e5673bf857..8ec190461e0 100644 --- a/Source/items.cpp +++ b/Source/items.cpp @@ -645,8 +645,8 @@ void GetBookSpell(Item &item, int lvl) const std::string_view spellName = GetSpellData(bs).sNameText; const size_t iNameLen = std::string_view(item._iName).size(); const size_t iINameLen = std::string_view(item._iIName).size(); - CopyUtf8(item._iName + iNameLen, spellName, sizeof(item._iName) - iNameLen); - CopyUtf8(item._iIName + iINameLen, spellName, sizeof(item._iIName) - iINameLen); + CopyUtf8(item._iName + iNameLen, spellName, ItemNameLength - iNameLen); + CopyUtf8(item._iIName + iINameLen, spellName, ItemNameLength - iINameLen); item._iSpell = bs; const SpellData &spellData = GetSpellData(bs); item._iMinMag = spellData.minInt; @@ -1134,12 +1134,12 @@ void GetStaffPower(const Player &player, Item &item, int lvl, SpellID bs, bool o const ItemData &baseItemData = AllItemsList[item.IDidx]; std::string staffName = GenerateStaffName(baseItemData, item._iSpell, false); - CopyUtf8(item._iName, staffName, sizeof(item._iName)); + CopyUtf8(item._iName, staffName, ItemNameLength); if (preidx != -1) { std::string staffNameMagical = GenerateStaffNameMagical(baseItemData, item._iSpell, preidx, false, std::nullopt); - CopyUtf8(item._iIName, staffNameMagical, sizeof(item._iIName)); + CopyUtf8(item._iIName, staffNameMagical, ItemNameLength); } else { - CopyUtf8(item._iIName, item._iName, sizeof(item._iIName)); + CopyUtf8(item._iIName, item._iName, ItemNameLength); } CalcItemValue(item); @@ -1242,9 +1242,9 @@ void GetItemPower(const Player &player, Item &item, int minlvl, int maxlvl, Affi pSufix = &suffix; }); - CopyUtf8(item._iIName, GenerateMagicItemName(item._iName, pPrefix, pSufix, false), sizeof(item._iIName)); + CopyUtf8(item._iIName, GenerateMagicItemName(item._iName, pPrefix, pSufix, false), ItemNameLength); if (!StringInPanel(item._iIName)) { - CopyUtf8(item._iIName, GenerateMagicItemName(AllItemsList[item.IDidx].iSName, pPrefix, pSufix, false), sizeof(item._iIName)); + CopyUtf8(item._iIName, GenerateMagicItemName(AllItemsList[item.IDidx].iSName, pPrefix, pSufix, false), ItemNameLength); } if (pPrefix != nullptr || pSufix != nullptr) CalcItemValue(item); @@ -1316,8 +1316,8 @@ void GetOilType(Item &item, int maxLvl) int8_t t = rnd[GenerateRnd(cnt)]; - CopyUtf8(item._iName, OilNames[t], sizeof(item._iName)); - CopyUtf8(item._iIName, OilNames[t], sizeof(item._iIName)); + CopyUtf8(item._iName, OilNames[t], ItemNameLength); + CopyUtf8(item._iIName, OilNames[t], ItemNameLength); item._iMiscId = OilMagic[t]; item._ivalue = OilValues[t]; item._iIvalue = OilValues[t]; @@ -1479,7 +1479,7 @@ void GetUniqueItem(const Player &player, Item &item, _unique_items uid) SaveItemPower(player, item, power); } - CopyUtf8(item._iIName, uniqueItemData.UIName, sizeof(item._iIName)); + CopyUtf8(item._iIName, uniqueItemData.UIName, ItemNameLength); if (uniqueItemData.UICurs != ICURS_DEFAULT) item._iCurs = uniqueItemData.UICurs; item._iIvalue = uniqueItemData.UIValue; @@ -2929,8 +2929,8 @@ void InitializeItem(Item &item, _item_indexes itemData) item._itype = pAllItem.itype; item._iCurs = pAllItem.iCurs; - CopyUtf8(item._iName, pAllItem.iName, sizeof(item._iName)); - CopyUtf8(item._iIName, pAllItem.iName, sizeof(item._iIName)); + CopyUtf8(item._iName, pAllItem.iName, ItemNameLength); + CopyUtf8(item._iIName, pAllItem.iName, ItemNameLength); item._iLoc = pAllItem.iLoc; item._iClass = pAllItem.iClass; item._iMinDam = pAllItem.iMinDam; @@ -3126,8 +3126,8 @@ void GetItemAttrs(Item &item, _item_indexes itemData, int lvl) auto &baseItemData = AllItemsList[static_cast(itemData)]; item._itype = baseItemData.itype; item._iCurs = baseItemData.iCurs; - CopyUtf8(item._iName, baseItemData.iName, sizeof(item._iName)); - CopyUtf8(item._iIName, baseItemData.iName, sizeof(item._iIName)); + CopyUtf8(item._iName, baseItemData.iName, ItemNameLength); + CopyUtf8(item._iIName, baseItemData.iName, ItemNameLength); item._iLoc = baseItemData.iLoc; item._iClass = baseItemData.iClass; item._iMinDam = baseItemData.iMinDam; @@ -3570,8 +3570,8 @@ void RecreateEar(Item &item, uint16_t ic, uint32_t iseed, uint8_t bCursval, std: std::string itemName = fmt::format(fmt::runtime("Ear of {:s}"), heroName); - CopyUtf8(item._iName, itemName, sizeof(item._iName)); - CopyUtf8(item._iIName, heroName, sizeof(item._iIName)); + CopyUtf8(item._iName, itemName, ItemNameLength); + CopyUtf8(item._iIName, heroName, ItemNameLength); item._iCurs = ((bCursval >> 6) & 3) + ICURS_EAR_SORCERER; item._ivalue = bCursval & 0x3F; diff --git a/Source/items.h b/Source/items.h index 47e87d07154..ade9faafd2a 100644 --- a/Source/items.h +++ b/Source/items.h @@ -31,6 +31,7 @@ namespace devilution { // Item indestructible durability #define DUR_INDESTRUCTIBLE 255 +constexpr int ItemNameLength = 64; constexpr int MaxVendorValue = 140000; constexpr int MaxVendorValueHf = 200000; constexpr int MaxBoyValue = 90000; @@ -200,8 +201,8 @@ struct Item { bool _iPostDraw = false; bool _iIdentified = false; item_quality _iMagical = ITEM_QUALITY_NORMAL; - char _iName[64] = {}; - char _iIName[64] = {}; + char _iName[ItemNameLength] = {}; + char _iIName[ItemNameLength] = {}; item_equip_type _iLoc = ILOC_NONE; item_class _iClass = ICLASS_NONE; uint8_t _iCurs = 0; diff --git a/Source/loadsave.cpp b/Source/loadsave.cpp index 2a43a42c125..ce95a89f767 100644 --- a/Source/loadsave.cpp +++ b/Source/loadsave.cpp @@ -86,6 +86,14 @@ T SwapBE(T in) } } +void TerminateUtf8(char *str, size_t maxLength) +{ + std::string_view inStr { str, maxLength }; + std::string_view truncStr = TruncateUtf8(inStr, maxLength - 1); + size_t utf8Length = truncStr.size(); + str[utf8Length] = '\0'; +} + class LoadHelper { std::unique_ptr m_buffer_; size_t m_cur_ = 0; @@ -268,8 +276,10 @@ void LoadItemData(LoadHelper &file, Item &item) item._iPostDraw = file.NextBool32(); item._iIdentified = file.NextBool32(); item._iMagical = static_cast(file.NextLE()); - file.NextBytes(item._iName, 64); - file.NextBytes(item._iIName, 64); + file.NextBytes(item._iName, ItemNameLength); + TerminateUtf8(item._iName, ItemNameLength); + file.NextBytes(item._iIName, ItemNameLength); + TerminateUtf8(item._iIName, ItemNameLength); item._iLoc = static_cast(file.NextLE()); item._iClass = static_cast(file.NextLE()); file.Skip(1); // Alignment @@ -439,6 +449,7 @@ void LoadPlayer(LoadHelper &file, Player &player) player._pLvlChanging = file.NextBool8(); file.NextBytes(player._pName, PlayerNameLength); + TerminateUtf8(player._pName, PlayerNameLength); player._pClass = static_cast(file.NextLE()); file.Skip(3); // Alignment player._pStrength = file.NextLE(); @@ -1088,8 +1099,8 @@ void SaveItem(SaveHelper &file, const Item &item) file.WriteLE(item._iPostDraw ? 1 : 0); file.WriteLE(item._iIdentified ? 1 : 0); file.WriteLE(item._iMagical); - file.WriteBytes(item._iName, 64); - file.WriteBytes(item._iIName, 64); + file.WriteBytes(item._iName, ItemNameLength); + file.WriteBytes(item._iIName, ItemNameLength); file.WriteLE(item._iLoc); file.WriteLE(item._iClass); file.Skip(1); // Alignment diff --git a/Source/player.cpp b/Source/player.cpp index e5c3dcc12c4..bafe6828e3c 100644 --- a/Source/player.cpp +++ b/Source/player.cpp @@ -2678,7 +2678,7 @@ StartPlayerKill(Player &player, DeathReason deathReason) Item ear; InitializeItem(ear, IDI_EAR); CopyUtf8(ear._iName, fmt::format(fmt::runtime("Ear of {:s}"), player._pName), sizeof(ear._iName)); - CopyUtf8(ear._iIName, player._pName, sizeof(ear._iIName)); + CopyUtf8(ear._iIName, player._pName, ItemNameLength); switch (player._pClass) { case HeroClass::Sorcerer: ear._iCurs = ICURS_EAR_SORCERER; diff --git a/test/pack_test.cpp b/test/pack_test.cpp index 36df4e024aa..ce4f4f393fd 100644 --- a/test/pack_test.cpp +++ b/test/pack_test.cpp @@ -95,7 +95,7 @@ void ComparePackedItems(const ItemPack &item1LE, const ItemPack &item2LE) } } typedef struct TestItemStruct { - char _iIName[64]; + char _iIName[ItemNameLength]; ItemType _itype; int _iClass; int _iCurs;