Files
fluxengine/scripts/protoencode.cc
David Given df4d27eefe Better support for repeated fields in the config language. Add a helper
for showing all config fields in a proto.
2025-08-10 22:22:58 +01:00

156 lines
3.4 KiB
C++

#include <stdio.h>
#include <google/protobuf/text_format.h>
#include <google/protobuf/io/zero_copy_stream_impl.h>
#include <fstream>
#include "fmt/format.h"
#include "lib/core/globals.h"
#include "tests/testproto.pb.h"
#include "lib/config/config.pb.h"
#include <sstream>
#include <locale>
const std::string protoname = STRINGIFY(PROTO);
static uint32_t readu8(std::string::iterator& it, std::string::iterator end)
{
int len;
uint32_t c = *it++;
if (c < 0x80)
{
/* Do nothing! */
len = 0;
}
else if (c < 0xc0)
{
/* Invalid character */
c = -1;
len = 0;
}
else if (c < 0xe0)
{
/* One trailing byte */
c &= 0x1f;
len = 1;
}
else if (c < 0xf0)
{
/* Two trailing bytes */
c &= 0x0f;
len = 2;
}
else if (c < 0xf8)
{
/* Three trailing bytes */
c &= 0x07;
len = 3;
}
else if (c < 0xfc)
{
/* Four trailing bytes */
c &= 0x03;
len = 4;
}
else
{
/* Five trailing bytes */
c &= 0x01;
len = 5;
}
while (len)
{
if (it == end)
break;
uint8_t d = *it++;
c <<= 6;
c += d & 0x3f;
}
return c;
}
int main(int argc, const char* argv[])
{
PROTO message;
std::ifstream input(argv[1]);
if (!input)
{
perror("couldn't open input file");
exit(1);
}
std::stringstream ss;
std::string s;
while (std::getline(input, s, '\n'))
{
if (s == "<<<")
{
while (std::getline(input, s, '\n'))
{
if (s == ">>>")
break;
ss << '"';
auto it = s.begin();
for (;;)
{
uint32_t u = readu8(it, s.end());
if (!u)
break;
ss << fmt::format("\\u{:04x}", u);
}
ss << "\\n\"\n";
}
}
else
ss << s << '\n';
}
if (!google::protobuf::TextFormat::ParseFromString(ss.str(), &message))
{
fprintf(stderr, "cannot parse text proto: %s\n", argv[1]);
exit(1);
}
std::ofstream output(argv[2]);
if (!output)
{
perror("couldn't open output file");
exit(1);
}
auto data = message.SerializeAsString();
auto name = argv[3];
output << "#include \"lib/core/globals.h\"\n"
<< "#include \"lib/config/proto.h\"\n"
<< "#include \"" STRINGIFY(INCLUDE) "\"\n"
<< "#include <string_view>\n"
<< "static const uint8_t " << name << "_rawData[] = {";
int count = 0;
for (char c : data)
{
if (count == 0)
output << "\n\t";
else
output << ' ';
output << fmt::format("0x{:02x},", (unsigned char)c);
count = (count + 1) & 7;
}
output << "\n};\n";
output << "extern const std::string_view " << name << "_data;\n";
output << "const std::string_view " << name
<< "_data = std::string_view((const char*)" << name << "_rawData, "
<< data.size() << ");\n";
output << "extern const " << protoname << " " << name << ";\n";
output << "const " << protoname << " " << name << " = parseProtoBytes<"
<< protoname << ">(" << argv[3] << "_data);\n";
return 0;
}