186 lines
6.4 KiB
C++
186 lines
6.4 KiB
C++
// MassBuilderSaveTool
|
|
// Copyright (C) 2021-2024 Guillaume Jacquemin
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
#include <cstring>
|
|
|
|
#include <Corrade/Containers/Array.h>
|
|
#include <Corrade/Containers/Optional.h>
|
|
#include <Corrade/Containers/String.h>
|
|
#include <Corrade/Utility/Path.h>
|
|
|
|
#include "../BinaryIo/Reader.h"
|
|
#include "../Configuration/Configuration.h"
|
|
#include "../Logger/Logger.h"
|
|
#include "../Utilities/Crc32.h"
|
|
|
|
#include "Keys.h"
|
|
|
|
#include "Import.h"
|
|
|
|
namespace mbst::ImportExport {
|
|
|
|
static Containers::String last_import_error;
|
|
|
|
Containers::StringView
|
|
lastImportError() {
|
|
return last_import_error;
|
|
}
|
|
|
|
Containers::Optional<GameObjects::CustomStyle>
|
|
importStyle(Containers::StringView filename) {
|
|
auto path = Utility::Path::join(conf().directories().styles, filename);
|
|
if(!Utility::Path::exists(path)) {
|
|
LOG_ERROR(last_import_error = path + " doesn't exist.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
BinaryIo::Reader reader{path};
|
|
if(!reader.open()) {
|
|
last_import_error = path + " couldn't be opened.";
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
Containers::Array<char> magic_bytes;
|
|
if(!reader.readArray(magic_bytes, 9)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read the magic bytes.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
Containers::StringView magic_bytes_view = magic_bytes;
|
|
static const auto expected_magic_bytes = "MBSTSTYLE"_s;
|
|
if(magic_bytes_view != expected_magic_bytes) {
|
|
LOG_ERROR(last_import_error = "Magic bytes are mismatched.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
std::size_t data_size;
|
|
if(!reader.readUint64(data_size)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read data size.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
std::uint32_t crc;
|
|
if(!reader.readUint32(crc)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read CRC-32 checksum.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
auto position = reader.position();
|
|
|
|
{
|
|
Containers::Array<char> data;
|
|
if(!reader.readArray(data, data_size)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read data.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
auto computed_crc = Utilities::crc32(0, data);
|
|
if(computed_crc != crc) {
|
|
LOG_ERROR(last_import_error = Utility::format("CRC-32 checksum doesn't match. "
|
|
"Expected {}, got {} instead.",
|
|
crc, computed_crc));
|
|
return Containers::NullOpt;
|
|
}
|
|
}
|
|
|
|
if(!reader.seek(position)) {
|
|
LOG_ERROR(last_import_error = Utility::format("Couldn't seek to position {}.", position));
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
GameObjects::CustomStyle style{};
|
|
|
|
while(!reader.eof()) {
|
|
Keys::CustomStyle key;
|
|
if(!reader.readValue(key)) {
|
|
if(reader.eof()) {
|
|
break;
|
|
}
|
|
LOG_ERROR(last_import_error = "Couldn't read key.");
|
|
return Containers::NullOpt;
|
|
}
|
|
|
|
switch(key) {
|
|
case Keys::Name:
|
|
if(!reader.readUEString(style.name)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style name.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::Colour:
|
|
if(!reader.readValue<Color4>(style.colour)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style colour.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::Metallic:
|
|
if(!reader.readFloat(style.metallic)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style metallic.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::Gloss:
|
|
if(!reader.readFloat(style.gloss)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style gloss.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::Glow:
|
|
if(!reader.readValue(style.glow)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style glow.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::PatternId:
|
|
if(!reader.readInt32(style.patternId)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style pattern ID.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::PatternOpacity:
|
|
if(!reader.readFloat(style.opacity)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style pattern opacity.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::PatternOffset:
|
|
if(!reader.readValue(style.offset)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style pattern offset.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::PatternRotation:
|
|
if(!reader.readFloat(style.rotation)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style pattern rotation.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
case Keys::PatternScale:
|
|
if(!reader.readFloat(style.scale)) {
|
|
LOG_ERROR(last_import_error = "Couldn't read style pattern scale.");
|
|
return Containers::NullOpt;
|
|
}
|
|
break;
|
|
default:
|
|
LOG_ERROR(last_import_error = Utility::format("Unknown key {}.", key));
|
|
return Containers::NullOpt;
|
|
}
|
|
}
|
|
|
|
return Utility::move(style);
|
|
}
|
|
|
|
}
|