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