blob: 430fb913e53d8007b279b7c9f867e9f59b686326 [file] [log] [blame]
#include "gzip_utils.hpp"
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include <unistd.h>
#include <zlib.h>
#include <optional>
#include <span>
#include <string>
#include <vector>
std::optional<std::string> gzipInflate(std::span<uint8_t> compressedBytes)
{
std::string uncompressedBytes;
if (compressedBytes.empty())
{
return std::nullopt;
}
z_stream strm{
};
strm.next_in = (Bytef*)compressedBytes.data();
strm.avail_in = static_cast<uInt>(compressedBytes.size());
strm.total_out = 0;
if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK)
{
return std::nullopt;
}
while (strm.avail_in > 0)
{
constexpr size_t chunkSize = 1024;
uncompressedBytes.resize(uncompressedBytes.size() + chunkSize);
strm.next_out =
std::bit_cast<Bytef*>(uncompressedBytes.end() - chunkSize);
strm.avail_out = chunkSize;
// Inflate another chunk.
int err = inflate(&strm, Z_SYNC_FLUSH);
if (err == Z_STREAM_END)
{
break;
}
if (err != Z_OK)
{
return std::nullopt;
}
}
if (inflateEnd(&strm) != Z_OK)
{
return std::nullopt;
}
uncompressedBytes.resize(strm.total_out);
return {uncompressedBytes};
}
static std::vector<std::string> xpathText(xmlDocPtr doc, const char* xp)
{
std::vector<std::string> val;
xmlXPathContextPtr ctx = xmlXPathNewContext(doc);
if (ctx == nullptr)
{
return val;
}
const unsigned char* xpptr = std::bit_cast<const unsigned char*>(xp);
xmlXPathObjectPtr obj = xmlXPathEvalExpression(xpptr, ctx);
if (obj != nullptr)
{
if (obj->type == XPATH_NODESET && obj->nodesetval != nullptr)
{
xmlNodeSetPtr nodeTab = obj->nodesetval;
size_t nodeNr = static_cast<size_t>(nodeTab->nodeNr);
std::span<xmlNodePtr> nodes{nodeTab->nodeTab, nodeNr};
for (xmlNodePtr node : nodes)
{
unsigned char* keyword = xmlNodeGetContent(node);
val.emplace_back(std::bit_cast<const char*>(keyword));
xmlFree(keyword);
}
}
}
xmlXPathFreeObject(obj);
xmlXPathFreeContext(ctx);
return val;
}
std::vector<std::string> getNodeFromXml(std::string_view xml,
const char* nodeName)
{
std::vector<std::string> node;
if (xml.empty())
{
return node;
}
xmlDocPtr doc = xmlReadMemory(
xml.data(), xml.size(), nullptr, nullptr,
XML_PARSE_RECOVER | XML_PARSE_NONET | XML_PARSE_NOWARNING);
if (doc == nullptr)
{
return {};
}
node = xpathText(doc, nodeName);
xmlFreeDoc(doc);
return node;
}