xref: /openbmc/entity-manager/src/fru_device/gzip_utils.cpp (revision 10c57656f31ed1c20778425b6090cfae7d788ab6)
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 
gzipInflate(std::span<uint8_t> compressedBytes)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 
xpathText(xmlDocPtr doc,const char * xp)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 
getNodeFromXml(std::string_view xml,const char * nodeName)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