#include #include #include namespace lcamera_dev { namespace { bool startsWith(const std::string& text, const std::string& prefix) { return text.size() >= prefix.size() && text.compare(0, prefix.size(), prefix) == 0; } SelectorCriterionKind parseCriterionKind(const std::string& prefixToken) { if (prefixToken == "lcamera-id") { return SelectorCriterionKind::LibcameraId; } if (prefixToken == "index") { return SelectorCriterionKind::Index; } if (prefixToken == "model-substr") { return SelectorCriterionKind::ModelSubstr; } if (prefixToken == "model") { return SelectorCriterionKind::Model; } if (prefixToken == "location") { return SelectorCriterionKind::Location; } throw std::runtime_error( "Unknown deviceSelector prefix: " + prefixToken); } SelectorCriterion parseCriterionClause(const std::string& clause) { const std::string trimmedClause = trimWhitespace(clause); if (trimmedClause.empty()) { throw std::runtime_error("Empty deviceSelector clause"); } const size_t colonPos = trimmedClause.find(':'); if (colonPos == std::string::npos) { return SelectorCriterion{ SelectorCriterionKind::LibcameraId, trimmedClause }; } const std::string prefixToken = trimWhitespace( trimmedClause.substr(0, colonPos)); const std::string value = trimWhitespace( trimmedClause.substr(colonPos + 1)); if (value.empty()) { throw std::runtime_error( "deviceSelector clause has empty value for prefix " + prefixToken); } return SelectorCriterion{ parseCriterionKind(prefixToken), value }; } } // namespace std::string trimWhitespace(const std::string& text) { size_t start = 0; while (start < text.size() && std::isspace(static_cast(text[start]))) { ++start; } size_t end = text.size(); while (end > start && std::isspace(static_cast(text[end - 1]))) { --end; } return text.substr(start, end - start); } std::vector parseDeviceSelector( const std::string& deviceSelector) { const std::string trimmedSelector = trimWhitespace(deviceSelector); if (trimmedSelector.empty()) { throw std::runtime_error("deviceSelector is empty"); } std::vector criteria; std::string currentClause; currentClause.reserve(trimmedSelector.size()); for (size_t i = 0; i < trimmedSelector.size(); ++i) { const char ch = trimmedSelector[i]; if (ch == '\\' && i + 1 < trimmedSelector.size() && trimmedSelector[i + 1] == ';') { currentClause.push_back(';'); ++i; continue; } if (ch == ';') { criteria.push_back(parseCriterionClause(currentClause)); currentClause.clear(); continue; } currentClause.push_back(ch); } criteria.push_back(parseCriterionClause(currentClause)); return criteria; } } // namespace lcamera_dev