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

Return-To-The-Roots / s25client / 15652710515

14 Jun 2025 01:51PM UTC coverage: 50.465% (-0.01%) from 50.476%
15652710515

Pull #1534

github

web-flow
Merge eb0559d1e into 19c9b91c8
Pull Request #1534: Portrait support

56 of 155 new or added lines in 17 files covered. (36.13%)

22 existing lines in 4 files now uncovered.

22510 of 44605 relevant lines covered (50.47%)

36236.29 hits per line

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

83.04
/libs/s25main/SavedFile.cpp
1
// Copyright (C) 2005 - 2024 Settlers Freaks (sf-team at siedler25.org)
2
//
3
// SPDX-License-Identifier: GPL-2.0-or-later
4

5
#include "SavedFile.h"
6
#include "BasePlayerInfo.h"
7
#include "RTTR_Version.h"
8
#include "enum_cast.hpp"
9
#include "libendian/ConvertEndianess.h"
10
#include "s25util/BinaryFile.h"
11
#include "s25util/Serializer.h"
12
#include <boost/format.hpp>
13
#include <algorithm>
14
#include <mygettext/mygettext.h>
15
#include <stdexcept>
16

17
SavedFile::SavedFile() : saveTime_(0)
18✔
18
{
19
    const std::string rev = rttr::version::GetRevision();
18✔
20
    std::copy(rev.begin(), rev.begin() + revision.size(), revision.begin());
18✔
21
}
18✔
22

23
SavedFile::~SavedFile() = default;
18✔
24

25
uint8_t SavedFile::GetMinorVersion() const
27✔
26
{
27
    return minorVersion_;
27✔
28
}
29

NEW
30
uint8_t SavedFile::GetMajorVersion() const
×
31
{
NEW
32
    return majorVersion_;
×
33
}
34

35
void SavedFile::WriteFileHeader(BinaryFile& file) const
7✔
36
{
37
    // Signature
38
    const std::string signature = GetSignature();
14✔
39
    file.WriteRawData(signature.c_str(), signature.length());
7✔
40
    // Format version
41
    file.WriteUnsignedChar(GetLatestMajorVersion());
7✔
42
    file.WriteUnsignedChar(GetLatestMinorVersion());
7✔
43
}
7✔
44

45
void SavedFile::WriteExtHeader(BinaryFile& file, const std::string& mapName)
6✔
46
{
47
    // Store data in struct
48
    saveTime_ = s25util::Time::CurrentTime();
6✔
49
    mapName_ = mapName;
6✔
50

51
    // Program version
52
    file.WriteRawData(revision.data(), revision.size());
6✔
53
    s25util::time64_t tmpTime = libendian::ConvertEndianess<false>::fromNative(saveTime_);
6✔
54
    file.WriteRawData(&tmpTime, sizeof(tmpTime));
6✔
55
    file.WriteShortString(mapName);
6✔
56
    file.WriteUnsignedInt(playerNames_.size());
6✔
57
    for(const std::string& name : playerNames_)
24✔
58
        file.WriteShortString(name);
18✔
59
}
6✔
60

61
bool SavedFile::ReadFileHeader(BinaryFile& file)
12✔
62
{
63
    lastErrorMsg.clear();
12✔
64

65
    const std::string signature = GetSignature();
24✔
66
    std::array<char, 32> read_signature;
67
    if(signature.size() > read_signature.size())
12✔
68
        throw std::range_error("Program signature is to long!");
×
69
    try
70
    {
71
        file.ReadRawData(read_signature.data(), signature.size());
12✔
72

73
        // Signatur überprüfen
74
        if(!std::equal(signature.begin(), signature.end(), read_signature.begin()))
12✔
75
        {
76
            lastErrorMsg = _("File is not in a valid format!");
×
77
            return false;
×
78
        }
79

80
        // Version überprüfen
81
        majorVersion_ = file.ReadUnsignedChar();
12✔
82
        minorVersion_ = file.ReadUnsignedChar();
12✔
83
        if(majorVersion_ != GetLatestMajorVersion())
12✔
84
        {
85
            boost::format fmt = boost::format(
NEW
86
              (majorVersion_ < GetLatestMajorVersion()) ?
×
87
                _("File has an old version and cannot be used (version: %1%, expected: %2%)!") :
×
88
                _("File was created with more recent program and cannot be used (version: %1%, expected: %2%)!"));
×
NEW
89
            lastErrorMsg = (fmt % majorVersion_ % GetLatestMajorVersion()).str();
×
90
            return false;
×
91
        }
92
    } catch(const std::runtime_error& e)
×
93
    {
94
        lastErrorMsg = e.what();
×
95
        return false;
×
96
    }
97

98
    return true;
12✔
99
}
100

101
bool SavedFile::ReadExtHeader(BinaryFile& file)
10✔
102
{
103
    file.ReadRawData(revision.data(), revision.size());
10✔
104
    file.ReadRawData(&saveTime_, sizeof(saveTime_));
10✔
105
    saveTime_ = libendian::ConvertEndianess<false>::toNative(saveTime_);
10✔
106
    mapName_ = file.ReadShortString();
10✔
107
    playerNames_.resize(file.ReadUnsignedInt());
10✔
108
    for(std::string& name : playerNames_)
40✔
109
        name = file.ReadShortString();
30✔
110
    return true;
10✔
111
}
112

113
void SavedFile::WriteAllHeaderData(BinaryFile& file, const std::string& mapName)
6✔
114
{
115
    // Versionszeug schreiben
116
    WriteFileHeader(file);
6✔
117
    WriteExtHeader(file, mapName);
6✔
118
}
6✔
119

120
bool SavedFile::ReadAllHeaderData(BinaryFile& file)
10✔
121
{
122
    if(!ReadFileHeader(file))
10✔
123
        return false;
×
124
    if(!ReadExtHeader(file))
10✔
125
        return false;
×
126
    return true;
10✔
127
}
128

129
void SavedFile::WritePlayerData(BinaryFile& file)
6✔
130
{
131
    Serializer ser;
12✔
132
    ser.PushUnsignedChar(players.size());
6✔
133
    for(const auto& player : players)
29✔
134
        player.Serialize(ser, true);
23✔
135

136
    ser.WriteToFile(file);
6✔
137
}
6✔
138

139
void SavedFile::ReadPlayerData(BinaryFile& file)
7✔
140
{
141
    ClearPlayers();
7✔
142
    Serializer ser;
14✔
143
    ser.ReadFromFile(file);
7✔
144
    const unsigned playerCt = ser.PopUnsignedChar();
7✔
145
    players.reserve(playerCt);
7✔
146
    for(unsigned i = 0; i < playerCt; i++)
34✔
147
    {
148
        // TODO(Replay) TODO(Savegame) minor versions will change their meaning when major is bumped
149
        BasePlayerInfo player(ser, GetMinorVersion() >= 1 ? 1 : 0, true);
54✔
150
        // Temporary workaround: The random team was stored in the file but should not anymore, see PR #1331
151
        if(player.team > Team::Team4)
27✔
152
            player.team = Team(rttr::enum_cast(player.team) - 3); // Was random team 2-4
×
153
        else if(player.team == Team::Random)
27✔
154
            player.team = Team::Team1; // Was random team 1
×
155
        AddPlayer(player);
27✔
156
    }
157
}
7✔
158

159
/**
160
 *  schreibt die GlobalGameSettings in die Datei.
161
 */
162
void SavedFile::WriteGGS(BinaryFile& file) const
6✔
163
{
164
    Serializer ser;
12✔
165
    ggs.Serialize(ser);
6✔
166
    ser.WriteToFile(file);
6✔
167
}
6✔
168

169
/**
170
 *  liest die GlobalGameSettings aus der Datei.
171
 */
172
void SavedFile::ReadGGS(BinaryFile& file)
7✔
173
{
174
    Serializer ser;
14✔
175
    ser.ReadFromFile(file);
7✔
176
    ggs.Deserialize(ser);
7✔
177
}
7✔
178

179
const BasePlayerInfo& SavedFile::GetPlayer(unsigned idx) const
27✔
180
{
181
    return players[idx];
27✔
182
}
183

184
unsigned SavedFile::GetNumPlayers()
9✔
185
{
186
    return players.size();
9✔
187
}
188

189
void SavedFile::AddPlayer(const BasePlayerInfo& player)
50✔
190
{
191
    players.push_back(player);
50✔
192
    if(player.isUsed())
50✔
193
        playerNames_.push_back(player.name);
39✔
194
}
50✔
195

196
void SavedFile::ClearPlayers()
17✔
197
{
198
    players.clear();
17✔
199
    playerNames_.clear();
17✔
200
}
17✔
201

202
std::string SavedFile::GetRevision() const
×
203
{
204
    return std::string(revision.begin(), revision.end());
×
205
}
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