Skip to content

Instantly share code, notes, and snippets.

@adamkewley
Created November 13, 2024 19:11
Show Gist options
  • Save adamkewley/ea5ede7f675ce5e1b834d0887f27bde4 to your computer and use it in GitHub Desktop.
Save adamkewley/ea5ede7f675ce5e1b834d0887f27bde4 to your computer and use it in GitHub Desktop.
#include <oscar/oscar.h>
#include <charconv>
#include <filesystem>
#include <fstream>
#include <regex>
#include <sstream>
#include <stdexcept>
#include <string_view>
#include <span>
using namespace osc;
namespace
{
struct State final {
std::regex data_array_opening_pattern{R"(<DataArray type="Float32"[^>]+>)"};
std::regex data_array_closing_pattern{R"(</DataArray>)"};
};
std::string slurp(const std::filesystem::path& p)
{
std::ifstream f{p, std::ios_base::binary};
f.exceptions(std::istream::failbit | std::istream::badbit);
std::string rv;
// reserve memory
f.seekg(0, std::ios::end);
if (const auto pos = f.tellg(); pos > 0) {
rv.reserve(static_cast<size_t>(pos));
}
f.seekg(0, std::ios::beg);
// then assign to it via an iterator
rv.assign((std::istreambuf_iterator<char>{f}), std::istreambuf_iterator<char>{});
return rv;
}
void write_to_file(const std::filesystem::path& p, std::string_view sv)
{
std::ofstream f{p, std::ios_base::binary};
f.exceptions(std::istream::failbit | std::istream::badbit);
f << sv;
}
void emit_reparsed_dataarray_content(std::string_view sv, std::stringstream& out)
{
while (not sv.empty()) {
if (std::isspace(sv.front())) {
// skip whitespace
out << sv.front();
sv = sv.substr(1);
}
else {
// parse as floating-point number
float value = 0.0f;
std::from_chars_result fromchars_result = std::from_chars(sv.data(), sv.data() + sv.size(), value);
if (fromchars_result.ec != std::errc{}) {
throw std::runtime_error{"parsing error"};
}
std::array<char, 128> buffer{};
std::to_chars(buffer.data(), buffer.data() + buffer.size(), value);
out << buffer.data();
sv = sv.substr(fromchars_result.ptr - sv.data());
}
}
}
void process_vtp(const State& s, const std::filesystem::path& vtp_path)
{
log_info("processing %s", vtp_path.string().c_str());
std::stringstream out;
const std::string content = slurp(vtp_path);
int count = 0;
for (auto it = std::sregex_iterator{content.begin(), content.end(), s.data_array_opening_pattern}; it != std::sregex_iterator{}; ++it) {
const std::smatch opening_tag_match = *it;
std::smatch closing_tag_match;
if (not std::regex_search(opening_tag_match.suffix().first, opening_tag_match.suffix().second, closing_tag_match, s.data_array_closing_pattern)) {
throw std::runtime_error{"cannot find closing tag"};
}
// this is the bit that needs to be replaced
std::string_view content_span{&*opening_tag_match.suffix().first, &*&*closing_tag_match[0].first};
out << opening_tag_match.prefix();
out << opening_tag_match.str();
emit_reparsed_dataarray_content(content_span, out);
out << closing_tag_match.str();
out << closing_tag_match.suffix();
++count;
}
if (count != 1) {
throw std::runtime_error{"unexpected number of <DataArray> elements"};
}
write_to_file(vtp_path, std::move(out).str());
}
}
int main(int argc, char** argv)
{
try {
State state;
for (int i = 1; i < argc; ++i) {
process_vtp(state, argv[i]);
}
return 0;
}
catch (std::exception& ex) {
std::cerr << ex.what() << std::endl;
throw;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment