24using std::string_view;
28template<
typename Derived>
31 string valueStr(value);
32 self().attribute(name, valueStr);
39unsigned OutputArchiveBase2::generateID1(
const void* p)
42 assert(
"Can't serialize ID of object located on the stack" &&
50unsigned OutputArchiveBase2::generateID2(
51 const void* p,
const std::type_info& typeInfo)
54 assert(
"Can't serialize ID of object located on the stack" &&
58 auto key = std::pair(p, std::type_index(typeInfo));
59 assert(!idMap.contains(key));
60 idMap.emplace_noDuplicateCheck(key, lastId);
64unsigned OutputArchiveBase2::getID1(
const void* p)
66 auto* v =
lookup(polyIdMap, p);
69unsigned OutputArchiveBase2::getID2(
70 const void* p,
const std::type_info& typeInfo)
72 auto* v =
lookup(idMap, std::pair(p, std::type_index(typeInfo)));
77template<
typename Derived>
79 const char* tag, std::span<const uint8_t> data,
bool )
86 tmp = HexDump::encode(data);
89 tmp = Base64::encode(data);
91 encoding =
"gz-base64";
93 auto len = data.size();
94 auto dstLen = uLongf(len + len / 1000 + 12 + 1);
96 if (compress2(buf.
data(), &dstLen,
97 reinterpret_cast<const Bytef*
>(data.data()),
102 tmp = Base64::encode(std::span{buf.
data(), dstLen});
104 this->self().beginTag(tag);
105 this->self().attribute(
"encoding", encoding);
107 saver(this->self(), tmp,
false);
108 this->self().endTag(tag);
118 auto* v =
lookup(idMap,
id);
119 return v ? *v :
nullptr;
130 for (
const auto& [
id, pt] : idMap) {
131 if (pt == ptr)
return id;
136template<
typename Derived>
138 const char* tag, std::span<uint8_t> data,
bool )
140 this->self().beginTag(tag);
142 this->self().attribute(
"encoding", encoding);
144 string_view tmp = this->self().loadStr();
145 this->self().endTag(tag);
147 if (encoding ==
"gz-base64") {
148 auto [buf, bufSize] = Base64::decode(tmp);
149 auto dstLen = uLongf(data.size());
150 if ((uncompress(
reinterpret_cast<Bytef*
>(data.data()), &dstLen,
151 reinterpret_cast<const Bytef*
>(buf.data()), uLong(bufSize))
153 (dstLen != data.size())) {
156 }
else if (encoding ==
one_of(
"hex",
"base64")) {
157 bool ok = (encoding ==
"hex")
162 "Length of decoded blob different from "
163 "expected value (", data.size(),
')');
166 throw XMLException(
"Unsupported encoding \"", encoding,
"\" for blob");
177 auto size = s.size();
179 memcpy(buf.data(), &
size,
sizeof(
size));
206 return {
reinterpret_cast<const char*
>(p),
length};
216static constexpr size_t SMALL_SIZE = 64;
221 if (data.size() > SMALL_SIZE) {
222 auto deltaBlockIdx = unsigned(deltaBlocks.size());
224 deltaBlocks.push_back(diff
225 ? lastDeltaBlocks.
createNew(data.data(), data)
228 auto buf = buffer.
allocate(data.size());
236 if (data.size() > SMALL_SIZE) {
245 unsigned deltaBlockIdx;
load(deltaBlockIdx);
246 deltaBlocks[deltaBlockIdx]->apply(data);
249 buffer.
skip(data.size());
256 : filename(filename_)
262 int duped_fd = dup(fileno(f.get()));
263 if (duped_fd == -1)
error();
264 file = gzdopen(duped_fd,
"wb9");
273 static constexpr std::string_view header =
274 "<?xml version=\"1.0\" ?>\n"
275 "<!DOCTYPE openmsx-serialize SYSTEM 'openmsx-serialize.dtd'>\n";
278 writer.begin(
"serial");
281 writer.attribute(
"platform", TARGET_PLATFORM);
288 writer.end(
"serial");
290 if (gzclose(file) != Z_OK) {
307 if ((gzwrite(file, buf.data(),
unsigned(buf.size())) == 0) && !buf.empty()) {
314 if (gzputc(file, c) == -1) {
321 assert(condition); (void)condition;
330 throw XMLException(
"could not write \"", filename,
'"');
335 writer.data(std::string_view(&c, 1));
343 writer.data(b ?
"true" :
"false");
372 writer.attribute(name, str);
396 xmlDoc.
load(filename,
"openmsx-serialize.dtd");
397 const auto* root = xmlDoc.
getRoot();
398 elems.emplace_back(root, root->getFirstChild());
404 throw XMLException(
"No child tags expected for primitive type");
416 std::istringstream is(str);
422 if (s ==
one_of(
"true",
"1")) {
424 }
else if (s ==
one_of(
"false",
"0")) {
444template<std::
integral T>
static inline void fastAtoi(string_view str, T&
t)
449 size_t l = str.
size();
451 if constexpr (std::numeric_limits<T>::is_signed) {
459 unsigned d = str[i] -
'0';
460 if (d > 9) [[unlikely]] {
461 throw XMLException(
"Invalid integer: ", str);
465 if constexpr (std::numeric_limits<T>::is_signed) {
468 assert(!neg); (void)neg;
488 u = narrow_cast<unsigned>(i);
500 b = narrow_cast<unsigned char>(u);
506 c = narrow_cast<signed char>(i);
512 c = narrow_cast<char>(i);
520 for (
auto&
e : elems) {
524 "\" found at location \"", path,
'\"');
526 elems.emplace_back(child, child->getFirstChild());
531 if (elem.getName() != tag) {
533 "\" not equal to begin tag \"", tag,
"\"");
544 throw XMLException(
"Missing attribute \"", name,
"\".");
546 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)
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)
MemBuffer< uint8_t > releaseBuffer(size_t &size)
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.
MemBuffer< uint8_t > release(size_t &size)
Release ownership of the buffer.
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)
bool decode_inplace(std::string_view input, std::span< uint8_t > output)
T length(const vecN< N, T > &x)
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:
auto copy(InputRange &&range, OutputIter out)
size_t size(std::string_view utf8)
constexpr auto subspan(Range &&range, size_t offset, size_t count=std::dynamic_extent)
void strAppend(std::string &result, Ts &&...ts)