25using std::string_view;
29template<
typename Derived>
32 string valueStr(value);
33 self().attribute(name, valueStr);
40unsigned OutputArchiveBase2::generateID1(
const void* p)
43 assert(
"Can't serialize ID of object located on the stack" &&
51unsigned OutputArchiveBase2::generateID2(
52 const void* p,
const std::type_info& typeInfo)
55 assert(
"Can't serialize ID of object located on the stack" &&
59 auto key = std::pair(p, std::type_index(typeInfo));
60 assert(!idMap.contains(key));
61 idMap.emplace_noDuplicateCheck(key, lastId);
65unsigned OutputArchiveBase2::getID1(
const void* p)
67 const auto* v =
lookup(polyIdMap, p);
70unsigned OutputArchiveBase2::getID2(
71 const void* p,
const std::type_info& typeInfo)
73 const auto* v =
lookup(idMap, std::pair(p, std::type_index(typeInfo)));
78template<
typename Derived>
80 const char* tag, std::span<const uint8_t> data,
bool )
87 tmp = HexDump::encode(data);
90 tmp = Base64::encode(data);
92 encoding =
"gz-base64";
94 auto len = data.size();
95 auto dstLen = uLongf(len + len / 1000 + 12 + 1);
97 if (compress2(buf.
data(), &dstLen,
98 std::bit_cast<const Bytef*>(data.data()),
103 tmp = Base64::encode(buf.
first(dstLen));
105 this->self().beginTag(tag);
106 this->self().attribute(
"encoding", encoding);
108 saver(this->self(), tmp,
false);
109 this->self().endTag(tag);
119 auto* v =
lookup(idMap,
id);
120 return v ? *v :
nullptr;
131 for (
const auto& [
id, pt] : idMap) {
132 if (pt == ptr)
return id;
137template<
typename Derived>
139 const char* tag, std::span<uint8_t> data,
bool )
141 this->self().beginTag(tag);
143 this->self().attribute(
"encoding", encoding);
145 string_view tmp = this->self().loadStr();
146 this->self().endTag(tag);
148 if (encoding ==
"gz-base64") {
149 auto buf = Base64::decode(tmp);
150 auto dstLen = uLongf(data.size());
151 if ((uncompress(std::bit_cast<Bytef*>(data.data()), &dstLen,
152 std::bit_cast<const Bytef*>(buf.data()), uLong(buf.size()))
154 (dstLen != data.size())) {
157 }
else if (encoding ==
one_of(
"hex",
"base64")) {
158 bool ok = (encoding ==
"hex")
160 : Base64 ::decode_inplace(tmp, data);
163 "Length of decoded blob different from "
164 "expected value (", data.size(),
')');
167 throw XMLException(
"Unsupported encoding \"", encoding,
"\" for blob");
178 auto size = s.size();
179 auto buf = buffer.
allocate(
sizeof(size) + size);
180 memcpy(buf.data(), &size,
sizeof(size));
192 buffer.
read(s.data(), length);
202 return {std::bit_cast<const char*>(p), length};
212static constexpr size_t SMALL_SIZE = 64;
217 if (data.size() > SMALL_SIZE) {
218 auto deltaBlockIdx = unsigned(deltaBlocks.size());
220 deltaBlocks.push_back(diff
221 ? lastDeltaBlocks.
createNew(data.data(), data)
224 auto buf = buffer.
allocate(data.size());
232 if (data.size() > SMALL_SIZE) {
241 unsigned deltaBlockIdx;
load(deltaBlockIdx);
242 deltaBlocks[deltaBlockIdx]->apply(data);
245 buffer.
skip(data.size());
252 : filename(filename_)
258 int duped_fd = dup(fileno(f.get()));
259 if (duped_fd == -1) error();
260 file = gzdopen(duped_fd,
"wb9");
269 static constexpr std::string_view header =
270 "<?xml version=\"1.0\" ?>\n"
271 "<!DOCTYPE openmsx-serialize SYSTEM 'openmsx-serialize.dtd'>\n";
274 writer.begin(
"serial");
277 writer.attribute(
"platform", TARGET_PLATFORM);
284 writer.end(
"serial");
286 if (gzclose(file) != Z_OK) {
303 if ((gzwrite(file, buf.data(),
unsigned(buf.size())) == 0) && !buf.empty()) {
310 if (gzputc(file, c) == -1) {
317 assert(condition); (void)condition;
326 throw XMLException(
"could not write \"", filename,
'"');
331 writer.data(std::string_view(&c, 1));
339 writer.data(b ?
"true" :
"false");
368 writer.attribute(name, str);
392 xmlDoc.
load(filename,
"openmsx-serialize.dtd");
393 const auto* root = xmlDoc.
getRoot();
394 elems.emplace_back(root, root->getFirstChild());
400 throw XMLException(
"No child tags expected for primitive type");
412 std::istringstream is(str);
418 if (s ==
one_of(
"true",
"1")) {
420 }
else if (s ==
one_of(
"false",
"0")) {
440template<std::
integral T>
static inline void fastAtoi(string_view str, T&
t)
445 size_t l = str.
size();
447 if constexpr (std::numeric_limits<T>::is_signed) {
455 unsigned d = str[i] -
'0';
456 if (d > 9) [[unlikely]] {
457 throw XMLException(
"Invalid integer: ", str);
461 if constexpr (std::numeric_limits<T>::is_signed) {
464 assert(!neg); (void)neg;
484 u = narrow_cast<unsigned>(i);
496 b = narrow_cast<unsigned char>(u);
502 c = narrow_cast<signed char>(i);
508 c = narrow_cast<char>(i);
516 for (
const auto& [e, _] : elems) {
520 "\" found at location \"", path,
'\"');
522 elems.emplace_back(child, child->getFirstChild());
527 if (elem.getName() != tag) {
529 "\" not equal to begin tag \"", tag,
"\"");
540 throw XMLException(
"Missing attribute \"", name,
"\".");
542 t = attr->getValue();
bool contains(const K &k) const
iterator emplace_noDuplicateCheck(Args &&... args)
void attribute(const char *name, T &t)
Load/store an attribute from/in the archive.
std::shared_ptr< DeltaBlock > createNew(const void *id, std::span< const uint8_t > data)
std::shared_ptr< DeltaBlock > createNullDiff(const void *id, std::span< const uint8_t > data)
This class manages the lifetime of a block of memory.
std::span< const T > first(size_t n) const
const T * data() const
Returns pointer to the start of the memory buffer.
void serialize_blob(const char *tag, std::span< const uint8_t > data, bool diff=true)
void serialize_blob(const char *tag, std::span< const uint8_t > data, bool diff=true)
std::span< uint8_t > allocate(size_t len)
Reserve space to insert the given number of bytes.
static std::string full()
const XMLElement * getRoot() const
void load(const std::string &filename, std::string_view systemID)
const XMLAttribute * findAttribute(std::string_view attrName) const
const XMLElement * findChild(std::string_view childName) const
std::string_view getData() const
void saveImpl(const T &t)
void check(bool condition) const
void write(std::span< const char > buf)
XmlOutputArchive(zstring_view filename)
void attributeImpl(const char *name, const T &t)
void endTag(const char *tag)
void beginTag(const char *tag)
void attribute(const char *name, const T &t)
Like std::string_view, but with the extra guarantee that it refers to a zero-terminated string.
const Value * lookup(const hash_map< Key, Value, Hasher, Equal > &map, const Key2 &key)
bool decode_inplace(std::string_view input, std::span< uint8_t > output)
std::string toString(time_t time)
FILE_t openFile(zstring_view filename, zstring_view mode)
Call fopen() in a platform-independent manner.
This file implemented 3 utility functions:
constexpr auto copy(InputRange &&range, OutputIter out)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
void strAppend(std::string &result, Ts &&...ts)