| 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 | } |