Loading...
Searching...
No Matches
ReadconDbMirror.cpp
Go to the documentation of this file.
1/*
2** This file is part of eOn.
3**
4** SPDX-License-Identifier: BSD-3-Clause
5**
6** Copyright (c) 2010--present, eOn Development Team
7** All rights reserved.
8**
9** Repo:
10** https://github.com/TheochemUI/eOn
11*/
12#include "ReadconDbMirror.h"
13
14#include <cstdint>
15#include <filesystem>
16#include <fstream>
17#include <mutex>
18#include <sstream>
19#include <string>
20#include <unordered_map>
21
22#if !defined(_WIN32)
23#include <dlfcn.h>
24#endif
25
26namespace eonc::io {
27namespace {
28
29constexpr std::uint64_t kFnvOffset = 14695981039346656037ull;
30constexpr std::uint64_t kFnvPrime = 1099511628211ull;
31
32std::uint64_t fnv1a(const std::string &bytes) {
33 std::uint64_t h = kFnvOffset;
34 for (unsigned char c : bytes) {
35 h ^= static_cast<std::uint64_t>(c);
36 h *= kFnvPrime;
37 }
38 return h == 0 ? 1 : h;
39}
40
41std::filesystem::path corpus_dir(const std::filesystem::path &con_path) {
42 namespace fs = std::filesystem;
43 std::error_code ec;
44 fs::path cur = fs::weakly_canonical(con_path, ec);
45 if (ec) {
46 cur = fs::absolute(con_path);
47 }
48 cur = cur.parent_path();
49 for (int i = 0; i < 8; ++i) {
50 if (fs::is_regular_file(cur / "config.ini")) {
51 return cur / "readcon.db";
52 }
53 const fs::path parent = cur.parent_path();
54 if (parent == cur) {
55 break;
56 }
57 cur = parent;
58 }
59 fs::path beside = fs::weakly_canonical(con_path, ec);
60 if (ec) {
61 beside = fs::absolute(con_path);
62 }
63 return beside.parent_path() / "readcon.db";
64}
65
66#if !defined(_WIN32)
67using OpenFn = int (*)(const char *, std::size_t *);
68using AppendFn = int (*)(std::size_t, std::uint64_t, const char *, const char *,
69 std::uint32_t *);
70
71struct Api {
72 void *lib = nullptr;
73 OpenFn open = nullptr;
74 AppendFn append_str = nullptr;
75 bool missing = false;
76};
77
78Api &api() {
79 static Api out;
80 if (out.lib != nullptr || out.missing) {
81 return out;
82 }
83 const char *names[] = {"libreadcon_db.so", "libreadcon_db.so.0",
84 "libreadcon_db.dylib"};
85 for (const char *name : names) {
86 out.lib = dlopen(name, RTLD_LAZY | RTLD_LOCAL);
87 if (out.lib != nullptr) {
88 break;
89 }
90 }
91 if (out.lib == nullptr) {
92 out.missing = true;
93 return out;
94 }
95 out.open = reinterpret_cast<OpenFn>(dlsym(out.lib, "rkrdb_open"));
96 out.append_str =
97 reinterpret_cast<AppendFn>(dlsym(out.lib, "rkrdb_append_trajectory_str"));
98 if (out.open == nullptr || out.append_str == nullptr) {
99 dlclose(out.lib);
100 out.lib = nullptr;
101 out.missing = true;
102 }
103 return out;
104}
105
106std::mutex &handles_mu() {
107 static std::mutex mu;
108 return mu;
109}
110
111std::unordered_map<std::string, std::size_t> &handles() {
112 static std::unordered_map<std::string, std::size_t> map;
113 return map;
114}
115
116std::size_t corpus_handle(const std::filesystem::path &dir) {
117 Api &fns = api();
118 if (fns.missing) {
119 return static_cast<std::size_t>(-1);
120 }
121 const std::string key = dir.string();
122 std::lock_guard<std::mutex> guard(handles_mu());
123 const auto found = handles().find(key);
124 if (found != handles().end()) {
125 return found->second;
126 }
127 std::size_t id = 0;
128 if (fns.open(key.c_str(), &id) != 0) {
129 return static_cast<std::size_t>(-1);
130 }
131 handles().emplace(key, id);
132 return id;
133}
134#endif
135
136} // namespace
137
138void mirror_con_corpus(const std::string &path) {
139#if !defined(_WIN32)
140 namespace fs = std::filesystem;
141 std::error_code ec;
142 if (!fs::is_regular_file(path, ec) || ec) {
143 return;
144 }
145 std::ifstream in(path);
146 if (!in) {
147 return;
148 }
149 std::ostringstream buf;
150 buf << in.rdbuf();
151 const std::string text = buf.str();
152 if (text.find_first_not_of(" \t\r\n") == std::string::npos) {
153 return;
154 }
155 fs::path canonical = fs::weakly_canonical(path, ec);
156 if (ec) {
157 canonical = fs::absolute(path);
158 }
159 const std::string resolved = canonical.string();
160 const std::size_t id = corpus_handle(corpus_dir(canonical));
161 if (id == static_cast<std::size_t>(-1)) {
162 return;
163 }
164 const std::uint64_t tid = fnv1a(resolved + '\0' + text);
165 std::uint32_t nframes = 0;
166 api().append_str(id, tid, text.c_str(), resolved.c_str(), &nframes);
167#else
168 (void)path;
169#endif
170}
171
172} // namespace eonc::io
void mirror_con_corpus(const std::string &path)
Copy a con file into the run readcon-db corpus when libreadcon_db loads.