• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

Return-To-The-Roots / s25client / 14612318600

23 Apr 2025 07:22AM UTC coverage: 50.27% (-0.03%) from 50.295%
14612318600

Pull #1761

github

web-flow
Merge a96bc721f into 0d97404a1
Pull Request #1761: Consistenly catch by const-ref

4 of 20 new or added lines in 14 files covered. (20.0%)

11 existing lines in 2 files now uncovered.

22350 of 44460 relevant lines covered (50.27%)

35200.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

94.2
/libs/libGamedata/lua/GameDataLoader.cpp
1
// Copyright (C) 2005 - 2021 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "GameDataLoader.h"
6
#include "CheckedLuaTable.h"
7
#include "RttrConfig.h"
8
#include "files.h"
9
#include "helpers/containerUtils.h"
10
#include "helpers/format.hpp"
11
#include "gameData/EdgeDesc.h"
12
#include "gameData/LandscapeDesc.h"
13
#include "gameData/TerrainDesc.h"
14
#include "gameData/WorldDescription.h"
15
#include "s25util/Log.h"
16
#include <kaguya/kaguya.hpp>
17
#include <boost/filesystem.hpp>
18
#include <stdexcept>
19

20
namespace bfs = boost::filesystem;
21

22
GameDataLoader::GameDataLoader(WorldDescription& worldDesc, const boost::filesystem::path& basePath)
205✔
23
    : worldDesc_(worldDesc), basePath_(basePath.lexically_normal().make_preferred()), curIncludeDepth_(0),
410✔
24
      errorInIncludeFile_(false)
615✔
25
{
26
    Register(lua);
205✔
27

28
    lua["rttr"] = this;
205✔
29
    lua["include"] = kaguya::function([this](const std::string& file) { Include(file); });
814✔
30
}
205✔
31

32
GameDataLoader::GameDataLoader(WorldDescription& worldDesc)
198✔
33
    : GameDataLoader(worldDesc, RTTRCONFIG.ExpandPath(s25::folders::gamedata) / "world")
396✔
34
{}
198✔
35

36
GameDataLoader::~GameDataLoader() = default;
205✔
37

38
bool GameDataLoader::Load()
205✔
39
{
40
    curFile_ = basePath_ / "default.lua";
410✔
41
    curIncludeDepth_ = 0;
205✔
42
    errorInIncludeFile_ = false;
205✔
43
    try
44
    {
45
        if(!loadScript(curFile_))
205✔
46
            return false;
5✔
NEW
47
    } catch(const std::exception& e)
×
48
    {
49
        LOG.write("Failed to load game data!\nReason: %1%\nCurrent file being processed: %2%\n") % e.what() % curFile_;
×
50
        return false;
×
51
    }
52
    return !errorInIncludeFile_;
200✔
53
}
54

55
void GameDataLoader::Register(kaguya::State& state)
205✔
56
{
57
    state["RTTRGameData"].setClass(kaguya::UserdataMetatable<GameDataLoader, LuaInterfaceBase>()
410✔
58
                                     .addFunction("AddLandscape", &GameDataLoader::AddLandscape)
205✔
59
                                     .addFunction("AddTerrainEdge", &GameDataLoader::AddTerrainEdge)
205✔
60
                                     .addFunction("AddTerrain", &GameDataLoader::AddTerrain));
205✔
61
}
205✔
62

63
class LuaIncludeError : public std::runtime_error
64
{
65
public:
66
    using std::runtime_error::runtime_error;
67
};
68

69
void GameDataLoader::Include(const std::string& filepath)
609✔
70
{
71
    try
72
    {
73
        constexpr int maxIncludeDepth = 10;
609✔
74
        // Protect against cycles and stack overflows
75
        if(++curIncludeDepth_ >= maxIncludeDepth)
609✔
76
            throw LuaIncludeError(helpers::format("Maximum include depth of %1% is reached!", maxIncludeDepth));
1✔
77
        const auto isAllowedChar = [](const char c) {
8,237✔
78
            return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_' || c == '/'
8,237✔
79
                   || c == '.';
16,474✔
80
        };
81
        if(helpers::contains_if(filepath, [isAllowedChar](const char c) { return !isAllowedChar(c); }))
8,845✔
82
            throw LuaIncludeError("It contains disallowed chars. Allowed: alpha-numeric, underscore, slash and dot.");
1✔
83
        if(bfs::path(filepath).is_absolute())
607✔
84
            throw LuaIncludeError("Path to file must be relative to current file");
1✔
85
        bfs::path absFilePath = bfs::absolute(filepath, curFile_.parent_path());
1,818✔
86
        if(!bfs::is_regular_file(absFilePath))
606✔
87
            throw LuaIncludeError("File not found!");
1✔
88

89
        // Normalize for below check against basePath
90
        absFilePath = absFilePath.lexically_normal().make_preferred();
605✔
91
        if(absFilePath.extension() != ".lua")
1,210✔
92
            throw LuaIncludeError("File must have .lua as the extension!");
1✔
93
        if(absFilePath.string().find(basePath_.string()) != 0)
604✔
94
            throw LuaIncludeError("File is outside the lua data directory!");
1✔
95
        const auto oldCurFile = curFile_;
603✔
96
        curFile_ = absFilePath;
603✔
97
        errorInIncludeFile_ |= !loadScript(absFilePath);
603✔
98
        curFile_ = oldCurFile;
603✔
99
        RTTR_Assert(curIncludeDepth_ > 0);
603✔
100
        --curIncludeDepth_;
603✔
101
    } catch(const LuaIncludeError& e)
12✔
102
    {
103
        throw std::runtime_error(helpers::format("Include file '%1%' cannot be included: %2%", filepath, e.what()));
6✔
104
    }
105
}
603✔
106

107
void GameDataLoader::AddLandscape(const kaguya::LuaTable& data)
595✔
108
{
109
    worldDesc_.landscapes.add(LandscapeDesc(data, worldDesc_));
595✔
110
}
595✔
111

112
void GameDataLoader::AddTerrainEdge(const kaguya::LuaTable& data)
2,773✔
113
{
114
    worldDesc_.edges.add(EdgeDesc(data, worldDesc_));
2,773✔
115
}
2,773✔
116

117
void GameDataLoader::AddTerrain(const kaguya::LuaTable& data)
13,863✔
118
{
119
    worldDesc_.terrain.add(TerrainDesc(data, worldDesc_));
13,863✔
120
}
13,863✔
121

122
void loadGameData(WorldDescription& worldDesc)
183✔
123

124
{
125
    GameDataLoader gdLoader(worldDesc);
366✔
126
    if(!gdLoader.Load())
183✔
127
        throw std::runtime_error("Failed to load game data");
×
128
}
183✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc