diff --git a/cdoc/CDoc1Writer.cpp b/cdoc/CDoc1Writer.cpp index ed7c343..988a7a4 100644 --- a/cdoc/CDoc1Writer.cpp +++ b/cdoc/CDoc1Writer.cpp @@ -32,6 +32,11 @@ using namespace libcdoc; #define RET_ERROR(F) if (auto rv = F; rv < 0) return rv +constexpr XMLWriter::NS DENC{ "denc", "http://www.w3.org/2001/04/xmlenc#" }; +constexpr XMLWriter::NS DS{ "ds", "http://www.w3.org/2000/09/xmldsig#" }; +constexpr XMLWriter::NS XENC11{ "xenc11", "http://www.w3.org/2009/xmlenc11#" }; +constexpr XMLWriter::NS DSIG11{ "dsig11", "http://www.w3.org/2009/xmldsig11#" }; + struct FileEntry { std::string name; size_t size; @@ -45,8 +50,6 @@ struct FileEntry { struct CDoc1Writer::Private final: public XMLWriter { - static const XMLWriter::NS DENC, DS, XENC11, DSIG11; - Private(DataConsumer &dst, std::string &last_error) : XMLWriter(dst) , lastError(last_error) @@ -57,57 +60,60 @@ struct CDoc1Writer::Private final: public XMLWriter std::string &lastError; std::vector files; - int64_t writeEncryptionProperties(bool use_ddoc); - int64_t writeKeyInfo(bool use_ddoc, const std::vector &rcpts, const Crypto::Key& transportKey); + int64_t writeDocument(bool use_ddoc, const std::vector &rcpts, const std::function &f); int64_t writeRecipient(const std::vector &recipient, const Crypto::Key& transportKey); }; -const XMLWriter::NS CDoc1Writer::Private::DENC{ "denc", "http://www.w3.org/2001/04/xmlenc#" }; -const XMLWriter::NS CDoc1Writer::Private::DS{ "ds", "http://www.w3.org/2000/09/xmldsig#" }; -const XMLWriter::NS CDoc1Writer::Private::XENC11{ "xenc11", "http://www.w3.org/2009/xmlenc11#" }; -const XMLWriter::NS CDoc1Writer::Private::DSIG11{ "dsig11", "http://www.w3.org/2009/xmldsig11#" }; - CDoc1Writer::CDoc1Writer(DataConsumer *dst, bool take_ownership) : CDocWriter(1, dst, take_ownership) {} CDoc1Writer::~CDoc1Writer() noexcept = default; -int64_t CDoc1Writer::Private::writeEncryptionProperties(bool use_ddoc) +int64_t CDoc1Writer::Private::writeDocument(bool use_ddoc, const std::vector &rcpts, const std::function &f) { - RET_ERROR(writeElement(DENC, "EncryptionProperties", [&]() -> int64_t { - RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "LibraryVersion"}}, "cdoc|0.0.1")); - RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "DocumentFormat"}}, documentFormat)); - RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "Filename"}}, use_ddoc ? "tmp.ddoc" : files.at(0).name)); - for(const FileEntry &file: files) - { - RET_ERROR(writeTextElement(Private::DENC, "EncryptionProperty", {{"Name", "orig_file"}}, - file.name + "|" + std::to_string(file.size) + "|" + "application/octet-stream" + "|D0")); + return writeElement(DENC, "EncryptedData", + {{"MimeType", use_ddoc ? "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : "application/octet-stream"}}, [&] -> int64_t { + RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", method}})); + libcdoc::Crypto::Key transportKey = libcdoc::Crypto::generateKey(method); + if (transportKey.key.empty()) { + lastError = "Failed to generate transport key"; + LOG_ERROR("{}", lastError); + return CRYPTO_ERROR; } - return OK; - })); - return writeEndElement(Private::DENC); // EncryptedData -} - -int64_t CDoc1Writer::Private::writeKeyInfo(bool use_ddoc, const std::vector &rcpts, const Crypto::Key& transportKey) -{ - RET_ERROR(writeStartElement(Private::DENC, "EncryptedData", - {{"MimeType", use_ddoc ? "http://www.sk.ee/DigiDoc/v1.3.0/digidoc.xsd" : "application/octet-stream"}})); - RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", method}})); - return writeElement(Private::DS, "KeyInfo", {}, [&]() -> int64_t { - for (const Recipient& key : rcpts) { - if (!key.isCertificate()) { - lastError = "Invalid recipient type"; - LOG_ERROR("{}", lastError); - return UNSPECIFIED_ERROR; + RET_ERROR(writeElement(DS, "KeyInfo", {}, [&] -> int64_t { + for (const Recipient& key : rcpts) { + if (!key.isCertificate()) { + lastError = "Invalid recipient type"; + LOG_ERROR("{}", lastError); + return UNSPECIFIED_ERROR; + } + if(auto rv = writeRecipient(key.cert, transportKey); rv < 0) { + lastError = "Failed to write Recipient info"; + LOG_ERROR("{}", lastError); + return rv; + } } - if(auto rv = writeRecipient(key.cert, transportKey); rv < 0) { - lastError = "Failed to write Recipient info"; - LOG_ERROR("{}", lastError); - return rv; + return OK; + })); + RET_ERROR(writeElement(DENC, "CipherData", [&] { + return writeBase64Element(DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t { + EncryptionConsumer enc(dst, method, transportKey); + RET_ERROR(f(enc)); + return enc.close(); + }); + })); + return writeElement(DENC, "EncryptionProperties", [&] -> int64_t { + RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "LibraryVersion"}}, "cdoc|0.0.1")); + RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "DocumentFormat"}}, documentFormat)); + RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "Filename"}}, use_ddoc ? "tmp.ddoc" : files.at(0).name)); + for(const FileEntry &file: files) + { + RET_ERROR(writeTextElement(DENC, "EncryptionProperty", {{"Name", "orig_file"}}, + file.name + "|" + std::to_string(file.size) + "|" + "application/octet-stream" + "|D0")); } - } - return OK; + return OK; + }); }); } @@ -134,7 +140,7 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector &recipie OPENSSL_free(data); return cn; }(); - return writeElement(Private::DENC, "EncryptedKey", {{"Recipient", cn}}, [&]() -> int64_t { + return writeElement(DENC, "EncryptedKey", {{"Recipient", cn}}, [&] -> int64_t { std::vector encryptedData; auto *peerPKey = X509_get0_pubkey(peerCert.get()); switch(EVP_PKEY_base_id(peerPKey)) @@ -142,10 +148,10 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector &recipie case EVP_PKEY_RSA: { encryptedData = Crypto::encrypt(peerPKey, RSA_PKCS1_PADDING, transportKey.key); - RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", Crypto::RSA_MTH}})); - RET_ERROR(writeElement(Private::DS, "KeyInfo", [&] { - return writeElement(Private::DS, "X509Data", [&] { - return writeBase64Element(Private::DS, "X509Certificate", recipient); + RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", Crypto::RSA_MTH}})); + RET_ERROR(writeElement(DS, "KeyInfo", [&] { + return writeElement(DS, "X509Data", [&] { + return writeBase64Element(DS, "X509Certificate", recipient); }); })); break; @@ -183,28 +189,28 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector &recipie LOG_TRACE_KEY("iv {}", transportKey.iv); LOG_TRACE_KEY("transport {}", transportKey.key); - RET_ERROR(writeElement(Private::DENC, "EncryptionMethod", {{"Algorithm", encryptionMethod}})); - RET_ERROR(writeElement(Private::DS, "KeyInfo", [&] { - return writeElement(Private::DENC, "AgreementMethod", {{"Algorithm", Crypto::AGREEMENT_MTH}}, [&] { - RET_ERROR(writeElement(Private::XENC11, "KeyDerivationMethod", {{"Algorithm", Crypto::CONCATKDF_MTH}}, [&] { - return writeElement(Private::XENC11, "ConcatKDFParams", { + RET_ERROR(writeElement(DENC, "EncryptionMethod", {{"Algorithm", encryptionMethod}})); + RET_ERROR(writeElement(DS, "KeyInfo", [&] { + return writeElement(DENC, "AgreementMethod", {{"Algorithm", Crypto::AGREEMENT_MTH}}, [&] { + RET_ERROR(writeElement(XENC11, "KeyDerivationMethod", {{"Algorithm", Crypto::CONCATKDF_MTH}}, [&] { + return writeElement(XENC11, "ConcatKDFParams", { {"AlgorithmID", "00" + toHex(AlgorithmID)}, {"PartyUInfo", "00" + toHex(SsDer)}, {"PartyVInfo", "00" + toHex(recipient)}}, [&] { - return writeElement(Private::DS, "DigestMethod", {{"Algorithm", concatDigest}}); + return writeElement(DS, "DigestMethod", {{"Algorithm", concatDigest}}); }); })); - RET_ERROR(writeElement(Private::DENC, "OriginatorKeyInfo", [&] { - return writeElement(Private::DS, "KeyValue", [&] { - return writeElement(Private::DSIG11, "ECKeyValue", [&] { - RET_ERROR(writeElement(Private::DSIG11, "NamedCurve", {{"URI", "urn:oid:" + oid}})); - return writeBase64Element(Private::DSIG11, "PublicKey", SsDer); + RET_ERROR(writeElement(DENC, "OriginatorKeyInfo", [&] { + return writeElement(DS, "KeyValue", [&] { + return writeElement(DSIG11, "ECKeyValue", [&] { + RET_ERROR(writeElement(DSIG11, "NamedCurve", {{"URI", "urn:oid:" + oid}})); + return writeBase64Element(DSIG11, "PublicKey", SsDer); }); }); })); - return writeElement(Private::DENC, "RecipientKeyInfo", [&] { - return writeElement(Private::DS, "X509Data", [&] { - return writeBase64Element(Private::DS, "X509Certificate", recipient); + return writeElement(DENC, "RecipientKeyInfo", [&] { + return writeElement(DS, "X509Data", [&] { + return writeBase64Element(DS, "X509Certificate", recipient); }); }); }); @@ -217,8 +223,8 @@ int64_t CDoc1Writer::Private::writeRecipient(const std::vector &recipie if (encryptedData.empty()) return UNSPECIFIED_ERROR; - return writeElement(Private::DENC, "CipherData", [&] { - return writeBase64Element(Private::DENC, "CipherValue", encryptedData); + return writeElement(DENC, "CipherData", [&] { + return writeBase64Element(DENC, "CipherValue", encryptedData); }); }); } @@ -231,38 +237,31 @@ CDoc1Writer::encrypt(libcdoc::MultiDataSource& src, const std::vectormethod); + RET_ERROR(beginEncryption()); int n_components = src.getNumComponents(); bool use_ddoc = (n_components > 1) || (n_components == libcdoc::NOT_IMPLEMENTED); - - RET_ERROR(d->writeKeyInfo(use_ddoc, keys, transportKey)); - RET_ERROR(d->writeElement(Private::DENC, "CipherData", [&] { - return d->writeBase64Element(Private::DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t { - EncryptionConsumer enc(dst, d->method, transportKey); - std::string name; - int64_t size; - if(use_ddoc) { - DDOCWriter ddoc(enc); - result_t result; - for (result = src.next(name, size); result == OK; result = src.next(name, size)) { - RET_ERROR(ddoc.addFile(name, "application/octet-stream", size, src)); - d->files.push_back({name, size_t(size)}); - } - if(result != END_OF_STREAM) - return result; - } else { - RET_ERROR(src.next(name, size)); - if(auto rv = src.readAll(enc); rv >= 0) - d->files.push_back({std::move(name), size_t(rv)}); - else - return rv; + RET_ERROR(d->writeDocument(use_ddoc, keys, [&](DataConsumer &dst) -> int64_t { + std::string name; + int64_t size; + if(use_ddoc) { + DDOCWriter ddoc(dst); + result_t result; + for (result = src.next(name, size); result == OK; result = src.next(name, size)) { + RET_ERROR(ddoc.addFile(name, "application/octet-stream", size, src)); + d->files.push_back({name, size_t(size)}); } - return enc.close(); - }); + if(result != END_OF_STREAM) + return result; + } else { + RET_ERROR(src.next(name, size)); + if(auto rv = src.readAll(dst); rv >= 0) + d->files.push_back({std::move(name), size_t(rv)}); + else + return rv; + } + return OK; })); - RET_ERROR(d->writeEncryptionProperties(use_ddoc)); d.reset(); if (owned) return dst->close(); return OK; @@ -271,8 +270,16 @@ CDoc1Writer::encrypt(libcdoc::MultiDataSource& src, const std::vector(*dst, last_error); return libcdoc::OK; } @@ -308,26 +315,16 @@ CDoc1Writer::writeData(const uint8_t *src, size_t size) libcdoc::result_t CDoc1Writer::finishEncryption() { - if(!d || rcpts.empty() || d->files.empty()) + if(!d || d->files.empty()) return WORKFLOW_ERROR; bool use_ddoc = d->files.size() > 1; - libcdoc::Crypto::Key transportKey = libcdoc::Crypto::generateKey(d->method); - - RET_ERROR(d->writeKeyInfo(use_ddoc, rcpts, transportKey)); - RET_ERROR(d->writeElement(Private::DENC, "CipherData", [&] { - return d->writeBase64Element(Private::DENC, "CipherValue", [&](DataConsumer &dst) -> int64_t { - EncryptionConsumer enc(dst, d->method, transportKey); - if(use_ddoc) - { - for(DDOCWriter ddoc(enc); const FileEntry& file : d->files) - RET_ERROR(ddoc.addFile(file.name, "application/octet-stream", file.data)); - } - else - RET_ERROR(VectorSource(d->files.back().data).readAll(enc)); - return enc.close(); - }); + RET_ERROR(d->writeDocument(use_ddoc, rcpts, [&, this](DataConsumer &dst) -> int64_t { + if(!use_ddoc) + return VectorSource(d->files.back().data).readAll(dst); + for(DDOCWriter ddoc(dst); const FileEntry& file : d->files) + RET_ERROR(ddoc.addFile(file.name, "application/octet-stream", file.data)); + return OK; })); - RET_ERROR(d->writeEncryptionProperties(use_ddoc)); d.reset(); if (owned) return dst->close(); return libcdoc::OK; diff --git a/cdoc/DDocWriter.cpp b/cdoc/DDocWriter.cpp index e376967..eb85d1a 100644 --- a/cdoc/DDocWriter.cpp +++ b/cdoc/DDocWriter.cpp @@ -27,7 +27,7 @@ using namespace libcdoc; * @brief DDOCWriter is used for storing multiple files. */ -const XMLWriter::NS DDOCWriter::DDOC{ "", "http://www.sk.ee/DigiDoc/v1.3.0#" }; +constexpr XMLWriter::NS DDOC{ nullptr, "http://www.sk.ee/DigiDoc/v1.3.0#" }; DDOCWriter::DDOCWriter(DataConsumer &dst) : XMLWriter(dst) diff --git a/cdoc/DDocWriter.h b/cdoc/DDocWriter.h index d4fbf3c..2bfe482 100644 --- a/cdoc/DDocWriter.h +++ b/cdoc/DDocWriter.h @@ -36,8 +36,6 @@ class DDOCWriter final: public XMLWriter DDOCWriter(const DDOCWriter &) = delete; DDOCWriter &operator=(const DDOCWriter &) = delete; int fileCount = 0; - - static const NS DDOC; }; } diff --git a/cdoc/XmlWriter.cpp b/cdoc/XmlWriter.cpp index cda36ff..24715b1 100644 --- a/cdoc/XmlWriter.cpp +++ b/cdoc/XmlWriter.cpp @@ -20,8 +20,6 @@ #include "Io.h" -#include "utils/memory.h" - #include #include @@ -30,72 +28,51 @@ using namespace libcdoc; using pcxmlChar = xmlChar *; -struct XMLWriter::Private -{ - Private(libcdoc::DataConsumer &_dst): dst(_dst) {} - libcdoc::DataConsumer &dst; - std::map nsmap; - - unique_ptr_t w = make_unique_ptr(xmlNewTextWriter( - xmlOutputBufferCreateIO(xmlOutputWriteCallback, nullptr, this, nullptr))); - - static int xmlOutputWriteCallback (void *context, const char *buffer, int len); -}; - -int -XMLWriter::Private::xmlOutputWriteCallback (void *context, const char *buffer, int len) -{ - auto *d = reinterpret_cast(context); - return d->dst.write((uint8_t *) buffer, len); -} - XMLWriter::XMLWriter(libcdoc::DataConsumer &dst) - : d(std::make_unique(dst)) + : w(make_unique_ptr(xmlNewTextWriter(xmlOutputBufferCreateIO([](void *context, const char *buffer, int len) -> int { + auto *dst = reinterpret_cast(context); + auto result = dst->write((uint8_t *) buffer, len); + return result >= OK ? result : -1; + }, nullptr, &dst, nullptr)), xmlFreeTextWriter)) { - if(d->w) - xmlTextWriterStartDocument(d->w.get(), nullptr, "UTF-8", nullptr); + if(w) + xmlTextWriterStartDocument(w.get(), nullptr, "UTF-8", nullptr); } XMLWriter::~XMLWriter() noexcept { - if(d->w) - xmlTextWriterEndDocument(d->w.get()); + if(w) + xmlTextWriterEndDocument(w.get()); } -int64_t XMLWriter::writeStartElement(const NS &ns, const std::string &name, const std::map &attr) +int64_t XMLWriter::writeStartElement(NS ns, const std::string &name, const std::map &attr) { - if(!d->w) + if(!w) return WRONG_ARGUMENTS; - auto pos = d->nsmap.find(ns.prefix); - if (pos != d->nsmap.cend()) - pos->second++; - else - pos = d->nsmap.insert({ns.prefix, 1}).first; - if(xmlTextWriterStartElementNS(d->w.get(), - ns.prefix.empty() ? nullptr : pcxmlChar(ns.prefix.c_str()), - pcxmlChar(name.c_str()), - pos->second > 1 ? nullptr : pcxmlChar(ns.ns.c_str())) == -1) + auto [pos, inserted] = nsmap.emplace(ns.prefix ? ns.prefix : "", 0); + pos->second++; + if(xmlTextWriterStartElementNS(w.get(), pcxmlChar(ns.prefix), pcxmlChar(name.c_str()), inserted ? pcxmlChar(ns.ns) : nullptr) == -1) return IO_ERROR; for(const auto &[name, content]: attr) { - if(xmlTextWriterWriteAttribute(d->w.get(), pcxmlChar(name.c_str()), pcxmlChar(content.c_str())) == -1) + if(xmlTextWriterWriteAttribute(w.get(), pcxmlChar(name.c_str()), pcxmlChar(content.c_str())) == -1) return IO_ERROR; } return OK; } -int64_t XMLWriter::writeEndElement(const NS &ns) +int64_t XMLWriter::writeEndElement(NS ns) { - if(!d->w) + if(!w) return WRONG_ARGUMENTS; - if(xmlTextWriterEndElement(d->w.get()) == -1) + if(xmlTextWriterEndElement(w.get()) == -1) return IO_ERROR; - if(auto pos = d->nsmap.find(ns.prefix); pos != d->nsmap.cend()) + if(auto pos = nsmap.find(ns.prefix ? ns.prefix : ""); pos != nsmap.cend()) pos->second--; return OK; } -int64_t XMLWriter::writeElement(const NS &ns, const std::string &name, const std::function &f) +int64_t XMLWriter::writeElement(NS ns, const std::string &name, const std::function &f) { if(auto rv = writeStartElement(ns, name, {}); rv != OK) return rv; @@ -104,7 +81,7 @@ int64_t XMLWriter::writeElement(const NS &ns, const std::string &name, const std return writeEndElement(ns); } -int64_t XMLWriter::writeElement(const NS &ns, const std::string &name, const std::map &attr, const std::function &f) +int64_t XMLWriter::writeElement(NS ns, const std::string &name, const std::map &attr, const std::function &f) { if(auto rv = writeStartElement(ns, name, attr); rv != OK) return rv; @@ -113,7 +90,7 @@ int64_t XMLWriter::writeElement(const NS &ns, const std::string &name, const std return writeEndElement(ns); } -int64_t XMLWriter::writeBase64Element(const NS &ns, const std::string &name, const std::function &f, const std::map &attr) +int64_t XMLWriter::writeBase64Element(NS ns, const std::string &name, const std::function &f, const std::map &attr) { if(auto rv = writeStartElement(ns, name, attr); rv != OK) return rv; @@ -165,7 +142,7 @@ int64_t XMLWriter::writeBase64Element(const NS &ns, const std::string &name, con return OK; } bool isError() final { return false; } - } base64Consumer {d->w.get()}; + } base64Consumer {w.get()}; if(auto rv = f(base64Consumer); rv < 0) return rv; if(auto rv = base64Consumer.close(); rv < 0) @@ -173,20 +150,20 @@ int64_t XMLWriter::writeBase64Element(const NS &ns, const std::string &name, con return writeEndElement(ns); } -int64_t XMLWriter::writeBase64Element(const NS &ns, const std::string &name, const std::vector &data, const std::map &attr) +int64_t XMLWriter::writeBase64Element(NS ns, const std::string &name, const std::vector &data, const std::map &attr) { if(auto rv = writeStartElement(ns, name, attr); rv != OK) return rv; - if(xmlTextWriterWriteBase64(d->w.get(), reinterpret_cast(data.data()), 0, data.size()) == -1) + if(xmlTextWriterWriteBase64(w.get(), reinterpret_cast(data.data()), 0, data.size()) == -1) return IO_ERROR; return writeEndElement(ns); } -int64_t XMLWriter::writeTextElement(const NS &ns, const std::string &name, const std::map &attr, const std::string &data) +int64_t XMLWriter::writeTextElement(NS ns, const std::string &name, const std::map &attr, const std::string &data) { if(auto rv = writeStartElement(ns, name, attr); rv != OK) return rv; - if(xmlTextWriterWriteString(d->w.get(), pcxmlChar(data.c_str())) == -1) + if(xmlTextWriterWriteString(w.get(), pcxmlChar(data.c_str())) == -1) return IO_ERROR; return writeEndElement(ns); } diff --git a/cdoc/XmlWriter.h b/cdoc/XmlWriter.h index fc72eb2..97e9abd 100644 --- a/cdoc/XmlWriter.h +++ b/cdoc/XmlWriter.h @@ -18,12 +18,14 @@ #pragma once +#include "utils/memory.h" + #include #include #include -#include #include -#include + +struct _xmlTextWriter; namespace libcdoc { @@ -32,22 +34,22 @@ struct DataConsumer; class XMLWriter { public: - struct NS { std::string prefix, ns; }; + struct NS { const char *prefix, *ns; }; XMLWriter(DataConsumer &dst); virtual ~XMLWriter() noexcept; - int64_t writeStartElement(const NS &ns, const std::string &name, const std::map &attr); - int64_t writeEndElement(const NS &ns); - int64_t writeElement(const NS &ns, const std::string &name, const std::function &f = nullptr); - int64_t writeElement(const NS &ns, const std::string &name, const std::map &attr, const std::function &f = nullptr); - int64_t writeBase64Element(const NS &ns, const std::string &name, const std::function &f, const std::map &attr = {}); - int64_t writeBase64Element(const NS &ns, const std::string &name, const std::vector &data, const std::map &attr = {}); - int64_t writeTextElement(const NS &ns, const std::string &name, const std::map &attr, const std::string &data); + int64_t writeStartElement(NS ns, const std::string &name, const std::map &attr); + int64_t writeEndElement(NS ns); + int64_t writeElement(NS ns, const std::string &name, const std::function &f = nullptr); + int64_t writeElement(NS ns, const std::string &name, const std::map &attr, const std::function &f = nullptr); + int64_t writeBase64Element(NS ns, const std::string &name, const std::function &f, const std::map &attr = {}); + int64_t writeBase64Element(NS ns, const std::string &name, const std::vector &data, const std::map &attr = {}); + int64_t writeTextElement(NS ns, const std::string &name, const std::map &attr, const std::string &data); private: - struct Private; - std::unique_ptr d; + unique_free_t<_xmlTextWriter> w; + std::map nsmap; }; } // namespace libcdoc diff --git a/test/libcdoc_boost.cpp b/test/libcdoc_boost.cpp index 78e3ce4..f204edf 100644 --- a/test/libcdoc_boost.cpp +++ b/test/libcdoc_boost.cpp @@ -561,14 +561,14 @@ BOOST_AUTO_TEST_CASE(PlainLabelParsing) { const string label("data:v=1&type=ID-card&serial_number=PNOEE-38001085718&cn=J%C3%95EORG%2CJAAK-KRISTJAN%2C38001085718"); - map result = libcdoc::Recipient::parseLabel(label); - for (map::const_reference expected_pair : ExpectedParsedLabel) + auto result = libcdoc::Recipient::parseLabel(label); + for (const auto& [key, value] : ExpectedParsedLabel) { - map::const_iterator result_pair = result.find(expected_pair.first); - BOOST_TEST((result_pair != result.cend()), "Field " << expected_pair.first << " presented"); + auto result_pair = result.find(key); + BOOST_TEST((result_pair != result.cend()), "Field " << key << " presented"); if (result_pair != result.end()) { - BOOST_CHECK_EQUAL(result_pair->second, expected_pair.second); + BOOST_CHECK_EQUAL(result_pair->second, value); } } } @@ -577,14 +577,14 @@ BOOST_AUTO_TEST_CASE(Base64LabelParsing) { const string label("data:;base64,dj0xJnR5cGU9SUQtY2FyZCZzZXJpYWxfbnVtYmVyPVBOT0VFLTM4MDAxMDg1NzE4JmNuPUolQzMlOTVFT1JHJTJDSkFBSy1LUklTVEpBTiUyQzM4MDAxMDg1NzE4"); - map result = libcdoc::Recipient::parseLabel(label); - for (map::const_reference expected_pair : ExpectedParsedLabel) + auto result = libcdoc::Recipient::parseLabel(label); + for (const auto& [key, value] : ExpectedParsedLabel) { - map::const_iterator result_pair = result.find(expected_pair.first); - BOOST_TEST((result_pair != result.cend()), "Field " << expected_pair.first << " presented"); + auto result_pair = result.find(key); + BOOST_TEST((result_pair != result.cend()), "Field " << key << " presented"); if (result_pair != result.end()) { - BOOST_CHECK_EQUAL(result_pair->second, expected_pair.second); + BOOST_CHECK_EQUAL(result_pair->second, value); } } } @@ -593,14 +593,14 @@ BOOST_AUTO_TEST_CASE(Base64LabelParsingWithMediaType) { const string label("data:application/x-www-form-urlencoded;base64,dj0xJnR5cGU9SUQtY2FyZCZzZXJpYWxfbnVtYmVyPVBOT0VFLTM4MDAxMDg1NzE4JmNuPUolQzMlOTVFT1JHJTJDSkFBSy1LUklTVEpBTiUyQzM4MDAxMDg1NzE4"); - map result = libcdoc::Recipient::parseLabel(label); - for (map::const_reference expected_pair : ExpectedParsedLabel) + auto result = libcdoc::Recipient::parseLabel(label); + for (const auto& [key, value] : ExpectedParsedLabel) { - map::const_iterator result_pair = result.find(expected_pair.first); - BOOST_TEST((result_pair != result.cend()), "Field " << expected_pair.first << " presented"); + auto result_pair = result.find(key); + BOOST_TEST((result_pair != result.cend()), "Field " << key << " presented"); if (result_pair != result.end()) { - BOOST_CHECK_EQUAL(result_pair->second, expected_pair.second); + BOOST_CHECK_EQUAL(result_pair->second, value); } } }