From 0ca7545b3fbfdb7c36c131df9062d65eb345c9e0 Mon Sep 17 00:00:00 2001 From: "Robin E. R. Davies" Date: Wed, 20 Nov 2024 23:40:04 -0500 Subject: [PATCH] Use actual list of regulatory domains for wifi dialog. --- .vscode/launch.json | 3 +- PiPedalCommon/src/RegDb.cpp | 431 +++++++++++++++------------- PiPedalCommon/src/include/RegDb.hpp | 1 + config/iso_codes.json | 248 ++++++++++++++++ react/src/PiPedalModel.tsx | 5 +- src/PiPedalAlsaTest.cpp | 6 - src/PiPedalModel.cpp | 14 + src/PiPedalModel.hpp | 2 + src/PiPedalSocket.cpp | 5 + src/Storage.cpp | 260 +++++++++-------- src/Storage.hpp | 2 + src/WifiChannelsTest.cpp | 16 ++ 12 files changed, 661 insertions(+), 332 deletions(-) create mode 100644 config/iso_codes.json diff --git a/.vscode/launch.json b/.vscode/launch.json index 3c12bd4..6e6cf77 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -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, diff --git a/PiPedalCommon/src/RegDb.cpp b/PiPedalCommon/src/RegDb.cpp index 4bf9d81..3b08a40 100644 --- a/PiPedalCommon/src/RegDb.cpp +++ b/PiPedalCommon/src/RegDb.cpp @@ -18,6 +18,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "RegDb.hpp" + #include "ss.hpp" #include #include @@ -30,8 +31,12 @@ #include #include #include +#include "json_variant.hpp" +#include "json.hpp" #include +#include + #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 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 T NlSwap(T value) { if constexpr (std::endian::native == std::endian::big) { return value; - } else { - auto value_rep = std::bit_cast,T >(value); + } + else + { + auto value_rep = std::bit_cast, T>(value); std::ranges::reverse(value_rep); return std::bit_cast(value_rep); } } template -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&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 &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; #define BIT(n) (1 << n) template -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 cpu_to_be32(uint32_t value) { @@ -326,196 +329,203 @@ inline BigEndian cpu_to_be16(uint16_t value) return BigEndian(value); } - -inline uint16_t be16_to_cpu(const BigEndian&value) +inline uint16_t be16_to_cpu(const BigEndian &value) { return value.value(); } -inline uint32_t be32_to_cpu(const BigEndian&value) +inline uint32_t be32_to_cpu(const BigEndian &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 load_regdb(u8*pData) +static std::vector 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 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; -} \ No newline at end of file +} + + +static std::map getIsoNamesDict(const std::filesystem::path&filename) +{ + std::map 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 RegDb::getRegulatoryDomains(const std::filesystem::path&isoFilenamesfile) const +{ + std::map keyToNameDict = getIsoNamesDict(isoFilenamesfile); + std::map result; + + for (const auto ®ulation : this->regulations) + { + if (keyToNameDict.contains(regulation.reg_alpha2)) + { + result[regulation.reg_alpha2] = keyToNameDict[regulation.reg_alpha2]; + } + } + return result; +} diff --git a/PiPedalCommon/src/include/RegDb.hpp b/PiPedalCommon/src/include/RegDb.hpp index 6a27b02..01a45ba 100644 --- a/PiPedalCommon/src/include/RegDb.hpp +++ b/PiPedalCommon/src/include/RegDb.hpp @@ -61,6 +61,7 @@ namespace pipedal const WifiRegulations&getWifiRegulations(const std::string&countryIso3661) const; + std::map getRegulatoryDomains(const std::filesystem::path&namesFile="/etc/pipedal/config/iso_codes.json") const; private: bool isValid = false; diff --git a/config/iso_codes.json b/config/iso_codes.json new file mode 100644 index 0000000..0e970af --- /dev/null +++ b/config/iso_codes.json @@ -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" +} \ No newline at end of file diff --git a/react/src/PiPedalModel.tsx b/react/src/PiPedalModel.tsx index 17facf1..2ed7ac1 100644 --- a/react/src/PiPedalModel.tsx +++ b/react/src/PiPedalModel.tsx @@ -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("hello")) as number; diff --git a/src/PiPedalAlsaTest.cpp b/src/PiPedalAlsaTest.cpp index e7cf5d9..4b6e3c0 100644 --- a/src/PiPedalAlsaTest.cpp +++ b/src/PiPedalAlsaTest.cpp @@ -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(); } diff --git a/src/PiPedalModel.cpp b/src/PiPedalModel.cpp index 2c307ca..260e7ea 100644 --- a/src/PiPedalModel.cpp +++ b/src/PiPedalModel.cpp @@ -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 lock(mutex); return hasWifi; +} + +std::map PiPedalModel::GetWifiRegulatoryDomains() +{ + std::map 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; } \ No newline at end of file diff --git a/src/PiPedalModel.hpp b/src/PiPedalModel.hpp index 14bd646..ac5428c 100644 --- a/src/PiPedalModel.hpp +++ b/src/PiPedalModel.hpp @@ -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 &&listener); void OnLv2PluginsChanged(); void SetOnboarding(bool value); + std::map GetWifiRegulatoryDomains(); void UpdateDnsSd(); diff --git a/src/PiPedalSocket.cpp b/src/PiPedalSocket.cpp index 6e3b028..f1358cb 100644 --- a/src/PiPedalSocket.cpp +++ b/src/PiPedalSocket.cpp @@ -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()); diff --git a/src/Storage.cpp b/src/Storage.cpp index 9f1a96c..a25e4d7 100644 --- a/src/Storage.cpp +++ b/src/Storage.cpp @@ -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 &bindings) writer.write(bindings); } } -static bool hasBinding(std::vector &bindings, const std::string&name) +static bool hasBinding(std::vector &bindings, const std::string &name) { - for (auto&binding: bindings) + for (auto &binding : bindings) { if (binding.symbol() == name) { @@ -1534,7 +1546,8 @@ std::vector Storage::GetSystemMidiBindings() std::vector 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 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 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 Storage::GetFileList(const UiFileProperty &fileProperty) { if (!UiFileProperty::IsDirectoryNameValid(fileProperty.directory())) @@ -1652,22 +1664,21 @@ std::vector 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 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(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("","Home"); + FilePropertyDirectoryTree::ptr result = std::make_unique("", "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( - 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( - 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(rootDirectory.string(),"Home"); + FilePropertyDirectoryTree::ptr result = std::make_unique(rootDirectory.string(), "Home"); - FillSampleDirectoryTree(result.get(),rootDirectory); + FillSampleDirectoryTree(result.get(), rootDirectory); return result; } - } - const PluginPresetIndex &Storage::GetPluginPresetIndex() { return pluginPresetIndex; diff --git a/src/Storage.hpp b/src/Storage.hpp index 15df9e9..810e128 100644 --- a/src/Storage.hpp +++ b/src/Storage.hpp @@ -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; diff --git a/src/WifiChannelsTest.cpp b/src/WifiChannelsTest.cpp index 7ba602c..3c40c7f 100644 --- a/src/WifiChannelsTest.cpp +++ b/src/WifiChannelsTest.cpp @@ -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");