Symphony Of Empires
serializer.cpp
Go to the documentation of this file.
1 // Eng3D - General purpouse game engine
2 // Copyright (C) 2021, Eng3D contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // serializer.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <cstdint>
26 #include <fstream>
27 #include <iterator>
28 #include <memory>
29 #include "eng3d/serializer.hpp"
30 #include "eng3d/utils.hpp"
31 #include "eng3d/log.hpp"
32 #include "eng3d/compress.hpp"
33 
34 constexpr char archive_signature[4] = { '>', ':', ')', ' ' };
35 
36 #define MAX_CHUNK_SIZE (65536 * 128)
37 #define MAX_ARCHIVE_SIZE (65536 * 10000)
38 #define MIN_FILE_SIZE 4096
39 
40 void Eng3D::Deser::Archive::to_file(const std::string& path) {
41  Eng3D::Log::debug("archive", translate_format("Writing archive %s", path.c_str()));
42  if(buffer.empty())
43  CXX_THROW(Eng3D::Deser::Exception, translate("Can't output an empty archive to file"));
44 
45  std::unique_ptr<FILE, decltype(&std::fclose)> fp(::fopen(path.c_str(), "wb"), ::fclose);
46 
47  char signbuf[sizeof(archive_signature)];
48  std::memcpy(signbuf, archive_signature, sizeof(archive_signature));
49  std::fwrite(signbuf, 1, sizeof(signbuf), fp.get());
50  uint32_t inf_len = buffer.size();
51  std::fwrite(&inf_len, 1, sizeof(inf_len), fp.get());
52  std::vector<uint8_t> dest_buffer(std::max<size_t>(buffer.size(), MIN_FILE_SIZE));
53  auto r = Eng3D::Zlib::compress(buffer.data(), buffer.size(), dest_buffer.data(), dest_buffer.size());
54  dest_buffer.resize(r);
55  uint32_t def_len = dest_buffer.size();
56  std::fwrite(&def_len, 1, sizeof(def_len), fp.get());
57  std::fwrite(dest_buffer.data(), 1, dest_buffer.size(), fp.get());
58  Eng3D::Log::debug("archive", string_format("%zu->%zu bytes compressed; return value is %zu", inf_len, def_len, r));
59 }
60 
61 void Eng3D::Deser::Archive::from_file(const std::string& path) {
62  Eng3D::Log::debug("archive", translate_format("Reading archive %s", path.c_str()));
63 
64  std::unique_ptr<FILE, decltype(&std::fclose)> fp(::fopen(path.c_str(), "rb"), ::fclose);
65  if(fp == nullptr) CXX_THROW(std::runtime_error, translate("Can't read archive"));
66 
67  std::vector<uint8_t> src_buffer(buffer.size());
68 
69  char signbuf[sizeof(archive_signature)];
70  std::fread(signbuf, 1, sizeof(signbuf), fp.get());
71  if(std::memcmp(archive_signature, signbuf, sizeof(signbuf)) != 0)
72  CXX_THROW(std::runtime_error, "Invalid archive");
73  uint32_t inf_len;
74  std::fread(&inf_len, 1, sizeof(inf_len), fp.get());
75  uint32_t def_len;
76  std::fread(&def_len, 1, sizeof(def_len), fp.get());
77  if(def_len >= MAX_ARCHIVE_SIZE) CXX_THROW(std::runtime_error, "Exceeded archive size");
78  src_buffer.resize(def_len);
79  std::fread(src_buffer.data(), 1, src_buffer.size(), fp.get());
80 
81  buffer.resize(inf_len);
82  auto r = Eng3D::Zlib::decompress(src_buffer.data(), src_buffer.size(), buffer.data(), buffer.size());
83  Eng3D::Log::debug("archive", string_format("%zu<-%zu bytes decompressed; return value is %zu", inf_len, def_len, r));
84  buffer.shrink_to_fit();
85 }
86 
87 void Eng3D::Deser::Archive::copy_to(void* to_ptr, size_t size) {
88  if(size > buffer.size() - this->ptr)
89  CXX_THROW(Eng3D::Deser::Exception, string_format("Buffer too small for write of %zu bytes", size));
90  std::memcpy(to_ptr, &buffer[this->ptr], size);
91  this->ptr += size;
92 }
93 
94 void Eng3D::Deser::Archive::copy_from(const void* from_ptr, size_t size) {
95  this->expand(size);
96  if(size > buffer.size() - this->ptr)
97  CXX_THROW(Eng3D::Deser::Exception, string_format("Buffer too small for read of %zu bytes", size));
98  std::memcpy(&buffer[this->ptr], from_ptr, size);
99  this->ptr += size;
100 }
The purpouse of the serializer is to serialize objects onto a byte stream that can be transfered onto...
Definition: serializer.hpp:51
std::string translate(const std::string_view str)
Definition: string.cpp:76
void debug(const std::string_view category, const std::string_view msg)
Definition: log.cpp:58
size_t decompress(const void *src, size_t src_len, void *dest, size_t dest_len)
Definition: compress.hpp:49
size_t compress(const void *src, size_t src_len, void *dest, size_t dest_len)
Definition: compress.hpp:30
std::string string_format(const std::string_view format, Args &&... args)
String formatter.
Definition: string.hpp:100
std::string translate_format(const std::string_view format, Args &&... args)
String formatter, with translation.
Definition: string.hpp:128
constexpr char archive_signature[4]
Definition: serializer.cpp:34
#define MIN_FILE_SIZE
Definition: serializer.cpp:38
#define MAX_ARCHIVE_SIZE
Definition: serializer.cpp:37
::std::vector< uint8_t > buffer
Definition: serializer.hpp:97
void to_file(const ::std::string &path)
Definition: serializer.cpp:40
void from_file(const ::std::string &path)
Definition: serializer.cpp:61
void copy_from(const void *ptr, size_t size)
Definition: serializer.cpp:94
void copy_to(void *ptr, size_t size)
Definition: serializer.cpp:87
#define CXX_THROW(class,...)
Definition: utils.hpp:98