#ifndef __amf_h #define __amf_h #include #include #include #include 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() { switch (m_type) { case AMF_STRING: m_value.string->clear(); break; case AMF_OBJECT: case AMF_ECMA_ARRAY: m_value.object->clear(); break; default: break; } } AMFType type() const { return m_type; } const std::string &as_string() const { if(m_type != AMF_STRING){ throw std::runtime_error("AMF not a string"); } return *m_value.string; } double as_number() const { switch (m_type) { case AMF_NUMBER: return m_value.number; case AMF_INTEGER: return m_value.integer; case AMF_BOOLEAN: return m_value.boolean; break; default: throw std::runtime_error("AMF not a number"); break; } } int as_integer() const { switch (m_type) { case AMF_NUMBER: return m_value.number; case AMF_INTEGER: return m_value.integer; case AMF_BOOLEAN: return m_value.boolean; break; default: throw std::runtime_error("AMF not a integer"); break; } } bool as_boolean() const { switch (m_type) { case AMF_NUMBER: return m_value.number; case AMF_INTEGER: return m_value.integer; case AMF_BOOLEAN: return m_value.boolean; break; default: throw std::runtime_error("AMF not a boolean"); break; } } const AMFValue &operator[](const std::string &s) const { if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) { throw std::runtime_error("AMF not a object"); } auto i = m_value.object->find(s); if (i == m_value.object->end()) { static AMFValue val(AMF_NULL); return val; } return i->second; } template void object_for_each(const FUN &fun) const { if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) { throw std::runtime_error("AMF not a object"); } for (auto & pr : *(m_value.object)) { fun(pr.first, pr.second); } } bool operator()() const { return m_type != AMF_NULL; } void set(const std::string &s, const AMFValue &val) { if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) { throw std::runtime_error("AMF not a object"); } m_value.object->emplace(s, val); } void add(const AMFValue &val) { if (m_type != AMF_STRICT_ARRAY) { throw std::runtime_error("AMF not a array"); } assert(m_type == AMF_STRICT_ARRAY); m_value.array->push_back(val); } private: typedef std::unordered_map mapType; typedef std::vector arrayType; AMFType m_type; union { std::string *string; double number; int integer; bool boolean; mapType *object; arrayType *array; } m_value; friend class AMFEncoder; const mapType &getMap() const { if (m_type != AMF_OBJECT && m_type != AMF_ECMA_ARRAY) { throw std::runtime_error("AMF not a object"); } return *m_value.object; } const arrayType &getArr() const { if (m_type != AMF_STRICT_ARRAY) { throw std::runtime_error("AMF not a array"); } return *m_value.array; } 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 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