/* 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; }
/* write an object */ static size_t amf0_object_write(amf0_data * data, write_proc_t write_proc, void * user_data) { amf0_node * node; size_t w = 0; uint16_t filler = swap_uint16(0); uint8_t terminator = AMF0_TYPE_OBJECT_END; node = amf0_object_first(data); while (node != NULL) { w += amf0_string_write(amf0_object_get_name(node), write_proc, user_data); w += amf0_data_write(amf0_object_get_data(node), write_proc, user_data); node = amf0_object_next(node); } /* empty string is the last element */ w += write_proc(&filler, sizeof(uint16_t), user_data); /* an object ends with 0x09 */ w += write_proc(&terminator, sizeof(uint8_t), user_data); return w; }
/* dump AMF data into a stream as text */ void amf0_data_dump(FILE * stream, amf0_data * data, int indent_level) { if (data != NULL) { amf0_node * node; time_t time; struct tm * t; char datestr[128]; switch (data->type) { case AMF0_TYPE_NUMBER: fprintf(stream, "%.12g", data->number_data); break; case AMF0_TYPE_BOOLEAN: fprintf(stream, "%s", (data->boolean_data) ? "true" : "false"); break; case AMF0_TYPE_STRING: fprintf(stream, "\'%.*s\'", data->string_data.size, data->string_data.mbstr); break; case AMF0_TYPE_OBJECT: node = amf0_object_first(data); fprintf(stream, "{\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, amf0_object_get_name(node), indent_level+1); fprintf(stream, ": "); amf0_data_dump(stream, amf0_object_get_data(node), indent_level+1); node = amf0_object_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "}"); break; case AMF0_TYPE_NULL: fprintf(stream, "null"); break; case AMF0_TYPE_UNDEFINED: fprintf(stream, "undefined"); break; /*case AMF0_TYPE_REFERENCE:*/ case AMF0_TYPE_ECMA_ARRAY: node = amf0_associative_array_first(data); fprintf(stream, "{\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, amf0_associative_array_get_name(node), indent_level+1); fprintf(stream, " => "); amf0_data_dump(stream, amf0_associative_array_get_data(node), indent_level+1); node = amf0_associative_array_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "}"); break; case AMF0_TYPE_STRICT_ARRAY: node = amf0_array_first(data); fprintf(stream, "[\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, node->data, indent_level+1); node = amf0_array_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "]"); break; case AMF0_TYPE_DATE: time = amf0_date_to_time_t(data); tzset(); t = localtime(&time); strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S %z", t); fprintf(stream, "%s", datestr); break; /*case AMF0_TYPE_SIMPLEOBJECT:*/ case AMF0_TYPE_XML_DOCUMENT: break; case AMF0_TYPE_TYPED_OBJECT: break; default: break; } } }
/* dump AMF data into a stream as text */ void amf0_data_dump(FILE * stream, const amf0_data *data, int indent_level) { if (data != NULL) { amf0_node * node; time_t time; struct tm * t; char datestr[128]; switch (data->type) { case AMF0_TYPE_NUMBER: fprintf(stream, "%.12g", data->number_data); break; case AMF0_TYPE_BOOLEAN: fprintf(stream, "%s", (data->boolean_data) ? "true" : "false"); break; case AMF0_TYPE_STRING: fprintf(stream, "\'%.*s\'", data->string_data.size, data->string_data.mbstr); break; case AMF0_TYPE_OBJECT: node = amf0_object_first(data); fprintf(stream, "{\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, amf0_object_get_name(node), indent_level+1); fprintf(stream, ": "); amf0_data_dump(stream, amf0_object_get_data(node), indent_level+1); node = amf0_object_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "}"); break; case AMF0_TYPE_MOVIECLIP: fprintf(stream, "[movieclip]"); break; case AMF0_TYPE_NULL: fprintf(stream, "null"); break; case AMF0_TYPE_UNDEFINED: fprintf(stream, "undefined"); break; case AMF0_TYPE_REFERENCE: /* TODO */ fprintf(stream, "[reference]"); break; case AMF0_TYPE_ECMA_ARRAY: node = amf0_associative_array_first(data); fprintf(stream, "{\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, amf0_associative_array_get_name(node), indent_level+1); fprintf(stream, " => "); amf0_data_dump(stream, amf0_associative_array_get_data(node), indent_level+1); node = amf0_associative_array_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "}"); break; case AMF0_TYPE_OBJECT_END: fprintf(stream, "[object end]"); break; case AMF0_TYPE_STRICT_ARRAY: node = amf0_array_first(data); fprintf(stream, "[\n"); while (node != NULL) { fprintf(stream, "%*s", (indent_level+1)*4, ""); amf0_data_dump(stream, node->data, indent_level+1); node = amf0_array_next(node); fprintf(stream, "\n"); } fprintf(stream, "%*s", indent_level*4 + 1, "]"); break; case AMF0_TYPE_DATE: time = amf0_date_to_time_t(data); tzset(); t = localtime(&time); strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S %z", t); fprintf(stream, "%s", datestr); break; case AMF0_TYPE_LONG_STRING: /* TODO */ fprintf(stream, "[long string]"); break; case AMF0_TYPE_UNSUPPORTED: fprintf(stream, "[unsupported]"); break; case AMF0_TYPE_RECORDSET: fprintf(stream, "[recordset]"); break; case AMF0_TYPE_XML_DOCUMENT: /* TODO */ fprintf(stream, "[xml document]"); break; case AMF0_TYPE_TYPED_OBJECT: /* TODO */ fprintf(stream, "[typed object]"); break; default: fprintf(stream, "[unknown data type 0x%x]", data->type); break; } } }