Use actual list of regulatory domains for wifi dialog.
This commit is contained in:
Vendored
+2
-1
@@ -137,7 +137,8 @@
|
||||
//"[json_variants]" // subtest of your choice, or none to run all of the tests.
|
||||
//"[inverting_mutex_test]"
|
||||
// "[utf8_to_utf32]"
|
||||
"[pipedal_alsa_test]"
|
||||
//"[pipedal_alsa_test]"
|
||||
"[wifi_channels_test]"
|
||||
],
|
||||
|
||||
"stopAtEntry": false,
|
||||
|
||||
+233
-198
@@ -18,6 +18,7 @@
|
||||
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
#include "RegDb.hpp"
|
||||
|
||||
#include "ss.hpp"
|
||||
#include <fstream>
|
||||
#include <filesystem>
|
||||
@@ -30,8 +31,12 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include "json_variant.hpp"
|
||||
#include "json.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#define REGDB_MAGIC 0x52474442
|
||||
#define REGDB_VERSION 19 // pre-bookwork
|
||||
#define REGDB_VERSION_2 20 // bookworm and later.
|
||||
@@ -40,7 +45,7 @@ using namespace pipedal;
|
||||
using namespace std;
|
||||
|
||||
static std::unique_ptr<RegDb> g_Instance;
|
||||
RegDb&RegDb::GetInstance()
|
||||
RegDb &RegDb::GetInstance()
|
||||
{
|
||||
if (!g_Instance)
|
||||
{
|
||||
@@ -49,9 +54,9 @@ RegDb&RegDb::GetInstance()
|
||||
return *g_Instance;
|
||||
}
|
||||
|
||||
const WifiRegulations& RegDb::getWifiRegulations(const std::string&countryIso3661) const
|
||||
const WifiRegulations &RegDb::getWifiRegulations(const std::string &countryIso3661) const
|
||||
{
|
||||
for (const auto ®ulation: this->regulations)
|
||||
for (const auto ®ulation : this->regulations)
|
||||
{
|
||||
if (regulation.reg_alpha2 == countryIso3661)
|
||||
{
|
||||
@@ -61,28 +66,31 @@ const WifiRegulations& RegDb::getWifiRegulations(const std::string&countryIso366
|
||||
throw std::runtime_error("Invalid country code.");
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
T NlSwap(T value)
|
||||
{
|
||||
if constexpr (std::endian::native == std::endian::big)
|
||||
{
|
||||
return value;
|
||||
} else {
|
||||
auto value_rep = std::bit_cast<std::array<std::uint8_t,sizeof(T)>,T >(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
auto value_rep = std::bit_cast<std::array<std::uint8_t, sizeof(T)>, T>(value);
|
||||
std::ranges::reverse(value_rep);
|
||||
return std::bit_cast<T>(value_rep);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class BigEndian {
|
||||
class BigEndian
|
||||
{
|
||||
public:
|
||||
BigEndian(): m_value(0) { }
|
||||
explicit BigEndian(T value): m_value(NlSwap(value)) {}
|
||||
T value() const { return NlSwap(m_value);}
|
||||
bool operator==(const BigEndian<T>&other) const { return m_value == other.m_value; }
|
||||
BigEndian() : m_value(0) {}
|
||||
explicit BigEndian(T value) : m_value(NlSwap(value)) {}
|
||||
T value() const { return NlSwap(m_value); }
|
||||
bool operator==(const BigEndian<T> &other) const { return m_value == other.m_value; }
|
||||
explicit operator bool() const { return m_value != 0; }
|
||||
|
||||
private:
|
||||
T m_value;
|
||||
};
|
||||
@@ -141,17 +149,15 @@ struct RulesCollection19
|
||||
{
|
||||
this->ruleCount = NlSwap(this->ruleCount);
|
||||
}
|
||||
Rule*getRule(
|
||||
Rule *getRule(
|
||||
uint32_t nRule,
|
||||
char *pData
|
||||
)
|
||||
char *pData)
|
||||
{
|
||||
uint32_t ruleOffset = NlSwap(ruleOffsets[nRule]);
|
||||
return (Rule*)(pData+ruleOffset);
|
||||
}
|
||||
return (Rule *)(pData + ruleOffset);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
struct FrequencyRange
|
||||
{
|
||||
uint32_t startFrequency; // in khz.
|
||||
@@ -203,7 +209,7 @@ RegDb::RegDb()
|
||||
{
|
||||
}
|
||||
RegDb::RegDb(const std::filesystem::path &path)
|
||||
: pData(nullptr)
|
||||
: pData(nullptr)
|
||||
{
|
||||
ifstream f(path);
|
||||
if (!f.is_open())
|
||||
@@ -255,23 +261,22 @@ void RegDb::Load19()
|
||||
{
|
||||
WifiRegulations wifiRegulations;
|
||||
|
||||
|
||||
CountryHeader countryHeader = pCountryHeader[i];
|
||||
countryHeader.toNs();
|
||||
wifiRegulations.reg_alpha2 = SS(countryHeader.alpha2[0] << countryHeader.alpha2[1]);
|
||||
wifiRegulations.reg_alpha2 = SS(countryHeader.alpha2[0] << countryHeader.alpha2[1]);
|
||||
wifiRegulations.dfs_region = (DfsRegion)(countryHeader.dfsRegion & 0x03);
|
||||
|
||||
RulesCollection19 *pRules = (RulesCollection19 *)(pData + countryHeader.rulesOffset);
|
||||
uint32_t ruleCount = NlSwap(pRules->ruleCount);
|
||||
for (uint32_t nRule = 0; nRule < ruleCount; ++nRule)
|
||||
{
|
||||
Rule *pRule = pRules->getRule(nRule,pData);
|
||||
{
|
||||
Rule *pRule = pRules->getRule(nRule, pData);
|
||||
Rule rule = *pRule;
|
||||
rule.toNs();
|
||||
|
||||
FrequencyRange fr = *(FrequencyRange *)(pData + rule.frequencyRangeOffset);
|
||||
fr.toNs();
|
||||
|
||||
|
||||
PowerRule pr = *(PowerRule *)(pData + rule.powerRuleOffset);
|
||||
pr.toNs();
|
||||
|
||||
@@ -291,7 +296,7 @@ void RegDb::Load19()
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// glue
|
||||
#define IEEE80211_NUM_ACS 4 // linux/ieee80211.h Number of hardware queues?
|
||||
#define IEEE80211_NUM_ACS 4 // linux/ieee80211.h Number of hardware queues?
|
||||
|
||||
#define __aligned(n)
|
||||
#define __packed
|
||||
@@ -305,16 +310,14 @@ using __be16 = BigEndian<uint16_t>;
|
||||
#define BIT(n) (1 << n)
|
||||
|
||||
template <typename T>
|
||||
T ALIGN(T value,int bits)
|
||||
T ALIGN(T value, int bits)
|
||||
{
|
||||
intptr_t v = (intptr_t)value;
|
||||
|
||||
intptr_t mask = (1 << bits)-1;
|
||||
intptr_t mask = (1 << bits) - 1;
|
||||
v = (v + mask) & (~mask);
|
||||
return (T)v;
|
||||
|
||||
}
|
||||
|
||||
|
||||
inline BigEndian<uint32_t> cpu_to_be32(uint32_t value)
|
||||
{
|
||||
@@ -326,196 +329,203 @@ inline BigEndian<uint16_t> cpu_to_be16(uint16_t value)
|
||||
return BigEndian<uint16_t>(value);
|
||||
}
|
||||
|
||||
|
||||
inline uint16_t be16_to_cpu(const BigEndian<uint16_t>&value)
|
||||
inline uint16_t be16_to_cpu(const BigEndian<uint16_t> &value)
|
||||
{
|
||||
return value.value();
|
||||
}
|
||||
inline uint32_t be32_to_cpu(const BigEndian<uint32_t>&value)
|
||||
inline uint32_t be32_to_cpu(const BigEndian<uint32_t> &value)
|
||||
{
|
||||
return value.value();
|
||||
}
|
||||
|
||||
bool regdb_has_valid_signature(const u8 *data, unsigned int size) { return true; }
|
||||
|
||||
#define offsetofend(TYPE,FIELD) ((uint32_t)(offsetof(TYPE,FIELD)+sizeof(((TYPE*)0)->FIELD)))
|
||||
#define offsetofend(TYPE, FIELD) ((uint32_t)(offsetof(TYPE, FIELD) + sizeof(((TYPE *)0)->FIELD)))
|
||||
#define ASSERT_RTNL() // in the original, assert that rtnl is not locked.
|
||||
|
||||
/////////////////////////
|
||||
/////////////////////////
|
||||
// shamelessly lifted from linux net/wireless/reg.c
|
||||
|
||||
struct fwdb_country {
|
||||
u8 alpha2[2];
|
||||
__be16 coll_ptr;
|
||||
/* this struct cannot be extended */
|
||||
struct fwdb_country
|
||||
{
|
||||
u8 alpha2[2];
|
||||
__be16 coll_ptr;
|
||||
/* this struct cannot be extended */
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct fwdb_collection {
|
||||
u8 len;
|
||||
u8 n_rules;
|
||||
u8 dfs_region;
|
||||
/* no optional data yet */
|
||||
/* aligned to 2, then followed by __be16 array of rule pointers */
|
||||
struct fwdb_collection
|
||||
{
|
||||
u8 len;
|
||||
u8 n_rules;
|
||||
u8 dfs_region;
|
||||
/* no optional data yet */
|
||||
/* aligned to 2, then followed by __be16 array of rule pointers */
|
||||
} __packed __aligned(4);
|
||||
|
||||
struct fwdb_header {
|
||||
__be32 magic;
|
||||
__be32 version;
|
||||
struct fwdb_country country[];
|
||||
struct fwdb_header
|
||||
{
|
||||
__be32 magic;
|
||||
__be32 version;
|
||||
struct fwdb_country country[];
|
||||
} __packed __aligned(4);
|
||||
|
||||
|
||||
enum fwdb_flags {
|
||||
FWDB_FLAG_NO_OFDM = BIT(0),
|
||||
FWDB_FLAG_NO_OUTDOOR = BIT(1),
|
||||
FWDB_FLAG_DFS = BIT(2),
|
||||
FWDB_FLAG_NO_IR = BIT(3),
|
||||
FWDB_FLAG_AUTO_BW = BIT(4),
|
||||
enum fwdb_flags
|
||||
{
|
||||
FWDB_FLAG_NO_OFDM = BIT(0),
|
||||
FWDB_FLAG_NO_OUTDOOR = BIT(1),
|
||||
FWDB_FLAG_DFS = BIT(2),
|
||||
FWDB_FLAG_NO_IR = BIT(3),
|
||||
FWDB_FLAG_AUTO_BW = BIT(4),
|
||||
};
|
||||
|
||||
struct fwdb_wmm_ac {
|
||||
u8 ecw;
|
||||
u8 aifsn;
|
||||
__be16 cot;
|
||||
struct fwdb_wmm_ac
|
||||
{
|
||||
u8 ecw;
|
||||
u8 aifsn;
|
||||
__be16 cot;
|
||||
} __packed;
|
||||
|
||||
struct fwdb_wmm_rule {
|
||||
struct fwdb_wmm_ac client[IEEE80211_NUM_ACS];
|
||||
struct fwdb_wmm_ac ap[IEEE80211_NUM_ACS];
|
||||
struct fwdb_wmm_rule
|
||||
{
|
||||
struct fwdb_wmm_ac client[IEEE80211_NUM_ACS];
|
||||
struct fwdb_wmm_ac ap[IEEE80211_NUM_ACS];
|
||||
} __packed;
|
||||
|
||||
struct fwdb_rule {
|
||||
u8 len;
|
||||
u8 flags;
|
||||
__be16 max_eirp;
|
||||
__be32 start, end, max_bw;
|
||||
/* start of optional data */
|
||||
__be16 cac_timeout;
|
||||
__be16 wmm_ptr;
|
||||
struct fwdb_rule
|
||||
{
|
||||
u8 len;
|
||||
u8 flags;
|
||||
__be16 max_eirp;
|
||||
__be32 start, end, max_bw;
|
||||
/* start of optional data */
|
||||
__be16 cac_timeout;
|
||||
__be16 wmm_ptr;
|
||||
} __packed __aligned(4);
|
||||
|
||||
#define FWDB_MAGIC 0x52474442
|
||||
#define FWDB_VERSION 20
|
||||
|
||||
|
||||
static int ecw2cw(int ecw)
|
||||
{
|
||||
return (1 << ecw) - 1;
|
||||
return (1 << ecw) - 1;
|
||||
}
|
||||
|
||||
static bool valid_wmm(struct fwdb_wmm_rule *rule)
|
||||
{
|
||||
struct fwdb_wmm_ac *ac = (struct fwdb_wmm_ac *)rule;
|
||||
int i;
|
||||
struct fwdb_wmm_ac *ac = (struct fwdb_wmm_ac *)rule;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < IEEE80211_NUM_ACS * 2; i++) {
|
||||
u16 cw_min = ecw2cw((ac[i].ecw & 0xf0) >> 4);
|
||||
u16 cw_max = ecw2cw(ac[i].ecw & 0x0f);
|
||||
u8 aifsn = ac[i].aifsn;
|
||||
for (i = 0; i < IEEE80211_NUM_ACS * 2; i++)
|
||||
{
|
||||
u16 cw_min = ecw2cw((ac[i].ecw & 0xf0) >> 4);
|
||||
u16 cw_max = ecw2cw(ac[i].ecw & 0x0f);
|
||||
u8 aifsn = ac[i].aifsn;
|
||||
|
||||
if (cw_min >= cw_max)
|
||||
return false;
|
||||
if (cw_min >= cw_max)
|
||||
return false;
|
||||
|
||||
if (aifsn < 1)
|
||||
return false;
|
||||
}
|
||||
if (aifsn < 1)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool valid_rule(const u8 *data, unsigned int size, u16 rule_ptr)
|
||||
{
|
||||
struct fwdb_rule *rule = (fwdb_rule *)(data + (rule_ptr << 2));
|
||||
struct fwdb_rule *rule = (fwdb_rule *)(data + (rule_ptr << 2));
|
||||
|
||||
if ((u8 *)rule + sizeof(rule->len) > data + size)
|
||||
return false;
|
||||
if ((u8 *)rule + sizeof(rule->len) > data + size)
|
||||
return false;
|
||||
|
||||
/* mandatory fields */
|
||||
if (rule->len < offsetofend(struct fwdb_rule, max_bw))
|
||||
return false;
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr)) {
|
||||
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
/* mandatory fields */
|
||||
if (rule->len < offsetofend(struct fwdb_rule, max_bw))
|
||||
return false;
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
{
|
||||
u32 wmm_ptr = be16_to_cpu(rule->wmm_ptr) << 2;
|
||||
struct fwdb_wmm_rule *wmm;
|
||||
|
||||
if (wmm_ptr + sizeof(struct fwdb_wmm_rule) > size)
|
||||
return false;
|
||||
if (wmm_ptr + sizeof(struct fwdb_wmm_rule) > size)
|
||||
return false;
|
||||
|
||||
wmm = (fwdb_wmm_rule *)(data + wmm_ptr);
|
||||
wmm = (fwdb_wmm_rule *)(data + wmm_ptr);
|
||||
|
||||
if (!valid_wmm(wmm))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
if (!valid_wmm(wmm))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool valid_country(const u8 *data, unsigned int size,
|
||||
const struct fwdb_country *country)
|
||||
const struct fwdb_country *country)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (struct fwdb_collection *)(data + ptr);
|
||||
__be16 *rules_ptr;
|
||||
unsigned int i;
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (struct fwdb_collection *)(data + ptr);
|
||||
__be16 *rules_ptr;
|
||||
unsigned int i;
|
||||
|
||||
/* make sure we can read len/n_rules */
|
||||
if ((u8 *)coll + offsetofend(typeof(*coll), n_rules) > data + size)
|
||||
return false;
|
||||
/* make sure we can read len/n_rules */
|
||||
if ((u8 *)coll + offsetofend(typeof(*coll), n_rules) > data + size)
|
||||
return false;
|
||||
|
||||
/* make sure base struct and all rules fit */
|
||||
if ((u8 *)coll + ALIGN(coll->len, 2) +
|
||||
(coll->n_rules * 2) > data + size)
|
||||
return false;
|
||||
/* make sure base struct and all rules fit */
|
||||
if ((u8 *)coll + ALIGN(coll->len, 2) +
|
||||
(coll->n_rules * 2) >
|
||||
data + size)
|
||||
return false;
|
||||
|
||||
/* mandatory fields must exist */
|
||||
if (coll->len < offsetofend(struct fwdb_collection, dfs_region))
|
||||
return false;
|
||||
/* mandatory fields must exist */
|
||||
if (coll->len < offsetofend(struct fwdb_collection, dfs_region))
|
||||
return false;
|
||||
|
||||
rules_ptr = (__be16 *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
rules_ptr = (__be16 *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
|
||||
for (i = 0; i < coll->n_rules; i++) {
|
||||
u16 rule_ptr = be16_to_cpu(rules_ptr[i]);
|
||||
for (i = 0; i < coll->n_rules; i++)
|
||||
{
|
||||
u16 rule_ptr = be16_to_cpu(rules_ptr[i]);
|
||||
|
||||
if (!valid_rule(data, size, rule_ptr))
|
||||
return false;
|
||||
}
|
||||
if (!valid_rule(data, size, rule_ptr))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static bool valid_regdb(const u8 *data, unsigned int size)
|
||||
{
|
||||
const struct fwdb_header *hdr = (fwdb_header *)data;
|
||||
const struct fwdb_country *country;
|
||||
const struct fwdb_header *hdr = (fwdb_header *)data;
|
||||
const struct fwdb_country *country;
|
||||
|
||||
if (size < sizeof(*hdr))
|
||||
return false;
|
||||
if (size < sizeof(*hdr))
|
||||
return false;
|
||||
|
||||
if (hdr->magic != cpu_to_be32(FWDB_MAGIC))
|
||||
return false;
|
||||
if (hdr->magic != cpu_to_be32(FWDB_MAGIC))
|
||||
return false;
|
||||
|
||||
if (hdr->version != cpu_to_be32(FWDB_VERSION))
|
||||
return false;
|
||||
if (hdr->version != cpu_to_be32(FWDB_VERSION))
|
||||
return false;
|
||||
|
||||
if (!regdb_has_valid_signature(data, size))
|
||||
return false;
|
||||
if (!regdb_has_valid_signature(data, size))
|
||||
return false;
|
||||
|
||||
country = &hdr->country[0];
|
||||
while ((u8 *)(country + 1) <= data + size) {
|
||||
if (!country->coll_ptr)
|
||||
break;
|
||||
if (!valid_country(data, size, country))
|
||||
return false;
|
||||
country++;
|
||||
}
|
||||
country = &hdr->country[0];
|
||||
while ((u8 *)(country + 1) <= data + size)
|
||||
{
|
||||
if (!country->coll_ptr)
|
||||
break;
|
||||
if (!valid_country(data, size, country))
|
||||
return false;
|
||||
country++;
|
||||
}
|
||||
|
||||
return true;
|
||||
return true;
|
||||
}
|
||||
|
||||
static void set_wmm_rule(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country,
|
||||
const struct fwdb_rule *rule,
|
||||
WifiRule*rrule)
|
||||
const struct fwdb_country *country,
|
||||
const struct fwdb_rule *rule,
|
||||
WifiRule *rrule)
|
||||
{
|
||||
// not implemented.
|
||||
return;
|
||||
@@ -528,11 +538,11 @@ static void set_wmm_rule(const struct fwdb_header *db,
|
||||
// wmm = (fwdb_wmm_rule *)((u8 *)db + wmm_ptr);
|
||||
|
||||
// if (!valid_wmm(wmm)) {
|
||||
// std::cout
|
||||
// std::cout
|
||||
// << "Invalid regulatory WMM rule "
|
||||
// << be32_to_cpu(rule->start)
|
||||
// << be32_to_cpu(rule->start)
|
||||
// << "-" << be32_to_cpu(rule->end)
|
||||
// << " in domain " << country->alpha2[0] << country->alpha2[1]
|
||||
// << " in domain " << country->alpha2[0] << country->alpha2[1]
|
||||
// << std::endl;
|
||||
// return;
|
||||
// }
|
||||
@@ -553,90 +563,115 @@ static void set_wmm_rule(const struct fwdb_header *db,
|
||||
// rrule->has_wmm = true;
|
||||
// }
|
||||
|
||||
|
||||
static WifiRegulations regdb_load_country(const struct fwdb_header *db,
|
||||
const struct fwdb_country *country)
|
||||
const struct fwdb_country *country)
|
||||
{
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (fwdb_collection *)((u8 *)db + ptr);
|
||||
unsigned int i;
|
||||
unsigned int ptr = be16_to_cpu(country->coll_ptr) << 2;
|
||||
struct fwdb_collection *coll = (fwdb_collection *)((u8 *)db + ptr);
|
||||
unsigned int i;
|
||||
|
||||
WifiRegulations wifiRegulations;
|
||||
|
||||
wifiRegulations.reg_alpha2 = SS(country->alpha2[0] << country->alpha2[1]);
|
||||
wifiRegulations.dfs_region = (DfsRegion)(coll->dfs_region);
|
||||
unsigned int nRules = coll->n_rules;
|
||||
wifiRegulations.reg_alpha2 = SS(country->alpha2[0] << country->alpha2[1]);
|
||||
wifiRegulations.dfs_region = (DfsRegion)(coll->dfs_region);
|
||||
unsigned int nRules = coll->n_rules;
|
||||
|
||||
for (i = 0; i < nRules; i++) {
|
||||
const __be16 *rules_ptr = (const __be16 *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
|
||||
struct fwdb_rule *rule = (fwdb_rule *)((u8 *)db + rule_ptr);
|
||||
for (i = 0; i < nRules; i++)
|
||||
{
|
||||
const __be16 *rules_ptr = (const __be16 *)((u8 *)coll + ALIGN(coll->len, 2));
|
||||
unsigned int rule_ptr = be16_to_cpu(rules_ptr[i]) << 2;
|
||||
struct fwdb_rule *rule = (fwdb_rule *)((u8 *)db + rule_ptr);
|
||||
|
||||
WifiRule wifiRule;
|
||||
wifiRule.start_freq_khz = be32_to_cpu(rule->start);
|
||||
wifiRule.end_freq_khz = be32_to_cpu(rule->end);
|
||||
wifiRule.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
|
||||
wifiRule.end_freq_khz = be32_to_cpu(rule->end);
|
||||
wifiRule.max_bandwidth_khz = be32_to_cpu(rule->max_bw);
|
||||
wifiRule.max_antenna_gain = 0;
|
||||
wifiRule.max_eirp = be16_to_cpu(rule->max_eirp);
|
||||
wifiRule.flags = RegRuleFlags::NONE;
|
||||
|
||||
if (rule->flags & FWDB_FLAG_NO_OFDM)
|
||||
wifiRule.flags |= RegRuleFlags::NO_OFDM;
|
||||
if (rule->flags & FWDB_FLAG_NO_OUTDOOR)
|
||||
wifiRule.flags |= RegRuleFlags::NO_OUTDOOR;
|
||||
if (rule->flags & FWDB_FLAG_DFS)
|
||||
wifiRule.flags |= RegRuleFlags::DFS;
|
||||
if (rule->flags & FWDB_FLAG_NO_IR)
|
||||
wifiRule.flags |= RegRuleFlags::NO_IR;
|
||||
if (rule->flags & FWDB_FLAG_AUTO_BW)
|
||||
wifiRule.flags |= RegRuleFlags::AUTO_BW;
|
||||
if (rule->flags & FWDB_FLAG_NO_OFDM)
|
||||
wifiRule.flags |= RegRuleFlags::NO_OFDM;
|
||||
if (rule->flags & FWDB_FLAG_NO_OUTDOOR)
|
||||
wifiRule.flags |= RegRuleFlags::NO_OUTDOOR;
|
||||
if (rule->flags & FWDB_FLAG_DFS)
|
||||
wifiRule.flags |= RegRuleFlags::DFS;
|
||||
if (rule->flags & FWDB_FLAG_NO_IR)
|
||||
wifiRule.flags |= RegRuleFlags::NO_IR;
|
||||
if (rule->flags & FWDB_FLAG_AUTO_BW)
|
||||
wifiRule.flags |= RegRuleFlags::AUTO_BW;
|
||||
|
||||
wifiRule.dfs_cac_ms = 0;
|
||||
wifiRule.dfs_cac_ms = 0;
|
||||
|
||||
/* handle optional data */
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
|
||||
wifiRule.dfs_cac_ms =
|
||||
1000 * be16_to_cpu(rule->cac_timeout);
|
||||
// if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
// set_wmm_rule(db, country, rule, &wifiRule);
|
||||
/* handle optional data */
|
||||
if (rule->len >= offsetofend(struct fwdb_rule, cac_timeout))
|
||||
wifiRule.dfs_cac_ms =
|
||||
1000 * be16_to_cpu(rule->cac_timeout);
|
||||
// if (rule->len >= offsetofend(struct fwdb_rule, wmm_ptr))
|
||||
// set_wmm_rule(db, country, rule, &wifiRule);
|
||||
wifiRegulations.rules.push_back(std::move(wifiRule));
|
||||
}
|
||||
}
|
||||
|
||||
return wifiRegulations;
|
||||
return wifiRegulations;
|
||||
}
|
||||
|
||||
|
||||
static std::vector<WifiRegulations> load_regdb(u8*pData)
|
||||
static std::vector<WifiRegulations> load_regdb(u8 *pData)
|
||||
{
|
||||
const struct fwdb_header *hdr = (const fwdb_header*)pData;
|
||||
const struct fwdb_country *country;
|
||||
const struct fwdb_header *hdr = (const fwdb_header *)pData;
|
||||
const struct fwdb_country *country;
|
||||
|
||||
ASSERT_RTNL();
|
||||
if (!pData)
|
||||
ASSERT_RTNL();
|
||||
if (!pData)
|
||||
{
|
||||
throw std::runtime_error("Regdb not loaded.");
|
||||
}
|
||||
std::vector<WifiRegulations> result;
|
||||
|
||||
country = &hdr->country[0];
|
||||
while (country->coll_ptr) {
|
||||
country = &hdr->country[0];
|
||||
while (country->coll_ptr)
|
||||
{
|
||||
result.push_back(regdb_load_country(hdr, country));
|
||||
country++;
|
||||
}
|
||||
country++;
|
||||
}
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
void RegDb::Load20()
|
||||
{
|
||||
u8*data = (u8*)ptr();
|
||||
u8 *data = (u8 *)ptr();
|
||||
unsigned int size = (unsigned int)this->data.size();
|
||||
if (!valid_regdb(data,size))
|
||||
if (!valid_regdb(data, size))
|
||||
{
|
||||
throw std::runtime_error("Invalid file format.");
|
||||
|
||||
}
|
||||
this->regulations = load_regdb(data);
|
||||
this->regulations = load_regdb(data);
|
||||
this->isValid = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static std::map<std::string,std::string> getIsoNamesDict(const std::filesystem::path&filename)
|
||||
{
|
||||
std::map<std::string,std::string> result;
|
||||
std::ifstream f(filename);
|
||||
if (!f.is_open())
|
||||
{
|
||||
throw std::runtime_error("Can't open WiFi regulatory domain names file.");
|
||||
}
|
||||
json_reader reader(f);
|
||||
reader.read(&result);
|
||||
return result;
|
||||
}
|
||||
std::map<std::string,std::string> RegDb::getRegulatoryDomains(const std::filesystem::path&isoFilenamesfile) const
|
||||
{
|
||||
std::map<std::string,std::string> keyToNameDict = getIsoNamesDict(isoFilenamesfile);
|
||||
std::map<std::string,std::string> result;
|
||||
|
||||
for (const auto ®ulation : this->regulations)
|
||||
{
|
||||
if (keyToNameDict.contains(regulation.reg_alpha2))
|
||||
{
|
||||
result[regulation.reg_alpha2] = keyToNameDict[regulation.reg_alpha2];
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -61,6 +61,7 @@ namespace pipedal
|
||||
|
||||
const WifiRegulations&getWifiRegulations(const std::string&countryIso3661) const;
|
||||
|
||||
std::map<std::string,std::string> getRegulatoryDomains(const std::filesystem::path&namesFile="/etc/pipedal/config/iso_codes.json") const;
|
||||
private:
|
||||
bool isValid = false;
|
||||
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
{
|
||||
"AF": "Afghanistan",
|
||||
"AX": "Aland Islands",
|
||||
"AL": "Albania",
|
||||
"DZ": "Algeria",
|
||||
"AS": "American Samoa",
|
||||
"AD": "Andorra",
|
||||
"AO": "Angola",
|
||||
"AI": "Anguilla",
|
||||
"AQ": "Antarctica",
|
||||
"AG": "Antigua And Barbuda",
|
||||
"AR": "Argentina",
|
||||
"AM": "Armenia",
|
||||
"AW": "Aruba",
|
||||
"AU": "Australia",
|
||||
"AT": "Austria",
|
||||
"AZ": "Azerbaijan",
|
||||
"BS": "Bahamas",
|
||||
"BH": "Bahrain",
|
||||
"BD": "Bangladesh",
|
||||
"BB": "Barbados",
|
||||
"BY": "Belarus",
|
||||
"BE": "Belgium",
|
||||
"BZ": "Belize",
|
||||
"BJ": "Benin",
|
||||
"BM": "Bermuda",
|
||||
"BT": "Bhutan",
|
||||
"BO": "Bolivia",
|
||||
"BA": "Bosnia And Herzegovina",
|
||||
"BW": "Botswana",
|
||||
"BV": "Bouvet Island",
|
||||
"BR": "Brazil",
|
||||
"IO": "British Indian Ocean Territory",
|
||||
"BN": "Brunei Darussalam",
|
||||
"BG": "Bulgaria",
|
||||
"BF": "Burkina Faso",
|
||||
"BI": "Burundi",
|
||||
"KH": "Cambodia",
|
||||
"CM": "Cameroon",
|
||||
"CA": "Canada",
|
||||
"CV": "Cape Verde",
|
||||
"KY": "Cayman Islands",
|
||||
"CF": "Central African Republic",
|
||||
"TD": "Chad",
|
||||
"CL": "Chile",
|
||||
"CN": "China",
|
||||
"CX": "Christmas Island",
|
||||
"CC": "Cocos (Keeling) Islands",
|
||||
"CO": "Colombia",
|
||||
"KM": "Comoros",
|
||||
"CG": "Congo",
|
||||
"CD": "Congo, Democratic Republic",
|
||||
"CK": "Cook Islands",
|
||||
"CR": "Costa Rica",
|
||||
"CI": "Cote D\"Ivoire",
|
||||
"HR": "Croatia",
|
||||
"CU": "Cuba",
|
||||
"CY": "Cyprus",
|
||||
"CZ": "Czech Republic",
|
||||
"DK": "Denmark",
|
||||
"DJ": "Djibouti",
|
||||
"DM": "Dominica",
|
||||
"DO": "Dominican Republic",
|
||||
"EC": "Ecuador",
|
||||
"EG": "Egypt",
|
||||
"SV": "El Salvador",
|
||||
"GQ": "Equatorial Guinea",
|
||||
"ER": "Eritrea",
|
||||
"EE": "Estonia",
|
||||
"ET": "Ethiopia",
|
||||
"FK": "Falkland Islands (Malvinas)",
|
||||
"FO": "Faroe Islands",
|
||||
"FJ": "Fiji",
|
||||
"FI": "Finland",
|
||||
"FR": "France",
|
||||
"GF": "French Guiana",
|
||||
"PF": "French Polynesia",
|
||||
"TF": "French Southern Territories",
|
||||
"GA": "Gabon",
|
||||
"GM": "Gambia",
|
||||
"GE": "Georgia",
|
||||
"DE": "Germany",
|
||||
"GH": "Ghana",
|
||||
"GI": "Gibraltar",
|
||||
"GR": "Greece",
|
||||
"GL": "Greenland",
|
||||
"GD": "Grenada",
|
||||
"GP": "Guadeloupe",
|
||||
"GU": "Guam",
|
||||
"GT": "Guatemala",
|
||||
"GG": "Guernsey",
|
||||
"GN": "Guinea",
|
||||
"GW": "Guinea-Bissau",
|
||||
"GY": "Guyana",
|
||||
"HT": "Haiti",
|
||||
"HM": "Heard Island & Mcdonald Islands",
|
||||
"VA": "Holy See (Vatican City State)",
|
||||
"HN": "Honduras",
|
||||
"HK": "Hong Kong",
|
||||
"HU": "Hungary",
|
||||
"IS": "Iceland",
|
||||
"IN": "India",
|
||||
"ID": "Indonesia",
|
||||
"IR": "Iran, Islamic Republic Of",
|
||||
"IQ": "Iraq",
|
||||
"IE": "Ireland",
|
||||
"IM": "Isle Of Man",
|
||||
"IL": "Israel",
|
||||
"IT": "Italy",
|
||||
"JM": "Jamaica",
|
||||
"JP": "Japan",
|
||||
"JE": "Jersey",
|
||||
"JO": "Jordan",
|
||||
"KZ": "Kazakhstan",
|
||||
"KE": "Kenya",
|
||||
"KI": "Kiribati",
|
||||
"KR": "Korea",
|
||||
"KP": "North Korea",
|
||||
"KW": "Kuwait",
|
||||
"KG": "Kyrgyzstan",
|
||||
"LA": "Lao People\"s Democratic Republic",
|
||||
"LV": "Latvia",
|
||||
"LB": "Lebanon",
|
||||
"LS": "Lesotho",
|
||||
"LR": "Liberia",
|
||||
"LY": "Libyan Arab Jamahiriya",
|
||||
"LI": "Liechtenstein",
|
||||
"LT": "Lithuania",
|
||||
"LU": "Luxembourg",
|
||||
"MO": "Macao",
|
||||
"MK": "Macedonia",
|
||||
"MG": "Madagascar",
|
||||
"MW": "Malawi",
|
||||
"MY": "Malaysia",
|
||||
"MV": "Maldives",
|
||||
"ML": "Mali",
|
||||
"MT": "Malta",
|
||||
"MH": "Marshall Islands",
|
||||
"MQ": "Martinique",
|
||||
"MR": "Mauritania",
|
||||
"MU": "Mauritius",
|
||||
"YT": "Mayotte",
|
||||
"MX": "Mexico",
|
||||
"FM": "Micronesia, Federated States Of",
|
||||
"MD": "Moldova",
|
||||
"MC": "Monaco",
|
||||
"MN": "Mongolia",
|
||||
"ME": "Montenegro",
|
||||
"MS": "Montserrat",
|
||||
"MA": "Morocco",
|
||||
"MZ": "Mozambique",
|
||||
"MM": "Myanmar",
|
||||
"NA": "Namibia",
|
||||
"NR": "Nauru",
|
||||
"NP": "Nepal",
|
||||
"NL": "Netherlands",
|
||||
"AN": "Netherlands Antilles",
|
||||
"NC": "New Caledonia",
|
||||
"NZ": "New Zealand",
|
||||
"NI": "Nicaragua",
|
||||
"NE": "Niger",
|
||||
"NG": "Nigeria",
|
||||
"NU": "Niue",
|
||||
"NF": "Norfolk Island",
|
||||
"MP": "Northern Mariana Islands",
|
||||
"NO": "Norway",
|
||||
"OM": "Oman",
|
||||
"PK": "Pakistan",
|
||||
"PW": "Palau",
|
||||
"PS": "Palestinian Territory, Occupied",
|
||||
"PA": "Panama",
|
||||
"PG": "Papua New Guinea",
|
||||
"PY": "Paraguay",
|
||||
"PE": "Peru",
|
||||
"PH": "Philippines",
|
||||
"PN": "Pitcairn",
|
||||
"PL": "Poland",
|
||||
"PT": "Portugal",
|
||||
"PR": "Puerto Rico",
|
||||
"QA": "Qatar",
|
||||
"RE": "Reunion",
|
||||
"RO": "Romania",
|
||||
"RU": "Russian Federation",
|
||||
"RW": "Rwanda",
|
||||
"BL": "Saint Barthelemy",
|
||||
"SH": "Saint Helena",
|
||||
"KN": "Saint Kitts And Nevis",
|
||||
"LC": "Saint Lucia",
|
||||
"MF": "Saint Martin",
|
||||
"PM": "Saint Pierre And Miquelon",
|
||||
"VC": "Saint Vincent And Grenadines",
|
||||
"WS": "Samoa",
|
||||
"SM": "San Marino",
|
||||
"ST": "Sao Tome And Principe",
|
||||
"SA": "Saudi Arabia",
|
||||
"SN": "Senegal",
|
||||
"RS": "Serbia",
|
||||
"SC": "Seychelles",
|
||||
"SL": "Sierra Leone",
|
||||
"SG": "Singapore",
|
||||
"SK": "Slovakia",
|
||||
"SI": "Slovenia",
|
||||
"SB": "Solomon Islands",
|
||||
"SO": "Somalia",
|
||||
"ZA": "South Africa",
|
||||
"GS": "South Georgia And Sandwich Isl.",
|
||||
"ES": "Spain",
|
||||
"LK": "Sri Lanka",
|
||||
"SD": "Sudan",
|
||||
"SR": "Suriname",
|
||||
"SJ": "Svalbard And Jan Mayen",
|
||||
"SZ": "Swaziland",
|
||||
"SE": "Sweden",
|
||||
"CH": "Switzerland",
|
||||
"SY": "Syrian Arab Republic",
|
||||
"TW": "Taiwan",
|
||||
"TJ": "Tajikistan",
|
||||
"TZ": "Tanzania",
|
||||
"TH": "Thailand",
|
||||
"TL": "Timor-Leste",
|
||||
"TG": "Togo",
|
||||
"TK": "Tokelau",
|
||||
"TO": "Tonga",
|
||||
"TT": "Trinidad And Tobago",
|
||||
"TN": "Tunisia",
|
||||
"TR": "Turkey",
|
||||
"TM": "Turkmenistan",
|
||||
"TC": "Turks And Caicos Islands",
|
||||
"TV": "Tuvalu",
|
||||
"UG": "Uganda",
|
||||
"UA": "Ukraine",
|
||||
"AE": "United Arab Emirates",
|
||||
"GB": "United Kingdom",
|
||||
"US": "United States",
|
||||
"UM": "United States Outlying Islands",
|
||||
"UY": "Uruguay",
|
||||
"UZ": "Uzbekistan",
|
||||
"VU": "Vanuatu",
|
||||
"VE": "Venezuela",
|
||||
"VN": "Vietnam",
|
||||
"VG": "Virgin Islands, British",
|
||||
"VI": "Virgin Islands, U.S.",
|
||||
"WF": "Wallis And Futuna",
|
||||
"EH": "Western Sahara",
|
||||
"YE": "Yemen",
|
||||
"ZM": "Zambia",
|
||||
"ZW": "Zimbabwe"
|
||||
}
|
||||
@@ -1018,10 +1018,7 @@ export class PiPedalModel //implements PiPedalModel
|
||||
|
||||
}
|
||||
try {
|
||||
let isoFetch = await fetch(new Request('iso_codes.json'));
|
||||
this.countryCodes = (await isoFetch.json()) as { [Name: string]: string };
|
||||
|
||||
|
||||
this.countryCodes = await this.getWebSocket().request<{ [Name: string]: string }>("getWifiRegulatoryDomains");
|
||||
|
||||
this.clientId = (await this.getWebSocket().request<number>("hello")) as number;
|
||||
|
||||
|
||||
@@ -44,16 +44,10 @@ static void DiscoveryTest()
|
||||
|
||||
}
|
||||
|
||||
void ChannelConfigtest()
|
||||
{
|
||||
cout << "--- Channel Config Test" << endl;
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE( "ALSA Test", "[pipedal_alsa_test][Build][Dev]" ) {
|
||||
DiscoveryTest();
|
||||
|
||||
ChannelConfigTest();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "AdminClient.hpp"
|
||||
#include "SplitEffect.hpp"
|
||||
#include "CpuGovernor.hpp"
|
||||
#include "RegDb.hpp"
|
||||
#include "RingBufferReader.hpp"
|
||||
#include "PiPedalUI.hpp"
|
||||
#include "atom_object.hpp"
|
||||
@@ -2721,4 +2722,17 @@ bool PiPedalModel::GetHasWifi()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(mutex);
|
||||
return hasWifi;
|
||||
}
|
||||
|
||||
std::map<std::string,std::string> PiPedalModel::GetWifiRegulatoryDomains()
|
||||
{
|
||||
std::map<std::string,std::string> result;
|
||||
try {
|
||||
auto& regDb = RegDb::GetInstance();
|
||||
result = regDb.getRegulatoryDomains(storage.GetConfigRoot() / "iso_codes.json");
|
||||
} catch (const std::exception&e)
|
||||
{
|
||||
Lv2Log::warning(SS("Unable to query Wifi Regulatory domains. " << e.what()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@@ -91,6 +91,7 @@ namespace pipedal
|
||||
// virtual void OnPatchPropertyChanged(int64_t clientId, int64_t instanceId,const std::string& propertyUri,const json_variant& value) = 0;
|
||||
virtual void OnErrorMessage(const std::string &message) = 0;
|
||||
virtual void OnLv2PluginsChanging() = 0;
|
||||
|
||||
virtual void OnNetworkChanging(bool hotspotConnected) = 0;
|
||||
virtual void OnHasWifiChanged(bool hasWifi) = 0;
|
||||
virtual void Close() = 0;
|
||||
@@ -304,6 +305,7 @@ namespace pipedal
|
||||
void SetRestartListener(std::function<void(void)> &&listener);
|
||||
void OnLv2PluginsChanged();
|
||||
void SetOnboarding(bool value);
|
||||
std::map<std::string,std::string> GetWifiRegulatoryDomains();
|
||||
|
||||
void UpdateDnsSd();
|
||||
|
||||
|
||||
@@ -1640,6 +1640,11 @@ public:
|
||||
pReader->read(&value);
|
||||
this->model.SetOnboarding(value);
|
||||
}
|
||||
else if (message == "getWifiRegulatoryDomains")
|
||||
{
|
||||
auto regulatoryDomains = this->model.GetWifiRegulatoryDomains();
|
||||
this->Reply(replyTo, "getWifiRegulatoryDomains", regulatoryDomains);
|
||||
}
|
||||
else
|
||||
{
|
||||
Lv2Log::error("Unknown message received: %s", message.c_str());
|
||||
|
||||
+137
-123
@@ -43,8 +43,7 @@ const char *BANKS_FILENAME = "index.banks";
|
||||
|
||||
#define USER_SETTINGS_FILENAME "userSettings.json";
|
||||
|
||||
|
||||
static bool isSubdirectory(const fs::path&path, const fs::path&basePath)
|
||||
static bool isSubdirectory(const fs::path &path, const fs::path &basePath)
|
||||
{
|
||||
auto iPath = path.begin();
|
||||
for (auto i = basePath.begin(); i != basePath.end(); ++i)
|
||||
@@ -53,7 +52,7 @@ static bool isSubdirectory(const fs::path&path, const fs::path&basePath)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if ((*i) != (*iPath))
|
||||
{
|
||||
return false;
|
||||
@@ -74,7 +73,6 @@ static bool isSubdirectory(const fs::path&path, const fs::path&basePath)
|
||||
static bool hasSyntheticModRoot(const UiFileProperty &fileProperty)
|
||||
{
|
||||
return (fileProperty.modDirectories().size() > 1 || (fileProperty.modDirectories().size() == 1 && fileProperty.useLegacyModDirectory()));
|
||||
|
||||
}
|
||||
|
||||
Storage::Storage()
|
||||
@@ -165,7 +163,7 @@ std::string Storage::SafeEncodeName(const std::string &name)
|
||||
}
|
||||
else
|
||||
{
|
||||
s << '%' << hex[(c >> 4) & 0x0F] << hex[(c)&0x0F];
|
||||
s << '%' << hex[(c >> 4) & 0x0F] << hex[(c) & 0x0F];
|
||||
}
|
||||
}
|
||||
return s.str();
|
||||
@@ -187,7 +185,8 @@ std::filesystem::path ResolveHomePath(const std::filesystem::path &path)
|
||||
{
|
||||
homeDirectory = getenv("USERPROFILE");
|
||||
}
|
||||
if (homeDirectory == nullptr) {
|
||||
if (homeDirectory == nullptr)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
std::filesystem::path result = homeDirectory;
|
||||
@@ -213,6 +212,15 @@ void Storage::SetDataRoot(const std::filesystem::path &path)
|
||||
this->dataRoot = ResolveHomePath(path);
|
||||
}
|
||||
|
||||
const std::filesystem::path &Storage::GetConfigRoot()
|
||||
{
|
||||
return this->configRoot;
|
||||
}
|
||||
const std::filesystem::path &Storage::GetDataRoot()
|
||||
{
|
||||
return this->dataRoot;
|
||||
}
|
||||
|
||||
static void CopyDirectory(const std::filesystem::path &source, const std::filesystem::path &destination)
|
||||
{
|
||||
for (auto &directoryEntry : std::filesystem::directory_iterator(source))
|
||||
@@ -1001,7 +1009,9 @@ bool Storage::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings
|
||||
copyToSave.hasPassword_ = previousValue.hasPassword_;
|
||||
copyToSave.password_ = previousValue.password_;
|
||||
copyToSave.hasSavedPassword_ = previousValue.hasPassword_;
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (copyToSave.IsEnabled())
|
||||
{
|
||||
copyToSave.hasSavedPassword_ = copyToSave.hasPassword_;
|
||||
@@ -1012,7 +1022,7 @@ bool Storage::SetWifiConfigSettings(const WifiConfigSettings &wifiConfigSettings
|
||||
this->wifiConfigSettings = copyToSave;
|
||||
this->wifiConfigSettings.hasPassword_ = false;
|
||||
this->wifiConfigSettings.password_ = "";
|
||||
|
||||
|
||||
return configChanged;
|
||||
}
|
||||
|
||||
@@ -1160,19 +1170,21 @@ void Storage::MergePluginPresets(const std::string &pluginUri, const PluginPrese
|
||||
else
|
||||
{
|
||||
path = GetPluginPresetPath(pluginUri);
|
||||
try {
|
||||
try
|
||||
{
|
||||
std::ifstream f(path);
|
||||
if (f.is_open())
|
||||
{
|
||||
json_reader reader(f);
|
||||
reader.read(&existingPresets);
|
||||
}
|
||||
} catch (const std::exception &e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Storage::MergePluginPresets: Can't reading existing plugin presets." << e.what()));
|
||||
}
|
||||
}
|
||||
for (const PluginPreset &preset: presets.presets_)
|
||||
for (const PluginPreset &preset : presets.presets_)
|
||||
{
|
||||
|
||||
existingPresets.MergePreset(preset);
|
||||
@@ -1518,9 +1530,9 @@ void Storage::SetSystemMidiBindings(const std::vector<MidiBinding> &bindings)
|
||||
writer.write(bindings);
|
||||
}
|
||||
}
|
||||
static bool hasBinding(std::vector<MidiBinding> &bindings, const std::string&name)
|
||||
static bool hasBinding(std::vector<MidiBinding> &bindings, const std::string &name)
|
||||
{
|
||||
for (auto&binding: bindings)
|
||||
for (auto &binding : bindings)
|
||||
{
|
||||
if (binding.symbol() == name)
|
||||
{
|
||||
@@ -1534,7 +1546,8 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||
std::vector<MidiBinding> result;
|
||||
|
||||
std::filesystem::path fileName = this->dataRoot / "config" / "SystemMidiBindings.json";
|
||||
if (!std::filesystem::exists(fileName)) {
|
||||
if (!std::filesystem::exists(fileName))
|
||||
{
|
||||
// pick up from legacy location?
|
||||
fileName = this->configRoot / "config" / "SystemMidiBindings.json";
|
||||
}
|
||||
@@ -1542,7 +1555,8 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||
f.open(fileName);
|
||||
if (f.is_open())
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
json_reader reader(f);
|
||||
reader.read(&result);
|
||||
if (result.size() == 2)
|
||||
@@ -1552,23 +1566,23 @@ std::vector<MidiBinding> Storage::GetSystemMidiBindings()
|
||||
result.push_back(MidiBinding::SystemBinding("shutdown"));
|
||||
result.push_back(MidiBinding::SystemBinding("reboot"));
|
||||
}
|
||||
if (!hasBinding(result,"prevBank"))
|
||||
if (!hasBinding(result, "prevBank"))
|
||||
{
|
||||
result.insert(result.begin(),MidiBinding::SystemBinding("nextBank")); // reverse order.
|
||||
result.insert(result.begin(),MidiBinding::SystemBinding("prevBank"));
|
||||
result.insert(result.begin(), MidiBinding::SystemBinding("nextBank")); // reverse order.
|
||||
result.insert(result.begin(), MidiBinding::SystemBinding("prevBank"));
|
||||
}
|
||||
if (!hasBinding(result,"snapshot1"))
|
||||
if (!hasBinding(result, "snapshot1"))
|
||||
{
|
||||
auto position = 4;
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
result.insert(result.begin()+position,MidiBinding::SystemBinding(SS("snapshot" << (i+1))));
|
||||
result.insert(result.begin() + position, MidiBinding::SystemBinding(SS("snapshot" << (i + 1))));
|
||||
++position;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
catch (const std::exception&e)
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::warning(SS("Can't read file " << fileName << ". " << e.what()));
|
||||
}
|
||||
@@ -1604,13 +1618,11 @@ static bool containsDirectorySeparator(const std::string &value)
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static void ThrowPermissionDeniedError()
|
||||
{
|
||||
throw std::logic_error("Permission denied.");
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> Storage::GetFileList(const UiFileProperty &fileProperty)
|
||||
{
|
||||
if (!UiFileProperty::IsDirectoryNameValid(fileProperty.directory()))
|
||||
@@ -1652,22 +1664,21 @@ std::vector<std::string> Storage::GetFileList(const UiFileProperty &fileProperty
|
||||
// sort lexicographically
|
||||
auto collator = Locale::GetInstance()->GetCollator();
|
||||
|
||||
std::sort(result.begin(), result.end(), [&collator](const std::string&left,const std::string&right) {
|
||||
return collator->Compare(left,right) < 0;
|
||||
});
|
||||
std::sort(result.begin(), result.end(), [&collator](const std::string &left, const std::string &right)
|
||||
{ return collator->Compare(left, right) < 0; });
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool ensureNoDotDot(const std::filesystem::path&path)
|
||||
static bool ensureNoDotDot(const std::filesystem::path &path)
|
||||
{
|
||||
for (auto segment_: path)
|
||||
for (auto segment_ : path)
|
||||
{
|
||||
std::string segment = segment_.string();
|
||||
if (segment.starts_with("."))
|
||||
{
|
||||
// the linux rule: any path that consists of all '.'s.
|
||||
bool valid = false;
|
||||
for (auto c: segment)
|
||||
for (auto c : segment)
|
||||
{
|
||||
if (c != '.')
|
||||
{
|
||||
@@ -1679,22 +1690,21 @@ static bool ensureNoDotDot(const std::filesystem::path&path)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void AddFilesToResult(
|
||||
FileRequestResult&result,
|
||||
FileRequestResult &result,
|
||||
const UiFileProperty &fileProperty,
|
||||
const fs::path&rootPath)
|
||||
const fs::path &rootPath)
|
||||
{
|
||||
if (!fs::exists(rootPath))
|
||||
{
|
||||
return; // silently without error.
|
||||
}
|
||||
auto & resultFiles = result.files_;
|
||||
auto &resultFiles = result.files_;
|
||||
try
|
||||
{
|
||||
for (auto const &dir_entry : std::filesystem::directory_iterator(rootPath))
|
||||
@@ -1708,12 +1718,13 @@ static void AddFilesToResult(
|
||||
if (fileProperty.IsValidExtension(path.extension().string()))
|
||||
{
|
||||
resultFiles.push_back(
|
||||
FileEntry(path,name,false,false)
|
||||
);
|
||||
FileEntry(path, name, false, false));
|
||||
}
|
||||
}
|
||||
} else if (dir_entry.is_directory()) {
|
||||
resultFiles.push_back(FileEntry{path,name,true,fs::is_symlink(path)});
|
||||
}
|
||||
else if (dir_entry.is_directory())
|
||||
{
|
||||
resultFiles.push_back(FileEntry{path, name, true, fs::is_symlink(path)});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1726,61 +1737,57 @@ static void AddFilesToResult(
|
||||
|
||||
auto collator = Locale::GetInstance()->GetCollator();
|
||||
|
||||
std::sort(resultFiles.begin(), resultFiles.end(),[&collator](const FileEntry&l, const FileEntry&r) {
|
||||
std::sort(resultFiles.begin(), resultFiles.end(), [&collator](const FileEntry &l, const FileEntry &r)
|
||||
{
|
||||
if (l.isDirectory_ != r.isDirectory_)
|
||||
{
|
||||
return l.isDirectory_ > r.isDirectory_;
|
||||
}
|
||||
return collator->Compare(l.displayName_,r.displayName_) < 0;
|
||||
});
|
||||
return collator->Compare(l.displayName_,r.displayName_) < 0; });
|
||||
}
|
||||
FileRequestResult Storage::GetModFileList2(const std::string &relativePath,const UiFileProperty &fileProperty)
|
||||
FileRequestResult Storage::GetModFileList2(const std::string &relativePath, const UiFileProperty &fileProperty)
|
||||
{
|
||||
FileRequestResult result;
|
||||
fs::path uploadsDirectory = GetPluginUploadDirectory();
|
||||
|
||||
if (relativePath.empty())
|
||||
{
|
||||
// return the synthetic root.
|
||||
// return the synthetic root.
|
||||
result.isProtected_ = true;
|
||||
|
||||
for (const auto&modDirectory: fileProperty.modDirectories())
|
||||
for (const auto &modDirectory : fileProperty.modDirectories())
|
||||
{
|
||||
const auto directoryInfo = ModFileTypes::GetModDirectory(modDirectory);
|
||||
if (directoryInfo)
|
||||
{
|
||||
result.files_.push_back(
|
||||
FileEntry(uploadsDirectory / directoryInfo->pipedalPath,directoryInfo->displayName,true,true)
|
||||
);
|
||||
FileEntry(uploadsDirectory / directoryInfo->pipedalPath, directoryInfo->displayName, true, true));
|
||||
}
|
||||
|
||||
}
|
||||
if (fileProperty.useLegacyModDirectory())
|
||||
{
|
||||
result.files_.push_back(
|
||||
FileEntry(uploadsDirectory / fileProperty.directory(),fs::path(fileProperty.directory()).filename().string(),true,true)
|
||||
);
|
||||
FileEntry(uploadsDirectory / fileProperty.directory(), fs::path(fileProperty.directory()).filename().string(), true, true));
|
||||
}
|
||||
result.breadcrumbs_.push_back({"","Home"});
|
||||
result.breadcrumbs_.push_back({"", "Home"});
|
||||
return result;
|
||||
}
|
||||
fs::path modDirectoryPath;
|
||||
|
||||
result.breadcrumbs_.push_back({"","Home"});
|
||||
fs::path fsRelativePath { relativePath};
|
||||
result.breadcrumbs_.push_back({"", "Home"});
|
||||
fs::path fsRelativePath{relativePath};
|
||||
|
||||
for (const auto &modDirectory: fileProperty.modDirectories())
|
||||
for (const auto &modDirectory : fileProperty.modDirectories())
|
||||
{
|
||||
const ModFileTypes::ModDirectory*modDirectoryInfo = ModFileTypes::GetModDirectory(modDirectory);
|
||||
const ModFileTypes::ModDirectory *modDirectoryInfo = ModFileTypes::GetModDirectory(modDirectory);
|
||||
if (modDirectoryInfo)
|
||||
{
|
||||
if (isSubdirectory(fsRelativePath, uploadsDirectory / modDirectoryInfo->pipedalPath))
|
||||
{
|
||||
modDirectoryPath = uploadsDirectory / modDirectoryInfo->pipedalPath;
|
||||
result.breadcrumbs_.push_back({modDirectoryPath.string(),modDirectoryInfo->displayName});
|
||||
result.breadcrumbs_.push_back({modDirectoryPath.string(), modDirectoryInfo->displayName});
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (modDirectoryPath.empty() && fileProperty.useLegacyModDirectory())
|
||||
@@ -1788,37 +1795,39 @@ FileRequestResult Storage::GetModFileList2(const std::string &relativePath,const
|
||||
if (isSubdirectory(fsRelativePath, uploadsDirectory / fileProperty.directory()))
|
||||
{
|
||||
modDirectoryPath = uploadsDirectory / fileProperty.directory();
|
||||
result.breadcrumbs_.push_back({modDirectoryPath.string(),fs::path(fileProperty.directory()).filename().string()});
|
||||
} else {
|
||||
result.breadcrumbs_.push_back({modDirectoryPath.string(), fs::path(fileProperty.directory()).filename().string()});
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowPermissionDeniedError();
|
||||
}
|
||||
}
|
||||
|
||||
// add remaing path segements as breadcrumbs.
|
||||
{
|
||||
fs::path modPath {modDirectoryPath};
|
||||
fs::path rp { relativePath};
|
||||
fs::path modPath{modDirectoryPath};
|
||||
fs::path rp{relativePath};
|
||||
auto iRp = rp.begin();
|
||||
// skip past one or more segments in the modDiretoryPath.
|
||||
for (auto iModPath = modPath.begin(); iModPath != modPath.end(); ++iModPath)
|
||||
{
|
||||
if (iRp != rp.end()) {
|
||||
if (iRp != rp.end())
|
||||
{
|
||||
++iRp;
|
||||
}
|
||||
}
|
||||
while (iRp != rp.end())
|
||||
{
|
||||
result.breadcrumbs_.push_back({*iRp,*iRp});
|
||||
result.breadcrumbs_.push_back({*iRp, *iRp});
|
||||
++iRp;
|
||||
}
|
||||
}
|
||||
|
||||
AddFilesToResult(result,fileProperty,relativePath);
|
||||
AddFilesToResult(result, fileProperty, relativePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
FileRequestResult Storage::GetFileList2(const std::string &relativePath_,const UiFileProperty &fileProperty)
|
||||
FileRequestResult Storage::GetFileList2(const std::string &relativePath_, const UiFileProperty &fileProperty)
|
||||
{
|
||||
std::string absolutePath = relativePath_;
|
||||
if (!ensureNoDotDot(absolutePath))
|
||||
@@ -1827,12 +1836,12 @@ FileRequestResult Storage::GetFileList2(const std::string &relativePath_,const U
|
||||
}
|
||||
if (hasSyntheticModRoot(fileProperty))
|
||||
{
|
||||
return Storage::GetModFileList2(absolutePath,fileProperty);
|
||||
return Storage::GetModFileList2(absolutePath, fileProperty);
|
||||
}
|
||||
|
||||
FileRequestResult result;
|
||||
|
||||
if (fileProperty.directory().empty())
|
||||
if (fileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("fileProperty.directory() not specified.");
|
||||
}
|
||||
@@ -1842,10 +1851,9 @@ FileRequestResult Storage::GetFileList2(const std::string &relativePath_,const U
|
||||
absolutePath = pluginRootDirectory.string();
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
result.breadcrumbs_.push_back({"","Home"});
|
||||
fs::path fsAbsolutePath {absolutePath};
|
||||
result.breadcrumbs_.push_back({"", "Home"});
|
||||
fs::path fsAbsolutePath{absolutePath};
|
||||
auto iAbsolutePath = fsAbsolutePath.begin();
|
||||
for (auto i = pluginRootDirectory.begin(); i != pluginRootDirectory.end(); ++i)
|
||||
{
|
||||
@@ -1860,26 +1868,25 @@ FileRequestResult Storage::GetFileList2(const std::string &relativePath_,const U
|
||||
while (iAbsolutePath != fsAbsolutePath.end())
|
||||
{
|
||||
cumulativePath /= (*iAbsolutePath);
|
||||
result.breadcrumbs_.push_back({cumulativePath.string(),iAbsolutePath->string()});
|
||||
result.breadcrumbs_.push_back({cumulativePath.string(), iAbsolutePath->string()});
|
||||
++iAbsolutePath;
|
||||
}
|
||||
}
|
||||
if (!isSubdirectory(absolutePath,pluginRootDirectory))
|
||||
if (!isSubdirectory(absolutePath, pluginRootDirectory))
|
||||
{
|
||||
throw std::runtime_error(SS("Improper location. " << absolutePath));
|
||||
}
|
||||
AddFilesToResult(result,fileProperty,absolutePath);
|
||||
AddFilesToResult(result, fileProperty, absolutePath);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool Storage::IsValidSampleFileName(const std::filesystem::path &fileName)
|
||||
{
|
||||
if (!fileName.is_absolute())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
std::filesystem::path audioFilePath = this->GetPluginUploadDirectory();
|
||||
|
||||
std::filesystem::path parentDirectory = fileName.parent_path();
|
||||
@@ -1888,10 +1895,12 @@ bool Storage::IsValidSampleFileName(const std::filesystem::path &fileName)
|
||||
|
||||
for (auto i = audioFilePath.begin(); i != audioFilePath.end(); ++i)
|
||||
{
|
||||
if (iTarget == parentDirectory.end()) {
|
||||
if (iTarget == parentDirectory.end())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
if (*i != *iTarget) {
|
||||
if (*i != *iTarget)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
++iTarget;
|
||||
@@ -1927,14 +1936,17 @@ void Storage::DeleteSampleFile(const std::filesystem::path &fileName)
|
||||
if (std::filesystem::is_symlink(fileName))
|
||||
{
|
||||
std::filesystem::remove(fileName);
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (fileName.string().length() > 1) // guard against rm -rf / (bitter experience)
|
||||
{
|
||||
std::filesystem::remove_all(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
else
|
||||
{
|
||||
std::filesystem::remove(fileName);
|
||||
}
|
||||
}
|
||||
@@ -1958,7 +1970,7 @@ std::filesystem::path Storage::MakeUserFilePath(const std::string &directory, co
|
||||
}
|
||||
return result;
|
||||
}
|
||||
std::string Storage::UploadUserFile(const std::string &directory, const std::string &patchProperty, const std::string &filename, std::istream&stream, size_t contentLength)
|
||||
std::string Storage::UploadUserFile(const std::string &directory, const std::string &patchProperty, const std::string &filename, std::istream &stream, size_t contentLength)
|
||||
{
|
||||
std::filesystem::path path;
|
||||
if (directory.length() != 0)
|
||||
@@ -1966,7 +1978,7 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
||||
path = this->MakeUserFilePath(directory, filename);
|
||||
}
|
||||
else
|
||||
|
||||
|
||||
{
|
||||
if (patchProperty.length() == 0)
|
||||
{
|
||||
@@ -1975,7 +1987,8 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
||||
throw std::logic_error("patchProperty directory not implemented.");
|
||||
}
|
||||
{
|
||||
try {
|
||||
try
|
||||
{
|
||||
std::filesystem::create_directories(path.parent_path());
|
||||
|
||||
pipedal::ofstream_synced f(path, std::ios_base::trunc | std::ios_base::binary);
|
||||
@@ -1984,23 +1997,26 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
||||
throw std::logic_error(SS("Can't create file " << path << "."));
|
||||
}
|
||||
std::vector<uint8_t> buffer;
|
||||
size_t BUFFER_SIZE = 64*1024;
|
||||
size_t BUFFER_SIZE = 64 * 1024;
|
||||
buffer.resize(BUFFER_SIZE);
|
||||
char *pBuffer= (char*)&(buffer[0]);
|
||||
char *pBuffer = (char *)&(buffer[0]);
|
||||
while (contentLength != 0)
|
||||
{
|
||||
size_t thisTime = std::min(BUFFER_SIZE,contentLength);
|
||||
stream.read(pBuffer,(std::streamsize)thisTime);
|
||||
if (!stream) {
|
||||
size_t thisTime = std::min(BUFFER_SIZE, contentLength);
|
||||
stream.read(pBuffer, (std::streamsize)thisTime);
|
||||
if (!stream)
|
||||
{
|
||||
throw std::runtime_error("Unable to read body input stream.");
|
||||
}
|
||||
f.write(pBuffer,(std::streamsize)thisTime);
|
||||
if (!f) {
|
||||
f.write(pBuffer, (std::streamsize)thisTime);
|
||||
if (!f)
|
||||
{
|
||||
throw std::runtime_error("Failed to write to upload file.");
|
||||
}
|
||||
contentLength -= thisTime;
|
||||
}
|
||||
} catch (const std::exception &e)
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
Lv2Log::error(SS("Upload failed. " << e.what()));
|
||||
std::filesystem::remove(path);
|
||||
@@ -2010,7 +2026,7 @@ std::string Storage::UploadUserFile(const std::string &directory, const std::str
|
||||
return path.string();
|
||||
}
|
||||
|
||||
std::string Storage::CreateNewSampleDirectory(const std::string&relativePath, const UiFileProperty&uiFileProperty)
|
||||
std::string Storage::CreateNewSampleDirectory(const std::string &relativePath, const UiFileProperty &uiFileProperty)
|
||||
{
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
@@ -2027,12 +2043,11 @@ std::string Storage::CreateNewSampleDirectory(const std::string&relativePath, co
|
||||
}
|
||||
std::filesystem::create_directories(path);
|
||||
return path;
|
||||
|
||||
}
|
||||
std::string Storage::RenameFilePropertyFile(
|
||||
const std::string&oldRelativePath,
|
||||
const std::string&newRelativePath,
|
||||
const UiFileProperty&uiFileProperty)
|
||||
const std::string &oldRelativePath,
|
||||
const std::string &newRelativePath,
|
||||
const UiFileProperty &uiFileProperty)
|
||||
{
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
@@ -2058,67 +2073,68 @@ std::string Storage::RenameFilePropertyFile(
|
||||
if (std::filesystem::is_directory(newPath))
|
||||
{
|
||||
throw std::runtime_error("A directory with that name already exists.");
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
throw std::runtime_error("A file with that name already exists.");
|
||||
}
|
||||
}
|
||||
|
||||
std::filesystem::rename(oldPath,newPath);
|
||||
std::filesystem::rename(oldPath, newPath);
|
||||
return newPath;
|
||||
|
||||
}
|
||||
|
||||
void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree*node, const std::filesystem::path&directory) const
|
||||
void Storage::FillSampleDirectoryTree(FilePropertyDirectoryTree *node, const std::filesystem::path &directory) const
|
||||
{
|
||||
for (auto child: std::filesystem::directory_iterator(directory))
|
||||
for (auto child : std::filesystem::directory_iterator(directory))
|
||||
{
|
||||
if (child.is_directory())
|
||||
{
|
||||
const auto& childPath = child.path();
|
||||
const auto &childPath = child.path();
|
||||
FilePropertyDirectoryTree::ptr childTree = std::make_unique<FilePropertyDirectoryTree>(childPath);
|
||||
FillSampleDirectoryTree(childTree.get(),childPath);
|
||||
FillSampleDirectoryTree(childTree.get(), childPath);
|
||||
node->children_.push_back(std::move(childTree));
|
||||
}
|
||||
}
|
||||
auto collator = Locale::GetInstance()->GetCollator();
|
||||
std::sort(node->children_.begin(),node->children_.end(),
|
||||
[&collator](const FilePropertyDirectoryTree::ptr&left,const FilePropertyDirectoryTree::ptr&right)
|
||||
{
|
||||
return collator->Compare(left->directoryName_,right->directoryName_) < 0;
|
||||
});
|
||||
std::sort(node->children_.begin(), node->children_.end(),
|
||||
[&collator](const FilePropertyDirectoryTree::ptr &left, const FilePropertyDirectoryTree::ptr &right)
|
||||
{
|
||||
return collator->Compare(left->directoryName_, right->directoryName_) < 0;
|
||||
});
|
||||
}
|
||||
FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty&uiFileProperty)
|
||||
FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFileProperty &uiFileProperty)
|
||||
{
|
||||
fs::path uploadDirectory = this->GetPluginUploadDirectory();
|
||||
fs::path uploadDirectory = this->GetPluginUploadDirectory();
|
||||
|
||||
if (hasSyntheticModRoot(uiFileProperty))
|
||||
{
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>("","Home");
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>("", "Home");
|
||||
result->isProtected_ = true;
|
||||
for (const auto& modDirectory: uiFileProperty.modDirectories())
|
||||
for (const auto &modDirectory : uiFileProperty.modDirectories())
|
||||
{
|
||||
auto modDirectoryInfo = ModFileTypes::GetModDirectory(modDirectory);
|
||||
if (modDirectoryInfo)
|
||||
{
|
||||
auto childPath = uploadDirectory / modDirectoryInfo->pipedalPath;
|
||||
FilePropertyDirectoryTree::ptr child = std::make_unique<FilePropertyDirectoryTree>(
|
||||
childPath,modDirectoryInfo->displayName
|
||||
);
|
||||
FillSampleDirectoryTree(child.get(),childPath);
|
||||
childPath, modDirectoryInfo->displayName);
|
||||
FillSampleDirectoryTree(child.get(), childPath);
|
||||
result->children_.push_back(std::move(child));
|
||||
}
|
||||
}
|
||||
if (uiFileProperty.useLegacyModDirectory()) {
|
||||
if (uiFileProperty.useLegacyModDirectory())
|
||||
{
|
||||
auto childPath = uploadDirectory / uiFileProperty.directory();
|
||||
FilePropertyDirectoryTree::ptr child = std::make_unique<FilePropertyDirectoryTree>(
|
||||
childPath
|
||||
);
|
||||
FillSampleDirectoryTree(child.get(),childPath);
|
||||
childPath);
|
||||
FillSampleDirectoryTree(child.get(), childPath);
|
||||
result->children_.push_back(std::move(child));
|
||||
}
|
||||
return result;
|
||||
|
||||
} else {
|
||||
}
|
||||
else
|
||||
{
|
||||
if (uiFileProperty.directory().empty())
|
||||
{
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
@@ -2128,15 +2144,13 @@ FilePropertyDirectoryTree::ptr Storage::GetFilePropertydirectoryTree(const UiFil
|
||||
throw std::runtime_error("Invalid uiFileProperty");
|
||||
}
|
||||
std::filesystem::path rootDirectory = uploadDirectory / uiFileProperty.directory();
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>(rootDirectory.string(),"Home");
|
||||
FilePropertyDirectoryTree::ptr result = std::make_unique<FilePropertyDirectoryTree>(rootDirectory.string(), "Home");
|
||||
|
||||
FillSampleDirectoryTree(result.get(),rootDirectory);
|
||||
FillSampleDirectoryTree(result.get(), rootDirectory);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const PluginPresetIndex &Storage::GetPluginPresetIndex()
|
||||
{
|
||||
return pluginPresetIndex;
|
||||
|
||||
@@ -109,6 +109,8 @@ public:
|
||||
|
||||
void SetDataRoot(const std::filesystem::path& path);
|
||||
void SetConfigRoot(const std::filesystem::path& path);
|
||||
const std::filesystem::path&GetConfigRoot();
|
||||
const std::filesystem::path&GetDataRoot();
|
||||
|
||||
std::filesystem::path GetPluginUploadDirectory() const;
|
||||
|
||||
|
||||
@@ -230,8 +230,24 @@ static void DisplayRegulations(const std::string& country)
|
||||
}
|
||||
}
|
||||
|
||||
void DisplayRegDomains()
|
||||
{
|
||||
std::cout << "==== Regulatory domains === " << std::endl;
|
||||
std::filesystem::path dbPath = "test_data/debian_bookworm_regulatory.db";
|
||||
RegDb regdb{dbPath};
|
||||
REQUIRE(regdb.IsValid());
|
||||
|
||||
auto regDomains = regdb.getRegulatoryDomains("config/iso_codes.json");
|
||||
for (const auto®Domain: regDomains)
|
||||
{
|
||||
std::cout << " " << regDomain.first << ": " << regDomain.second << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
TEST_CASE("Wifi Channel Test", "[wifi_channels_test]")
|
||||
{
|
||||
DisplayRegDomains();
|
||||
DisplayRegulations("CA");
|
||||
DisplayRegulations("US");
|
||||
DisplayRegulations("JP");
|
||||
|
||||
Reference in New Issue
Block a user