amf.h 5.59 KB
Newer Older
xiongziliang committed
1
/*
xiongziliang committed
2 3
 * MIT License
 *
xiongziliang committed
4
 * Copyright (c) 2016-2019 xiongziliang <771730766@qq.com>
xiongziliang committed
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
xzl committed
26 27 28 29
#ifndef __amf_h
#define __amf_h

#include <assert.h>
xiongzilaing committed
30
#include <string>
xzl committed
31
#include <vector>
xiongzilaing committed
32
#include <unordered_map>
xiongziliang committed
33
#include <map>
34
#include <stdexcept>
xzl committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
enum AMFType {
	AMF_NUMBER,
	AMF_INTEGER,
	AMF_BOOLEAN,
	AMF_STRING,
	AMF_OBJECT,
	AMF_NULL,
	AMF_UNDEFINED,
	AMF_ECMA_ARRAY,
	AMF_STRICT_ARRAY,
};

class AMFValue;

class AMFValue {
public:

	AMFValue(AMFType type = AMF_NULL);
	AMFValue(const char *s);
	AMFValue(const std::string &s);
	AMFValue(double n);
	AMFValue(int i);
	AMFValue(bool b);
	AMFValue(const AMFValue &from);
	AMFValue(AMFValue &&from);
	AMFValue &operator =(const AMFValue &from);
	AMFValue &operator =(AMFValue &&from);
	~AMFValue();

	void clear() {
65
		switch (_type) {
xzl committed
66
		case AMF_STRING:
67
			_value.string->clear();
xzl committed
68 69 70
			break;
		case AMF_OBJECT:
		case AMF_ECMA_ARRAY:
71
			_value.object->clear();
xzl committed
72 73 74 75 76 77 78
			break;
		default:
			break;
		}
	}

	AMFType type() const {
79
		return _type;
xzl committed
80 81 82
	}

	const std::string &as_string() const {
83
		if(_type != AMF_STRING){
xzl committed
84 85
			throw std::runtime_error("AMF not a string");
		}
86
		return *_value.string;
xzl committed
87 88
	}
	double as_number() const {
89
		switch (_type) {
xzl committed
90
		case AMF_NUMBER:
91
			return _value.number;
xzl committed
92
		case AMF_INTEGER:
93
			return _value.integer;
xzl committed
94
		case AMF_BOOLEAN:
95
			return _value.boolean;
xzl committed
96 97 98 99 100 101 102
			break;
		default:
			throw std::runtime_error("AMF not a number");
			break;
		}
	}
	int as_integer() const {
103
		switch (_type) {
xzl committed
104
		case AMF_NUMBER:
105
			return _value.number;
xzl committed
106
		case AMF_INTEGER:
107
			return _value.integer;
xzl committed
108
		case AMF_BOOLEAN:
109
			return _value.boolean;
xzl committed
110 111 112 113 114 115 116
			break;
		default:
			throw std::runtime_error("AMF not a integer");
			break;
		}
	}
	bool as_boolean() const {
117
		switch (_type) {
xzl committed
118
		case AMF_NUMBER:
119
			return _value.number;
xzl committed
120
		case AMF_INTEGER:
121
			return _value.integer;
xzl committed
122
		case AMF_BOOLEAN:
123
			return _value.boolean;
xzl committed
124 125 126 127 128 129 130
			break;
		default:
			throw std::runtime_error("AMF not a boolean");
			break;
		}
	}

xiongziliang committed
131
	const AMFValue &operator[](const char *str) const {
132
		if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
xzl committed
133 134
			throw std::runtime_error("AMF not a object");
		}
135 136
		auto i = _value.object->find(str);
		if (i == _value.object->end()) {
xzl committed
137 138 139 140 141 142 143
			static AMFValue val(AMF_NULL);
			return val;
		}
		return i->second;
	}
	template<typename FUN>
	void object_for_each(const FUN &fun) const {
144
		if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
xzl committed
145 146
			throw std::runtime_error("AMF not a object");
		}
147
		for (auto & pr : *(_value.object)) {
xzl committed
148 149 150 151
			fun(pr.first, pr.second);
		}
	}

xiongziliang committed
152
	operator bool() const{
153
		return _type != AMF_NULL;
xzl committed
154 155
	}
	void set(const std::string &s, const AMFValue &val) {
156
		if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
xzl committed
157 158
			throw std::runtime_error("AMF not a object");
		}
159
		_value.object->emplace(s, val);
xzl committed
160 161
	}
	void add(const AMFValue &val) {
162
		if (_type != AMF_STRICT_ARRAY) {
xzl committed
163 164
			throw std::runtime_error("AMF not a array");
		}
165 166
		assert(_type == AMF_STRICT_ARRAY);
		_value.array->push_back(val);
xzl committed
167 168 169
	}

private:
xiongziliang committed
170
	typedef std::map<std::string, AMFValue> mapType;
xzl committed
171 172
	typedef std::vector<AMFValue> arrayType;

173
	AMFType _type;
xzl committed
174 175 176 177 178 179 180
	union {
		std::string *string;
		double number;
		int integer;
		bool boolean;
		mapType *object;
		arrayType *array;
181
	} _value;
xzl committed
182 183 184

	friend class AMFEncoder;
	const mapType &getMap() const {
185
		if (_type != AMF_OBJECT && _type != AMF_ECMA_ARRAY) {
xzl committed
186 187
			throw std::runtime_error("AMF not a object");
		}
188
		return *_value.object;
xzl committed
189 190
	}
	const arrayType &getArr() const {
191
		if (_type != AMF_STRICT_ARRAY) {
xzl committed
192 193
			throw std::runtime_error("AMF not a array");
		}
194
		return *_value.array;
xzl committed
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250
	}
	inline void destroy();
	inline void init();
};

class AMFDecoder {
public:
	AMFDecoder(const std::string &_buf, size_t _pos, int _version = 0) :
			buf(_buf), pos(_pos), version(_version) {
	}

	int getVersion() const {
		return version;
	}

	template<typename TP>
	TP load();



private:
	const std::string &buf;
	size_t pos;
	int version;

	std::string load_key();
	AMFValue load_object();
	AMFValue load_ecma();
	AMFValue load_arr();
	uint8_t front();
	uint8_t pop_front();
};

class AMFEncoder {
public:
	AMFEncoder & operator <<(const char *s);
	AMFEncoder & operator <<(const std::string &s);
	AMFEncoder & operator <<(std::nullptr_t);
	AMFEncoder & operator <<(const int n);
	AMFEncoder & operator <<(const double n);
	AMFEncoder & operator <<(const bool b);
	AMFEncoder & operator <<(const AMFValue &value);
	const std::string data() const {
		return buf;
	}
	void clear() {
		buf.clear();
	}
private:
	void write_key(const std::string &s);
	AMFEncoder &write_undefined();
	std::string buf;
};


#endif