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