diff options
Diffstat (limited to 'amf.cpp')
| -rw-r--r-- | amf.cpp | 429 |
1 files changed, 0 insertions, 429 deletions
diff --git a/amf.cpp b/amf.cpp deleted file mode 100644 index 2794419..0000000 --- a/amf.cpp +++ /dev/null @@ -1,429 +0,0 @@ -#include "amf.h" -#include "rtmputils.h" - -#include <stdexcept> -#include <string.h> -#include <arpa/inet.h> - -namespace { - -uint8_t peek(const Decoder *dec) -{ - if (dec->pos >= dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - return uint8_t(dec->buf[dec->pos]); -} - -uint8_t get_byte(Decoder *dec) -{ - if (dec->version == 0 && peek(dec) == AMF0_SWITCH_AMF3) { - debug("entering AMF3 mode\n"); - dec->pos++; - dec->version = 3; - } - - if (dec->pos >= dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - return uint8_t(dec->buf[dec->pos++]); -} - -} - -AMFValue::AMFValue(AMFType type) : - m_type(type) -{ - switch (m_type) { - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - m_value.object = new amf_object_t; - break; - case AMF_NUMBER: - case AMF_INTEGER: - case AMF_NULL: - case AMF_UNDEFINED: - break; - default: - assert(0); - } -} - -AMFValue::AMFValue(const std::string &s) : - m_type(AMF_STRING) -{ - m_value.string = new std::string(s); -} - -AMFValue::AMFValue(double n) : - m_type(AMF_NUMBER) -{ - m_value.number = n; -} - -AMFValue::AMFValue(int i) : - m_type(AMF_INTEGER) -{ - m_value.integer = i; -} - -AMFValue::AMFValue(bool b) : - m_type(AMF_BOOLEAN) -{ - m_value.boolean = b; -} - -AMFValue::AMFValue(const amf_object_t &object) : - m_type(AMF_OBJECT) -{ - m_value.object = new amf_object_t(object); -} - -AMFValue::AMFValue(const AMFValue &from) : - m_type(AMF_NULL) -{ - *this = from; -} - -AMFValue::~AMFValue() -{ - destroy(); -} - -void AMFValue::destroy() -{ - switch (m_type) { - case AMF_STRING: - delete m_value.string; - break; - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - delete m_value.object; - break; - case AMF_NULL: - case AMF_NUMBER: - case AMF_INTEGER: - case AMF_BOOLEAN: - case AMF_UNDEFINED: - break; - } -} - -void AMFValue::operator = (const AMFValue &from) -{ - destroy(); - m_type = from.m_type; - switch (m_type) { - case AMF_STRING: - m_value.string = new std::string(*from.m_value.string); - break; - case AMF_OBJECT: - case AMF_ECMA_ARRAY: - m_value.object = new amf_object_t(*from.m_value.object); - break; - case AMF_NUMBER: - m_value.number = from.m_value.number; - break; - case AMF_INTEGER: - m_value.integer = from.m_value.integer; - break; - case AMF_BOOLEAN: - m_value.boolean = from.m_value.boolean; - break; - default: - break; - } -} - -void amf_write(Encoder *enc, const std::string &s) -{ - enc->buf += char(AMF0_STRING); - uint16_t str_len = htons(s.size()); - enc->buf.append((char *) &str_len, 2); - enc->buf += s; -} - -void amf_write(Encoder *enc, int i) -{ - throw std::runtime_error("AMF0 does not have integers"); -} - -void amf_write(Encoder *enc, double n) -{ - enc->buf += char(AMF0_NUMBER); - uint64_t encoded = 0; -//#if defined(__i386__) || defined(__x86_64__) - /* Flash uses same floating point format as x86 */ - memcpy(&encoded, &n, 8); -//#endif - uint32_t val = htonl(encoded >> 32); - enc->buf.append((char *) &val, 4); - val = htonl(encoded); - enc->buf.append((char *) &val, 4); -} - -void amf_write(Encoder *enc, bool b) -{ - enc->buf += char(AMF0_BOOLEAN); - enc->buf += char(b); -} - -void amf_write_key(Encoder *enc, const std::string &s) -{ - uint16_t str_len = htons(s.size()); - enc->buf.append((char *) &str_len, 2); - enc->buf += s; -} - -void amf_write(Encoder *enc, const amf_object_t &object) -{ - enc->buf += char(AMF0_OBJECT); - for (amf_object_t::const_iterator i = object.begin(); - i != object.end(); ++i) { - amf_write_key(enc, i->first); - amf_write(enc, i->second); - } - amf_write_key(enc, ""); - enc->buf += char(AMF0_OBJECT_END); -} - -void amf_write_ecma(Encoder *enc, const amf_object_t &object) -{ - enc->buf += char(AMF0_ECMA_ARRAY); - uint32_t zero = 0; - enc->buf.append((char *) &zero, 4); - for (amf_object_t::const_iterator i = object.begin(); - i != object.end(); ++i) { - amf_write_key(enc, i->first); - amf_write(enc, i->second); - } - amf_write_key(enc, ""); - enc->buf += char(AMF0_OBJECT_END); -} - -void amf_write_null(Encoder *enc) -{ - enc->buf += char(AMF0_NULL); -} - -void amf_write(Encoder *enc, const AMFValue &value) -{ - switch (value.type()) { - case AMF_STRING: - amf_write(enc, value.as_string()); - break; - case AMF_NUMBER: - amf_write(enc, value.as_number()); - break; - case AMF_INTEGER: - amf_write(enc, value.as_integer()); - break; - case AMF_BOOLEAN: - amf_write(enc, value.as_boolean()); - break; - case AMF_OBJECT: - amf_write(enc, value.as_object()); - break; - case AMF_ECMA_ARRAY: - amf_write_ecma(enc, value.as_object()); - break; - case AMF_NULL: - amf_write_null(enc); - break; - default: - break; - } -} - -unsigned int load_amf3_integer(Decoder *dec) -{ - unsigned int value = 0; - for (int i = 0; i < 4; ++i) { - uint8_t b = get_byte(dec); - if (i == 3) { - /* use all bits from 4th byte */ - value = (value << 8) | b; - break; - } - value = (value << 7) | (b & 0x7f); - if ((b & 0x80) == 0) - break; - } - return value; -} - -std::string amf_load_string(Decoder *dec) -{ - size_t str_len = 0; - uint8_t type = get_byte(dec); - if (dec->version == 3) { - if (type != AMF3_STRING) { - throw std::runtime_error("Expected a string"); - } - str_len = load_amf3_integer(dec) / 2; - - } else { - if (type != AMF0_STRING) { - throw std::runtime_error("Expected a string"); - } - if (dec->pos + 2 > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - str_len = load_be16(&dec->buf[dec->pos]); - dec->pos += 2; - } - if (dec->pos + str_len > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - std::string s(dec->buf, dec->pos, str_len); - dec->pos += str_len; - return s; -} - -double amf_load_number(Decoder *dec) -{ - if (get_byte(dec) != AMF0_NUMBER) { - throw std::runtime_error("Expected a string"); - } - if (dec->pos + 8 > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - uint64_t val = ((uint64_t) load_be32(&dec->buf[dec->pos]) << 32) | - load_be32(&dec->buf[dec->pos + 4]); - double n = 0; -//#if defined(__i386__) || defined(__x86_64__) - /* Flash uses same floating point format as x86 */ - memcpy(&n, &val, 8); -//#endif - dec->pos += 8; - return n; -} - -int amf_load_integer(Decoder *dec) -{ - if (dec->version == 3) { - return load_amf3_integer(dec); - } else { - return amf_load_number(dec); - } -} - -bool amf_load_boolean(Decoder *dec) -{ - if (get_byte(dec) != AMF0_BOOLEAN) { - throw std::runtime_error("Expected a boolean"); - } - return get_byte(dec) != 0; -} - -std::string amf_load_key(Decoder *dec) -{ - if (dec->pos + 2 > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - size_t str_len = load_be16(&dec->buf[dec->pos]); - dec->pos += 2; - if (dec->pos + str_len > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - std::string s(dec->buf, dec->pos, str_len); - dec->pos += str_len; - return s; -} - -amf_object_t amf_load_object(Decoder *dec) -{ - amf_object_t object; - if (get_byte(dec) != AMF0_OBJECT) { - throw std::runtime_error("Expected an object"); - } - while (1) { - std::string key = amf_load_key(dec); - if (key.empty()) - break; - AMFValue value = amf_load(dec); - object.insert(std::make_pair(key, value)); - } - if (get_byte(dec) != AMF0_OBJECT_END) { - throw std::runtime_error("expected object end"); - } - return object; -} - -amf_object_t amf_load_ecma(Decoder *dec) -{ - /* ECMA array is the same as object, with 4 extra zero bytes */ - amf_object_t object; - if (get_byte(dec) != AMF0_ECMA_ARRAY) { - throw std::runtime_error("Expected an ECMA array"); - } - if (dec->pos + 4 > dec->buf.size()) { - throw std::runtime_error("Not enough data"); - } - dec->pos += 4; - while (1) { - std::string key = amf_load_key(dec); - if (key.empty()) - break; - AMFValue value = amf_load(dec); - object.insert(std::make_pair(key, value)); - } - if (get_byte(dec) != AMF0_OBJECT_END) { - throw std::runtime_error("expected object end"); - } - return object; -} - -AMFValue amf_load(Decoder *dec) -{ - uint8_t type = peek(dec); - if (dec->version == 3) { - switch (type) { - case AMF3_STRING: - return AMFValue(amf_load_string(dec)); - case AMF3_NUMBER: - return AMFValue(amf_load_number(dec)); - case AMF3_INTEGER: - return AMFValue(amf_load_integer(dec)); - case AMF3_FALSE: - dec->pos++; - return AMFValue(false); - case AMF3_TRUE: - dec->pos++; - return AMFValue(true); - case AMF3_OBJECT: - return AMFValue(amf_load_object(dec)); - case AMF3_ARRAY: - return AMFValue(amf_load_ecma(dec)); - case AMF3_NULL: - dec->pos++; - return AMFValue(AMF_NULL); - case AMF3_UNDEFINED: - dec->pos++; - return AMFValue(AMF_UNDEFINED); - default: - throw std::runtime_error(strf("Unsupported AMF3 type: %02x", type)); - } - } else { - switch (type) { - case AMF0_STRING: - return AMFValue(amf_load_string(dec)); - case AMF0_NUMBER: - return AMFValue(amf_load_number(dec)); - case AMF0_BOOLEAN: - return AMFValue(amf_load_boolean(dec)); - case AMF0_OBJECT: - return AMFValue(amf_load_object(dec)); - case AMF0_ECMA_ARRAY: - return AMFValue(amf_load_ecma(dec)); - case AMF0_NULL: - dec->pos++; - return AMFValue(AMF_NULL); - case AMF0_UNDEFINED: - dec->pos++; - return AMFValue(AMF_UNDEFINED); - default: - throw std::runtime_error(strf("Unsupported AMF0 type: %02x", type)); - } - } -} |
