1 // Copyright 2019 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef DISCOVERY_DNSSD_PUBLIC_DNS_SD_TXT_RECORD_H_ 6 #define DISCOVERY_DNSSD_PUBLIC_DNS_SD_TXT_RECORD_H_ 7 8 #include <functional> 9 #include <map> 10 #include <set> 11 #include <string> 12 #include <vector> 13 14 #include "platform/base/error.h" 15 16 namespace openscreen { 17 namespace discovery { 18 19 class DnsSdTxtRecord { 20 public: 21 using ValueRef = std::reference_wrapper<const std::vector<uint8_t>>; 22 23 // Returns whether the provided key value pair is valid for a TXT record. 24 static bool IsValidTxtValue(const std::string& key, 25 const std::vector<uint8_t>& value); 26 static bool IsValidTxtValue(const std::string& key, const std::string& value); 27 static bool IsValidTxtValue(const std::string& key, uint8_t value); 28 29 // Sets the value currently stored in this DNS-SD TXT record. Returns error 30 // if the provided key is already set or if either the key or value is 31 // invalid, and Error::None() otherwise. Keys are case-insensitive. Setting a 32 // value or flag which was already set will overwrite the previous one, and 33 // setting a value with a key which was previously associated with a flag 34 // erases the flag's value and vice versa. 35 Error SetValue(const std::string& key, std::vector<uint8_t> value); 36 Error SetValue(const std::string& key, const std::string& value); 37 Error SetFlag(const std::string& key, bool value); 38 39 // Reads the value associated with the provided key, or an error if the key 40 // is mapped to the opposite type or the query is otherwise invalid. Keys are 41 // case-insensitive. 42 // NOTE: If GetValue is called on a key assigned to a flag, an ItemNotFound 43 // error will be returned. If GetFlag is called on a key assigned to a value, 44 // 'false' will be returned. 45 ErrorOr<ValueRef> GetValue(const std::string& key) const; 46 ErrorOr<bool> GetFlag(const std::string& key) const; 47 48 // Clears an existing TxtRecord value associated with the given key. If the 49 // key is not found, these methods return successfully without removing any 50 // keys. 51 // NOTE: If ClearValue is called on a key assigned to a flag (or ClearFlag for 52 // a value), no error will be returned but no value will be cleared. 53 Error ClearValue(const std::string& key); 54 Error ClearFlag(const std::string& key); 55 IsEmpty()56 inline bool IsEmpty() const { 57 return key_value_txt_.empty() && boolean_txt_.empty(); 58 } 59 60 // Returns the data for the TXT record represented by this object. 61 // Specifically, it returns a vector containing an entry for each string s in 62 // boolean_txt_ of the form 's' (without quotes) and an entry for each key- 63 // value pair (key, value) in key_value_txt_ of the form 'key=value' (without 64 // quotes). 65 std::vector<std::vector<uint8_t>> GetData() const; 66 67 private: 68 struct CaseInsensitiveComparison { 69 bool operator()(const std::string& lhs, const std::string& rhs) const; 70 }; 71 72 // Validations for keys and (key, value) pairs. 73 static bool IsKeyValid(const std::string& key); 74 75 // Set of (key, value) pairs associated with this TXT record. 76 // NOTE: The same string name can only occur in one of key_value_txt_, 77 // boolean_txt_. 78 std::map<std::string, std::vector<uint8_t>, CaseInsensitiveComparison> 79 key_value_txt_; 80 81 // Set of named booleans associated with this TXT record. All stored boolean 82 // names are 'true', as 'false' values are not stored. 83 // NOTE: The same string name can only occur in one of key_value_txt_, 84 // boolean_txt_. 85 std::set<std::string, CaseInsensitiveComparison> boolean_txt_; 86 87 friend bool operator<(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs); 88 }; 89 90 inline bool operator<(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 91 if (lhs.boolean_txt_ != rhs.boolean_txt_) { 92 return lhs.boolean_txt_ < rhs.boolean_txt_; 93 } 94 95 return lhs.key_value_txt_ < rhs.key_value_txt_; 96 } 97 98 inline bool operator>(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 99 return rhs < lhs; 100 } 101 102 inline bool operator<=(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 103 return !(rhs > lhs); 104 } 105 106 inline bool operator>=(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 107 return !(rhs < lhs); 108 } 109 110 inline bool operator==(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 111 return lhs <= rhs && lhs >= rhs; 112 } 113 114 inline bool operator!=(const DnsSdTxtRecord& lhs, const DnsSdTxtRecord& rhs) { 115 return !(lhs == rhs); 116 } 117 118 } // namespace discovery 119 } // namespace openscreen 120 121 #endif // DISCOVERY_DNSSD_PUBLIC_DNS_SD_TXT_RECORD_H_ 122