| Ed Tanous | 10c5765 | 2025-09-30 10:24:57 -0700 | [diff] [blame] | 1 | #include "gzip_utils.hpp" | 
|  | 2 |  | 
|  | 3 | #include <libxml/parser.h> | 
|  | 4 | #include <libxml/xpath.h> | 
|  | 5 | #include <unistd.h> | 
|  | 6 | #include <zlib.h> | 
|  | 7 |  | 
|  | 8 | #include <optional> | 
|  | 9 | #include <span> | 
|  | 10 | #include <string> | 
|  | 11 | #include <vector> | 
|  | 12 |  | 
|  | 13 | std::optional<std::string> gzipInflate(std::span<uint8_t> compressedBytes) | 
|  | 14 | { | 
|  | 15 | std::string uncompressedBytes; | 
|  | 16 | if (compressedBytes.empty()) | 
|  | 17 | { | 
|  | 18 | return std::nullopt; | 
|  | 19 | } | 
|  | 20 |  | 
|  | 21 | z_stream strm{ | 
|  | 22 |  | 
|  | 23 | }; | 
|  | 24 | strm.next_in = (Bytef*)compressedBytes.data(); | 
|  | 25 | strm.avail_in = static_cast<uInt>(compressedBytes.size()); | 
|  | 26 | strm.total_out = 0; | 
|  | 27 |  | 
|  | 28 | if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) | 
|  | 29 | { | 
|  | 30 | return std::nullopt; | 
|  | 31 | } | 
|  | 32 |  | 
|  | 33 | while (strm.avail_in > 0) | 
|  | 34 | { | 
|  | 35 | constexpr size_t chunkSize = 1024; | 
|  | 36 | uncompressedBytes.resize(uncompressedBytes.size() + chunkSize); | 
|  | 37 | strm.next_out = | 
|  | 38 | std::bit_cast<Bytef*>(uncompressedBytes.end() - chunkSize); | 
|  | 39 | strm.avail_out = chunkSize; | 
|  | 40 |  | 
|  | 41 | // Inflate another chunk. | 
|  | 42 | int err = inflate(&strm, Z_SYNC_FLUSH); | 
|  | 43 | if (err == Z_STREAM_END) | 
|  | 44 | { | 
|  | 45 | break; | 
|  | 46 | } | 
|  | 47 | if (err != Z_OK) | 
|  | 48 | { | 
|  | 49 | return std::nullopt; | 
|  | 50 | } | 
|  | 51 | } | 
|  | 52 |  | 
|  | 53 | if (inflateEnd(&strm) != Z_OK) | 
|  | 54 | { | 
|  | 55 | return std::nullopt; | 
|  | 56 | } | 
|  | 57 | uncompressedBytes.resize(strm.total_out); | 
|  | 58 |  | 
|  | 59 | return {uncompressedBytes}; | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | static std::vector<std::string> xpathText(xmlDocPtr doc, const char* xp) | 
|  | 63 | { | 
|  | 64 | std::vector<std::string> val; | 
|  | 65 | xmlXPathContextPtr ctx = xmlXPathNewContext(doc); | 
|  | 66 | if (ctx == nullptr) | 
|  | 67 | { | 
|  | 68 | return val; | 
|  | 69 | } | 
|  | 70 | const unsigned char* xpptr = std::bit_cast<const unsigned char*>(xp); | 
|  | 71 | xmlXPathObjectPtr obj = xmlXPathEvalExpression(xpptr, ctx); | 
|  | 72 | if (obj != nullptr) | 
|  | 73 | { | 
|  | 74 | if (obj->type == XPATH_NODESET && obj->nodesetval != nullptr) | 
|  | 75 | { | 
|  | 76 | xmlNodeSetPtr nodeTab = obj->nodesetval; | 
|  | 77 | size_t nodeNr = static_cast<size_t>(nodeTab->nodeNr); | 
|  | 78 | std::span<xmlNodePtr> nodes{nodeTab->nodeTab, nodeNr}; | 
|  | 79 | for (xmlNodePtr node : nodes) | 
|  | 80 | { | 
|  | 81 | unsigned char* keyword = xmlNodeGetContent(node); | 
|  | 82 | val.emplace_back(std::bit_cast<const char*>(keyword)); | 
|  | 83 | xmlFree(keyword); | 
|  | 84 | } | 
|  | 85 | } | 
|  | 86 | } | 
|  | 87 |  | 
|  | 88 | xmlXPathFreeObject(obj); | 
|  | 89 | xmlXPathFreeContext(ctx); | 
|  | 90 | return val; | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | std::vector<std::string> getNodeFromXml(std::string_view xml, | 
|  | 94 | const char* nodeName) | 
|  | 95 | { | 
|  | 96 | std::vector<std::string> node; | 
|  | 97 | if (xml.empty()) | 
|  | 98 | { | 
|  | 99 | return node; | 
|  | 100 | } | 
|  | 101 | xmlDocPtr doc = xmlReadMemory( | 
|  | 102 | xml.data(), xml.size(), nullptr, nullptr, | 
|  | 103 | XML_PARSE_RECOVER | XML_PARSE_NONET | XML_PARSE_NOWARNING); | 
|  | 104 | if (doc == nullptr) | 
|  | 105 | { | 
|  | 106 | return {}; | 
|  | 107 | } | 
|  | 108 | node = xpathText(doc, nodeName); | 
|  | 109 | xmlFreeDoc(doc); | 
|  | 110 | return node; | 
|  | 111 | } |