25#ifndef BES_VLSA_UTIL_H
26#define BES_VLSA_UTIL_H
34#define PUGIXML_NO_XPATH
35#define PUGIXML_HEADER_ONLY
38#include <libdap/XMLWriter.h>
41#include "DmrppArray.h"
42#include "DmrppNames.h"
44#include "BESInternalError.h"
47#define prolog std::string("vlsa_util::").append(__func__).append("() - ")
53const auto VLSA =
"vlsa";
54const auto VLSA_VERBOSE =
"vlsa:verbose";
55const auto VLSA_VALUE_COMPRESSION_THRESHOLD = 512;
62string zlib_msg(
int retval)
79 msg =
"Z_STREAM_ERROR";
91 msg =
"Z_VERSION_ERROR";
94 msg =
"UNKNOWN ZLIB RETURN CODE";
100constexpr unsigned int W = 10;
101constexpr unsigned int R = 8;
111std::string encode(
const std::string &source_string) {
112 BESDEBUG(VLSA, prolog <<
"BEGIN\n");
116 BESDEBUG(VLSA, prolog <<
" source_string.size(): " << source_string.size() <<
" bytes. \n");
117 BESDEBUG(VLSA_VERBOSE,
"source_string: " << source_string <<
"\n");
119 uLong ssize = source_string.size();
120 uLongf csize = source_string.size();
121 vector<Bytef> compressed_src;
122 compressed_src.resize(source_string.size());
124 int retval = compress(compressed_src.data(), &csize, (Bytef *)source_string.data(), ssize);
125 BESDEBUG(VLSA, prolog <<
" compress() retval: " << setw(W) << retval
126 <<
" (" << zlib_msg(retval) <<
")\n");
130 msg <<
"Failed to compress source string. \n";
131 msg <<
" compress() retval: " << retval <<
" (" << zlib_msg(retval) <<
")\n";
132 msg <<
" ssize: " << ssize <<
"\n";
133 msg <<
" csize: " << csize <<
"\n";
134 throw BESInternalError(msg.str(), __FILE__, __LINE__);
137 BESDEBUG(VLSA, prolog <<
" source len: " << setw(W) << source_string.size() <<
"\n");
138 BESDEBUG(VLSA, prolog <<
" compressed source binary: " << setw(W) << compressed_src.size() <<
139 " src:csb=" << setw(R) << ((
double) source_string.size()) / ((
double) compressed_src.size()) <<
"\n");
141 BESDEBUG(VLSA, prolog <<
"END\n");
142 return { base64::Base64::encode(compressed_src.data(), (
int)csize) };
151string decode(
const string &encoded, uint64_t expected_size) {
152 BESDEBUG(VLSA, prolog <<
"BEGIN\n");
153 BESDEBUG(VLSA, prolog <<
" expected_size: " << setw(W) << expected_size <<
"\n");
154 BESDEBUG(VLSA, prolog <<
" encoded.size(): " << setw(W) << encoded.size() <<
"\n");
156 string decoded_string;
157 std::vector<u_int8_t> decoded = base64::Base64::decode(encoded);
158 BESDEBUG(VLSA, prolog <<
" (base64) decoded.size(): " << setw(W) << decoded.size() <<
"\n");
160 vector<Bytef> result_bytes;
161 uLongf result_size = expected_size;
163 BESDEBUG(VLSA, prolog <<
" result_size: " << setw(W) << result_size <<
"\n");
165 result_bytes.resize(result_size);
166 BESDEBUG(VLSA, prolog <<
" result_bytes.size(): " << setw(W) << result_bytes.size() <<
"\n");
168 int retval = uncompress(result_bytes.data(), &result_size, decoded.data(), decoded.size());
171 msg << prolog <<
"Failed to decompress payload. \n";
172 msg <<
" retval: " << retval <<
" (" << zlib_msg(retval) <<
")\n";
173 msg <<
" result_size: " << result_size <<
"\n";
174 msg <<
" expected_size: " << expected_size <<
"\n";
175 msg <<
" result_bytes.size(): " << result_bytes.size() <<
"\n";
177 throw BESInternalError(msg.str(), __FILE__, __LINE__);
179 BESDEBUG(VLSA, prolog <<
" uncompress() result_size: " << setw(W) << result_size <<
"\n");
180 BESDEBUG(VLSA, prolog <<
" expected_size: " << setw(W) << expected_size <<
"\n");
182 if(result_bytes.size() != expected_size){
184 msg << prolog <<
"Result size " << result_bytes.size() <<
" does not match expected size " << expected_size;
185 throw BESInternalError(msg.str(), __FILE__, __LINE__);
187 BESDEBUG(VLSA, prolog <<
"END\n");
188 return {result_bytes.begin(), result_bytes.end()};
202void write_value(libdap::XMLWriter &xml,
const std::string &value, uint64_t dup_count)
204 if (xmlTextWriterStartElement(xml.get_writer(), (
const xmlChar *) DMRPP_VLSA_VALUE_ELEMENT) < 0) {
206 msg << prolog <<
"Could not begin '" << DMRPP_VLSA_VALUE_ELEMENT <<
"' element.";
207 throw BESInternalError( msg.str(), __FILE__, __LINE__);
210 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *) DMRPP_VLSA_VALUE_COUNT_ATTR,
211 (
const xmlChar *) to_string(dup_count).c_str()) < 0) {
213 msg << prolog <<
"Could not write '" <<
"c" <<
"' (size) attribute.";
214 throw BESInternalError( msg.str(), __FILE__, __LINE__);
218 if(value.size() > VLSA_VALUE_COMPRESSION_THRESHOLD) {
220 if (xmlTextWriterWriteAttribute(xml.get_writer(), (
const xmlChar *) DMRPP_VLSA_VALUE_SIZE_ATTR,
221 (
const xmlChar *) to_string(value.size()).c_str()) < 0) {
223 msg << prolog <<
"Could not write '" << DMRPP_VLSA_VALUE_SIZE_ATTR <<
"' (size) attribute.";
224 throw BESInternalError( msg.str(), __FILE__, __LINE__);
226 string encoded = encode(value);
228 if (xmlTextWriterWriteString(xml.get_writer(), (
const xmlChar *) encoded.c_str()) < 0) {
230 msg << prolog <<
"Could not write text into element '" << DMRPP_VLSA_VALUE_ELEMENT <<
"'";
231 throw BESInternalError( msg.str(), __FILE__, __LINE__);
235 if (xmlTextWriterWriteString(xml.get_writer(), (
const xmlChar *) value.c_str()) < 0) {
237 msg << prolog <<
"Could not write text into element '"<< DMRPP_VLSA_VALUE_ELEMENT <<
"'";
238 throw BESInternalError( msg.str(), __FILE__, __LINE__);
242 if (xmlTextWriterEndElement(xml.get_writer()) < 0) {
244 msg << prolog <<
"Could not end '" << DMRPP_VLSA_VALUE_ELEMENT <<
"' element";
245 throw BESInternalError( msg.str(), __FILE__, __LINE__);
249void write(libdap::XMLWriter &xml,
const vector<string> &values)
251 if (xmlTextWriterStartElement(xml.get_writer(), (
const xmlChar *)DMRPP_VLSA_ELEMENT) < 0) {
253 msg << prolog <<
"Could not write " << DMRPP_VLSA_VALUE_ELEMENT <<
" element";
254 throw BESInternalError( msg.str(), __FILE__, __LINE__);
258 bool not_first =
false;
259 uint64_t dup_count = 1;
260 for(
const auto &value : values) {
262 if(value == last_value) {
266 BESDEBUG(VLSA, prolog <<
"value: '" << value <<
"' dup_count: " << dup_count << endl);
267 vlsa::write_value(xml, last_value, dup_count);
274 BESDEBUG(VLSA, prolog <<
"last_value: '" << last_value <<
"' dup_count: " << dup_count << endl);
275 write_value(xml,last_value, dup_count);
278 if (xmlTextWriterEndElement(xml.get_writer()) < 0) {
280 msg << prolog <<
"Could not end " << DMRPP_VLSA_VALUE_ELEMENT <<
" element";
281 throw BESInternalError( msg.str(), __FILE__, __LINE__);
286void write(libdap::XMLWriter &xml, dmrpp::DmrppArray &a)
288 write(xml, a.get_str());
296std::string read_value(
const pugi::xml_node &v)
298 static string vlsa_value_element_name(DMRPP_VLSA_VALUE_ELEMENT);
301 if (v.name() == vlsa_value_element_name ) {
305 auto size_attr = v.attribute(DMRPP_VLSA_VALUE_SIZE_ATTR);
307 uint64_t value_size = stoull(size_attr.value());
308 value = decode(v.child_value(), value_size);
310 value = v.child_value();
316void read(
const pugi::xml_node &vlsa_element, vector<string> &entries)
318 static string vlsa_element_name(DMRPP_VLSA_ELEMENT);
320 if (vlsa_element.name() != vlsa_element_name ) {
return; }
323 for (
auto v = vlsa_element.child(DMRPP_VLSA_VALUE_ELEMENT); v; v = v.next_sibling()) {
324 string value = read_value(v);
327 pugi::xml_attribute c_attr = v.attribute(DMRPP_VLSA_VALUE_COUNT_ATTR);
329 count = stoull(c_attr.value());
331 BESDEBUG(VLSA, prolog <<
"value: '" << value <<
"' count: " << count <<
"\n");
332 for(uint64_t i=0; i<count ;i++){
334 entries.push_back(value);