/* determines the size of the given AMF data */ size_t amf0_data_size(amf0_data * data) { size_t s = 0; amf0_node * node; if (data != NULL) { s += sizeof(uint8_t); switch (data->type) { case AMF0_TYPE_NUMBER: s += sizeof(number64_t); break; case AMF0_TYPE_BOOLEAN: s += sizeof(uint8_t); break; case AMF0_TYPE_STRING: s += sizeof(uint16_t) + (size_t)amf0_string_get_size(data); break; case AMF0_TYPE_OBJECT: node = amf0_object_first(data); while (node != NULL) { s += sizeof(uint16_t) + (size_t)amf0_string_get_size(amf0_object_get_name(node)); s += (size_t)amf0_data_size(amf0_object_get_data(node)); node = amf0_object_next(node); } s += sizeof(uint16_t) + sizeof(uint8_t); break; case AMF0_TYPE_NULL: case AMF0_TYPE_UNDEFINED: break; /*case AMF0_TYPE_REFERENCE:*/ case AMF0_TYPE_ECMA_ARRAY: s += sizeof(uint32_t); node = amf0_associative_array_first(data); while (node != NULL) { s += sizeof(uint16_t) + (size_t)amf0_string_get_size(amf0_associative_array_get_name(node)); s += (size_t)amf0_data_size(amf0_associative_array_get_data(node)); node = amf0_associative_array_next(node); } s += sizeof(uint16_t) + sizeof(uint8_t); break; case AMF0_TYPE_STRICT_ARRAY: s += sizeof(uint32_t); node = amf0_array_first(data); while (node != NULL) { s += (size_t)amf0_data_size(amf0_array_get(node)); node = amf0_array_next(node); } break; case AMF0_TYPE_DATE: s += sizeof(number64_t) + sizeof(int16_t); break; /*case AMF0_TYPE_SIMPLEOBJECT:*/ case AMF0_TYPE_XML_DOCUMENT: case AMF0_TYPE_TYPED_OBJECT: case AMF0_TYPE_OBJECT_END: break; /* end of composite object */ default: break; } } return s; }
/* read an associative array */ static amf0_data * amf0_associative_array_read(read_proc_t read_proc, void * user_data) { amf0_data * name; amf0_data * element; uint32_t size; uint8_t error_code; amf0_data * data; data = amf0_associative_array_new(); if (data == NULL) { return NULL; } /* we ignore the 32 bits array size marker */ if (read_proc(&size, sizeof(uint32_t), user_data) < sizeof(uint32_t)) { amf0_data_free(data); return amf0_data_error(AMF0_ERROR_EOF); } while(1) { name = amf0_string_read(read_proc, user_data); error_code = amf0_data_get_error(name); if (error_code != AMF0_ERROR_OK) { /* invalid name: error */ amf0_data_free(name); amf0_data_free(data); return amf0_data_error(error_code); } element = amf0_data_read(read_proc, user_data); error_code = amf0_data_get_error(element); if (amf0_string_get_size(name) == 0 || error_code == AMF0_ERROR_END_TAG || error_code == AMF0_ERROR_UNKNOWN_TYPE) { /* end tag or unknown element: end of data, exit loop */ amf0_data_free(name); amf0_data_free(element); break; } else if (error_code != AMF0_ERROR_OK) { amf0_data_free(name); amf0_data_free(data); amf0_data_free(element); return amf0_data_error(error_code); } if (amf0_associative_array_add(data, (char *)amf0_string_get_bytes(name), element) == NULL) { amf0_data_free(name); amf0_data_free(element); amf0_data_free(data); return NULL; } else { amf0_data_free(name); } } return data; }
/* clone AMF data */ amf0_data * amf0_data_clone(amf0_data * data) { /* we copy data recursively */ if (data != NULL) { switch (data->type) { case AMF0_TYPE_NUMBER: return amf0_number_new(amf0_number_get_value(data)); case AMF0_TYPE_BOOLEAN: return amf0_boolean_new(amf0_boolean_get_value(data)); case AMF0_TYPE_STRING: if (data->string_data.mbstr != NULL) { return amf0_string_new((uint8_t *)strdup((char *)amf0_string_get_uint8_ts(data)), amf0_string_get_size(data)); } else { return amf0_str(NULL); } case AMF0_TYPE_NULL: return NULL; case AMF0_TYPE_UNDEFINED: return NULL; /*case AMF0_TYPE_REFERENCE:*/ case AMF0_TYPE_OBJECT: case AMF0_TYPE_ECMA_ARRAY: case AMF0_TYPE_STRICT_ARRAY: { amf0_data * d = amf0_data_new(data->type); if (d != NULL) { amf0_list_init(&d->list_data); amf0_list_clone(&data->list_data, &d->list_data); } return d; } case AMF0_TYPE_DATE: return amf0_date_new(amf0_date_get_milliseconds(data), amf0_date_get_timezone(data)); /*case AMF0_TYPE_SIMPLEOBJECT:*/ case AMF0_TYPE_XML_DOCUMENT: return NULL; case AMF0_TYPE_TYPED_OBJECT: return NULL; } } return NULL; }
/* clone AMF data */ amf0_data * amf0_data_clone(const amf0_data *data) { /* we copy data recursively */ if (data != NULL) { switch (data->type) { case AMF0_TYPE_NUMBER: return amf0_number_new(amf0_number_get_value(data)); case AMF0_TYPE_BOOLEAN: return amf0_boolean_new(amf0_boolean_get_value(data)); case AMF0_TYPE_STRING: if (data->string_data.mbstr != NULL) { return amf0_string_new((uint8_t *)strdup((char *)amf0_string_get_bytes(data)), amf0_string_get_size(data)); } else { return amf0_str(NULL); } case AMF0_TYPE_MOVIECLIP: /* not supported */ case AMF0_TYPE_NULL: case AMF0_TYPE_UNDEFINED: case AMF0_TYPE_REFERENCE: /* TODO */ case AMF0_TYPE_OBJECT_END: return NULL; case AMF0_TYPE_OBJECT: case AMF0_TYPE_ECMA_ARRAY: case AMF0_TYPE_STRICT_ARRAY: { amf0_data * d = amf0_data_new(data->type); if (d != NULL) { amf0_list_init(&d->list_data); amf0_list_clone(&data->list_data, &d->list_data); } return d; } case AMF0_TYPE_DATE: return amf0_date_new(amf0_date_get_milliseconds(data), amf0_date_get_timezone(data)); case AMF0_TYPE_LONG_STRING: /* TODO */ case AMF0_TYPE_UNSUPPORTED: /* TODO */ case AMF0_TYPE_RECORDSET: /* not supported */ case AMF0_TYPE_XML_DOCUMENT: /* TODO */ case AMF0_TYPE_TYPED_OBJECT: /* TODO */ default: return NULL; } } return NULL; }