/* * ZeroTier One - Network Virtualization Everywhere * Copyright (C) 2011-2016 ZeroTier, Inc. https://www.zerotier.com/ * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #ifndef ZT_DICTIONARY_HPP #define ZT_DICTIONARY_HPP #include "Constants.hpp" #include "Utils.hpp" #include #include #define ZT_DICTIONARY_MAX_SIZE 16384 namespace ZeroTier { /** * A small key=value store * * This stores data in the form of a blob of max size ZT_DICTIONARY_MAX_SIZE. * It's *technically* human-readable to be backward compatible with old format * netconfs, but it can store binary data and doing this will negatively impact * its human-readability. * * In any case nulls are always escaped, making the serialized form of this * object a valid null-terminated C-string. Appending it to a buffer appends * it as such. * * Keys cannot contain binary data, CR/LF, nulls, or the equals (=) sign. * Adding such a key will result in an invalid entry (but isn't dangerous). * * There is code to test and fuzz this in selftest.cpp. */ class Dictionary { public: Dictionary() { _d[0] = (char)0; } Dictionary(const char *s) { Utils::scopy(_d,sizeof(_d),s); } inline void load(const char *s) { Utils::scopy(_d,sizeof(_d),s); } /** * Delete all entries */ inline void clear() { _d[0] = (char)0; } /** * @return Size of dictionary in bytes not including terminating NULL */ inline unsigned int sizeBytes() const { for(unsigned int i=0;i= destlen) { dest[destlen-1] = (char)0; return (int)(destlen-1); } dest[j++] = *p; } ++p; } } } else { ++p; } } } } /** * @param key Key to look up * @param dfl Default value if not found in dictionary (a key with an empty value is considered not found) * @return Boolean value of key or 'dfl' if not found */ bool getBoolean(const char *key,bool dfl = false) const { char tmp[128]; if (this->get(key,tmp,sizeof(tmp)) >= 1) { switch(tmp[0]) { case '1': case 't': case 'T': case 'y': case 'Y': return true; default: return false; } } return dfl; } /** * @param key Key to look up * @param dfl Default value or 0 if unspecified * @return Decoded hex UInt value or 'dfl' if not found */ inline uint64_t getHexUInt(const char *key,uint64_t dfl = 0) const { char tmp[128]; if (this->get(key,tmp,sizeof(tmp)) >= 1) return Utils::hexStrToU64(tmp); return dfl; } /** * Add a new key=value pair * * If the key is already present this will append another, but the first * will always be returned by get(). There is no erase(). This is designed * to be generated and shipped, not as an editable data structure. * * @param key Key -- nulls, CR/LF, and equals (=) are illegal characters * @param value Value to set * @param vlen Length of value in bytes or -1 to treat value[] as a C-string and look for terminating 0 * @return True if there was enough room to add this key=value pair */ inline bool add(const char *key,const char *value,int vlen = -1) { for(unsigned int i=0;iadd(key,(value) ? "1" : "0",1); } /** * Add a 64-bit integer (unsigned) as a hex value */ inline void add(const char *key,uint64_t value) { char tmp[128]; Utils::snprintf(tmp,sizeof(tmp),"%llx",(unsigned long long)value); this->add(key,tmp,-1); } /** * @param key Key to check * @return True if key is present */ inline bool contains(const char *key) const { char tmp[2]; return (this->get(key,tmp,2) >= 0); } /** * @return Dictionary data as a 0-terminated C-string */ inline const char *data() const { return _d; } private: char _d[ZT_DICTIONARY_MAX_SIZE]; }; } // namespace ZeroTier #endif