Browse Source

Add simple key=value dictionary, sorta like java.util.Properties.

Adam Ierymenko 12 years ago
parent
commit
fb975ead23
2 changed files with 160 additions and 0 deletions
  1. 136 0
      node/Dictionary.hpp
  2. 24 0
      selftest.cpp

+ 136 - 0
node/Dictionary.hpp

@@ -0,0 +1,136 @@
+/*
+ * ZeroTier One - Global Peer to Peer Ethernet
+ * Copyright (C) 2012-2013  ZeroTier Networks LLC
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * --
+ *
+ * ZeroTier may be used and distributed under the terms of the GPLv3, which
+ * are available at: http://www.gnu.org/licenses/gpl-3.0.html
+ *
+ * If you would like to embed ZeroTier into a commercial application or
+ * redistribute it in a modified binary form, please contact ZeroTier Networks
+ * LLC. Start here: http://www.zerotier.com/
+ */
+
+#ifndef _ZT_DICTIONARY_HPP
+#define _ZT_DICTIONARY_HPP
+
+#include <string>
+#include <map>
+#include "Constants.hpp"
+
+namespace ZeroTier {
+
+/**
+ * Simple key/value dictionary with string serialization
+ *
+ * The serialization format is a flat key=value with backslash escape.
+ * It does not support comments or other syntactic complexities.
+ */
+class Dictionary : public std::map<std::string,std::string>
+{
+public:
+	inline std::string toString() const
+	{
+		std::string s;
+
+		for(const_iterator kv(begin());kv!=end();++kv) {
+			_appendEsc(kv->first.data(),kv->first.length(),s);
+			s.push_back('=');
+			_appendEsc(kv->second.data(),kv->second.length(),s);
+			s.append(ZT_EOL_S);
+		}
+
+		return s;
+	}
+
+	inline void fromString(const char *s)
+	{
+		clear();
+		bool escapeState = false;
+		std::string keyBuf;
+		std::string *element = &keyBuf;
+		while (*s) {
+			if (escapeState) {
+				escapeState = false;
+				switch(*s) {
+					case '0':
+						element->push_back((char)0);
+						break;
+					case 'r':
+						element->push_back('\r');
+						break;
+					case 'n':
+						element->push_back('\n');
+						break;
+					default:
+						element->push_back(*s);
+						break;
+				}
+			} else {
+				if (*s == '\\') {
+					escapeState = true;
+				} else if (*s == '=') {
+					if (element == &keyBuf)
+						element = &((*this)[keyBuf]);
+				} else if ((*s == '\r')||(*s == '\n')) {
+					if ((element == &keyBuf)&&(keyBuf.length() > 0))
+						(*this)[keyBuf];
+					keyBuf = "";
+					element = &keyBuf;
+				} else element->push_back(*s);
+			}
+			++s;
+		}
+		if ((element == &keyBuf)&&(keyBuf.length() > 0))
+			(*this)[keyBuf];
+	}
+	inline void fromString(const std::string &s)
+	{
+		fromString(s.c_str());
+	}
+
+private:
+	static inline void _appendEsc(const char *data,unsigned int len,std::string &to)
+	{
+		for(unsigned int i=0;i<len;++i) {
+			switch(data[i]) {
+				case 0:
+					to.append("\\0");
+					break;
+				case '\r':
+					to.append("\\r");
+					break;
+				case '\n':
+					to.append("\\n");
+					break;
+				case '\\':
+					to.append("\\\\");
+					break;
+				case '=':
+					to.append("\\=");
+					break;
+				default:
+					to.push_back(data[i]);
+					break;
+			}
+		}
+	}
+};
+
+} // namespace ZeroTier
+
+#endif

+ 24 - 0
selftest.cpp

@@ -45,6 +45,7 @@
 #include "node/Peer.hpp"
 #include "node/Condition.hpp"
 #include "node/NodeConfig.hpp"
+#include "node/Dictionary.hpp"
 
 using namespace ZeroTier;
 
@@ -298,6 +299,29 @@ static int testOther()
 	}
 	std::cout << "PASS" << std::endl;
 
+	std::cout << "[other] Testing Dictionary... "; std::cout.flush();
+	for(int k=0;k<10000;++k) {
+		Dictionary a,b;
+		int nk = rand() % 32;
+		for(int q=0;q<nk;++q) {
+			std::string k,v;
+			int kl = (rand() % 512);
+			int vl = (rand() % 512);
+			for(int i=0;i<kl;++i)
+				k.push_back((char)rand());
+			for(int i=0;i<vl;++i)
+				v.push_back((char)rand());
+			a[k] = v;
+		}
+		std::string aser = a.toString();
+		b.fromString(aser);
+		if (a != b) {
+			std::cout << "FAIL!" << std::endl;
+			return -1;
+		}
+	}
+	std::cout << "PASS" << std::endl;
+
 	return 0;
 }