1 /*
2 $Id$
3
4 FLV Metadata updater
5
6 Copyright (C) 2007-2010 Marc Noirot <marc.noirot AT gmail.com>
7
8 This file is part of FLVMeta.
9
10 FLVMeta is free software; you can redistribute it and/or modify
11 it under the terms of the GNU General Public License as published by
12 the Free Software Foundation; either version 2 of the License, or
13 (at your option) any later version.
14
15 FLVMeta is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with FLVMeta; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 */
24 #include <string.h>
25
26 #include "flvmeta.h"
27 #include "amf.h"
28
29 /* function common to all array types */
amf_list_init(amf_list * list)30 static void amf_list_init(amf_list * list) {
31 if (list != NULL) {
32 list->size = 0;
33 list->first_element = NULL;
34 list->last_element = NULL;
35 }
36 }
37
amf_list_push(amf_list * list,amf_data * data)38 static amf_data * amf_list_push(amf_list * list, amf_data * data) {
39 amf_node * node = (amf_node*)malloc(sizeof(amf_node));
40 if (node != NULL) {
41 node->data = data;
42 node->next = NULL;
43 node->prev = NULL;
44 if (list->size == 0) {
45 list->first_element = node;
46 list->last_element = node;
47 }
48 else {
49 list->last_element->next = node;
50 node->prev = list->last_element;
51 list->last_element = node;
52 }
53 ++(list->size);
54 return data;
55 }
56 return NULL;
57 }
58
amf_list_insert_before(amf_list * list,amf_node * node,amf_data * data)59 static amf_data * amf_list_insert_before(amf_list * list, amf_node * node, amf_data * data) {
60 if (node != NULL) {
61 amf_node * new_node = (amf_node*)malloc(sizeof(amf_node));
62 if (new_node != NULL) {
63 new_node->next = node;
64 new_node->prev = node->prev;
65
66 if (node->prev != NULL) {
67 node->prev->next = new_node;
68 node->prev = new_node;
69 }
70 if (node == list->first_element) {
71 list->first_element = new_node;
72 }
73 ++(list->size);
74 new_node->data = data;
75 return data;
76 }
77 }
78 return NULL;
79 }
80
amf_list_insert_after(amf_list * list,amf_node * node,amf_data * data)81 static amf_data * amf_list_insert_after(amf_list * list, amf_node * node, amf_data * data) {
82 if (node != NULL) {
83 amf_node * new_node = (amf_node*)malloc(sizeof(amf_node));
84 if (new_node != NULL) {
85 new_node->next = node->next;
86 new_node->prev = node;
87
88 if (node->next != NULL) {
89 node->next->prev = new_node;
90 node->next = new_node;
91 }
92 if (node == list->last_element) {
93 list->last_element = new_node;
94 }
95 ++(list->size);
96 new_node->data = data;
97 return data;
98 }
99 }
100 return NULL;
101 }
102
amf_list_delete(amf_list * list,amf_node * node)103 static amf_data * amf_list_delete(amf_list * list, amf_node * node) {
104 amf_data * data = NULL;
105 if (node != NULL) {
106 if (node->next != NULL) {
107 node->next->prev = node->prev;
108 }
109 if (node->prev != NULL) {
110 node->prev->next = node->next;
111 }
112 if (node == list->first_element) {
113 list->first_element = node->next;
114 }
115 if (node == list->last_element) {
116 list->last_element = node->prev;
117 }
118 data = node->data;
119 free(node);
120 --(list->size);
121 }
122 return data;
123 }
124
amf_list_get_at(amf_list * list,uint32 n)125 static amf_data * amf_list_get_at(amf_list * list, uint32 n) {
126 if (n < list->size) {
127 uint32 i;
128 amf_node * node = list->first_element;
129 for (i = 0; i < n; ++i) {
130 node = node->next;
131 }
132 return node->data;
133 }
134 return NULL;
135 }
136
amf_list_pop(amf_list * list)137 static amf_data * amf_list_pop(amf_list * list) {
138 return amf_list_delete(list, list->last_element);
139 }
140
amf_list_first(amf_list * list)141 static amf_node * amf_list_first(amf_list * list) {
142 return list->first_element;
143 }
144
amf_list_last(amf_list * list)145 static amf_node * amf_list_last(amf_list * list) {
146 return list->last_element;
147 }
148
amf_list_clear(amf_list * list)149 static void amf_list_clear(amf_list * list) {
150 amf_node * tmp;
151 amf_node * node = list->first_element;
152 while (node != NULL) {
153 amf_data_free(node->data);
154 tmp = node;
155 node = node->next;
156 free(tmp);
157 }
158 list->size = 0;
159 }
160
amf_list_clone(amf_list * list,amf_list * out_list)161 static amf_list * amf_list_clone(amf_list * list, amf_list * out_list) {
162 amf_node * node;
163 node = list->first_element;
164 while (node != NULL) {
165 amf_list_push(out_list, amf_data_clone(node->data));
166 node = node->next;
167 }
168 return out_list;
169 }
170
171 /* structure used to mimic a stream with a memory buffer */
172 typedef struct __buffer_context {
173 byte * start_address;
174 byte * current_address;
175 size_t buffer_size;
176 } buffer_context;
177
178 /* callback function to mimic fread using a memory buffer */
buffer_read(void * out_buffer,size_t size,void * user_data)179 static size_t buffer_read(void * out_buffer, size_t size, void * user_data) {
180 buffer_context * ctxt = (buffer_context *)user_data;
181 if (ctxt->current_address >= ctxt->start_address &&
182 ctxt->current_address + size <= ctxt->start_address + ctxt->buffer_size) {
183
184 memcpy(out_buffer, ctxt->current_address, size);
185 ctxt->current_address += size;
186 return size;
187 }
188 else {
189 return 0;
190 }
191 }
192
193 /* callback function to mimic fwrite using a memory buffer */
buffer_write(const void * in_buffer,size_t size,void * user_data)194 static size_t buffer_write(const void * in_buffer, size_t size, void * user_data) {
195 buffer_context * ctxt = (buffer_context *)user_data;
196 if (ctxt->current_address >= ctxt->start_address &&
197 ctxt->current_address + size <= ctxt->start_address + ctxt->buffer_size) {
198
199 memcpy(ctxt->current_address, in_buffer, size);
200 ctxt->current_address += size;
201 return size;
202 }
203 else {
204 return 0;
205 }
206 }
207
208 /* allocate an AMF data object */
amf_data_new(byte type)209 amf_data * amf_data_new(byte type) {
210 amf_data * data = (amf_data*)malloc(sizeof(amf_data));
211 if (data != NULL) {
212 data->type = type;
213 }
214 return data;
215 }
216
217 /* read AMF data from buffer */
amf_data_buffer_read(byte * buffer,size_t maxbytes)218 amf_data * amf_data_buffer_read(byte * buffer, size_t maxbytes) {
219 buffer_context ctxt;
220 ctxt.start_address = ctxt.current_address = buffer;
221 ctxt.buffer_size = maxbytes;
222 return amf_data_read(buffer_read, &ctxt);
223 }
224
225 /* write AMF data to buffer */
amf_data_buffer_write(amf_data * data,byte * buffer,size_t maxbytes)226 size_t amf_data_buffer_write(amf_data * data, byte * buffer, size_t maxbytes) {
227 buffer_context ctxt;
228 ctxt.start_address = ctxt.current_address = buffer;
229 ctxt.buffer_size = maxbytes;
230 return amf_data_write(data, buffer_write, &ctxt);
231 }
232
233 /* callback function to read data from a file stream */
file_read(void * out_buffer,size_t size,void * user_data)234 static size_t file_read(void * out_buffer, size_t size, void * user_data) {
235 return fread(out_buffer, sizeof(byte), size, (FILE *)user_data);
236 }
237
238 /* callback function to write data to a file stream */
file_write(const void * in_buffer,size_t size,void * user_data)239 static size_t file_write(const void * in_buffer, size_t size, void * user_data) {
240 return fwrite(in_buffer, sizeof(byte), size, (FILE *)user_data);
241 }
242
243 /* load AMF data from a file stream */
amf_data_file_read(FILE * stream)244 amf_data * amf_data_file_read(FILE * stream) {
245 return amf_data_read(file_read, stream);
246 }
247
248 /* write AMF data into a file stream */
amf_data_file_write(amf_data * data,FILE * stream)249 size_t amf_data_file_write(amf_data * data, FILE * stream) {
250 return amf_data_write(data, file_write, stream);
251 }
252
253 /* read a number */
amf_number_read(amf_read_proc read_proc,void * user_data)254 static amf_data * amf_number_read(amf_read_proc read_proc, void * user_data) {
255 number64_be val;
256 if (read_proc(&val, sizeof(number64_be), user_data) == sizeof(number64_be)) {
257 return amf_number_new(swap_number64(val));
258 }
259 return NULL;
260 }
261
262 /* read a boolean */
amf_boolean_read(amf_read_proc read_proc,void * user_data)263 static amf_data * amf_boolean_read(amf_read_proc read_proc, void * user_data) {
264 uint8 val;
265 if (read_proc(&val, sizeof(uint8), user_data) == sizeof(uint8)) {
266 return amf_boolean_new(val);
267 }
268 return NULL;
269 }
270
271 /* read a string */
amf_string_read(amf_read_proc read_proc,void * user_data)272 static amf_data * amf_string_read(amf_read_proc read_proc, void * user_data) {
273 uint16_be strsize;
274 byte * buffer;
275 if (read_proc(&strsize, sizeof(uint16_be), user_data) == sizeof(uint16_be)) {
276 strsize = swap_uint16(strsize);
277 if (strsize > 0) {
278 buffer = (byte*)calloc(strsize, sizeof(byte));
279 if (buffer != NULL && read_proc(buffer, strsize, user_data) == strsize) {
280 amf_data * data = amf_string_new(buffer, strsize);
281 free(buffer);
282 return data;
283 }
284 }
285 else {
286 return amf_string_new(NULL, 0);
287 }
288 }
289 return NULL;
290 }
291
292 /* read an object */
amf_object_read(amf_read_proc read_proc,void * user_data)293 static amf_data * amf_object_read(amf_read_proc read_proc, void * user_data) {
294 amf_data * data = amf_object_new();
295 if (data != NULL) {
296 amf_data * name;
297 amf_data * element;
298 while (1) {
299 name = amf_string_read(read_proc, user_data);
300 if (name != NULL) {
301 element = amf_data_read(read_proc, user_data);
302 if (element != NULL) {
303 if (amf_object_add(data, (char *)amf_string_get_bytes(name), element) == NULL) {
304 amf_data_free(name);
305 amf_data_free(element);
306 amf_data_free(data);
307 return NULL;
308 }
309 else {
310 amf_data_free(name);
311 }
312 }
313 else {
314 amf_data_free(name);
315 break;
316 }
317 }
318 else {
319 /* invalid name: error */
320 amf_data_free(data);
321 return NULL;
322 }
323 }
324 }
325 return data;
326 }
327
328 /* read an associative array */
amf_associative_array_read(amf_read_proc read_proc,void * user_data)329 static amf_data * amf_associative_array_read(amf_read_proc read_proc, void * user_data) {
330 amf_data * data = amf_associative_array_new();
331 if (data != NULL) {
332 amf_data * name;
333 amf_data * element;
334 uint32_be size;
335 if (read_proc(&size, sizeof(uint32_be), user_data) == sizeof(uint32_be)) {
336 /* we ignore the 32 bits array size marker */
337 while(1) {
338 name = amf_string_read(read_proc, user_data);
339 if (name != NULL) {
340 element = amf_data_read(read_proc, user_data);
341 if (element != NULL) {
342 if (amf_associative_array_add(data, (char *)amf_string_get_bytes(name), element) == NULL) {
343 amf_data_free(name);
344 amf_data_free(element);
345 amf_data_free(data);
346 return NULL;
347 }
348 else {
349 amf_data_free(name);
350 }
351 }
352 else {
353 amf_data_free(name);
354 break;
355 }
356 }
357 else {
358 /* invalid name: error */
359 amf_data_free(data);
360 return NULL;
361 }
362 }
363 }
364 else {
365 amf_data_free(data);
366 return NULL;
367 }
368 }
369 return data;
370 }
371
372 /* read an array */
amf_array_read(amf_read_proc read_proc,void * user_data)373 static amf_data * amf_array_read(amf_read_proc read_proc, void * user_data) {
374 size_t i;
375 amf_data * element;
376 amf_data * data = amf_array_new();
377 if (data != NULL) {
378 uint32 array_size;
379 if (read_proc(&array_size, sizeof(uint32), user_data) == sizeof(uint32)) {
380 array_size = swap_uint32(array_size);
381
382 for (i = 0; i < array_size; ++i) {
383 element = amf_data_read(read_proc, user_data);
384
385 if (element != NULL) {
386 if (amf_array_push(data, element) == NULL) {
387 amf_data_free(element);
388 amf_data_free(data);
389 return NULL;
390 }
391 }
392 else {
393 amf_data_free(data);
394 return NULL;
395 }
396 }
397 }
398 else {
399 amf_data_free(data);
400 return NULL;
401 }
402 }
403 return data;
404 }
405
406 /* read a date */
amf_date_read(amf_read_proc read_proc,void * user_data)407 static amf_data * amf_date_read(amf_read_proc read_proc, void * user_data) {
408 number64_be milliseconds;
409 sint16_be timezone;
410 if (read_proc(&milliseconds, sizeof(number64_be), user_data) == sizeof(number64_be) &&
411 read_proc(&timezone, sizeof(sint16_be), user_data) == sizeof(sint16_be)) {
412 return amf_date_new(swap_number64(milliseconds), swap_sint16(timezone));
413 }
414 else {
415 return NULL;
416 }
417 }
418
419 /* load AMF data from stream */
amf_data_read(amf_read_proc read_proc,void * user_data)420 amf_data * amf_data_read(amf_read_proc read_proc, void * user_data) {
421 byte type;
422 if (read_proc(&type, sizeof(byte), user_data) == sizeof(byte)) {
423 switch (type) {
424 case AMF_TYPE_NUMBER:
425 return amf_number_read(read_proc, user_data);
426 case AMF_TYPE_BOOLEAN:
427 return amf_boolean_read(read_proc, user_data);
428 case AMF_TYPE_STRING:
429 return amf_string_read(read_proc, user_data);
430 case AMF_TYPE_OBJECT:
431 return amf_object_read(read_proc, user_data);
432 case AMF_TYPE_NULL:
433 return amf_null_new();
434 case AMF_TYPE_UNDEFINED:
435 return amf_undefined_new();
436 /*case AMF_TYPE_REFERENCE:*/
437 case AMF_TYPE_ASSOCIATIVE_ARRAY:
438 return amf_associative_array_read(read_proc, user_data);
439 case AMF_TYPE_ARRAY:
440 return amf_array_read(read_proc, user_data);
441 case AMF_TYPE_DATE:
442 return amf_date_read(read_proc, user_data);
443 /*case AMF_TYPE_SIMPLEOBJECT:*/
444 case AMF_TYPE_XML:
445 case AMF_TYPE_CLASS:
446 case AMF_TYPE_END:
447 return NULL; /* end of composite object */
448 default:
449 break;
450 }
451 }
452 return NULL;
453 }
454
455 /* determines the size of the given AMF data */
amf_data_size(amf_data * data)456 size_t amf_data_size(amf_data * data) {
457 size_t s = 0;
458 amf_node * node;
459 if (data != NULL) {
460 s += sizeof(byte);
461 switch (data->type) {
462 case AMF_TYPE_NUMBER:
463 s += sizeof(number64_be);
464 break;
465 case AMF_TYPE_BOOLEAN:
466 s += sizeof(uint8);
467 break;
468 case AMF_TYPE_STRING:
469 s += sizeof(uint16) + (size_t)amf_string_get_size(data);
470 break;
471 case AMF_TYPE_OBJECT:
472 node = amf_object_first(data);
473 while (node != NULL) {
474 s += sizeof(uint16) + (size_t)amf_string_get_size(amf_object_get_name(node));
475 s += (size_t)amf_data_size(amf_object_get_data(node));
476 node = amf_object_next(node);
477 }
478 s += sizeof(uint16) + sizeof(uint8);
479 break;
480 case AMF_TYPE_NULL:
481 case AMF_TYPE_UNDEFINED:
482 break;
483 /*case AMF_TYPE_REFERENCE:*/
484 case AMF_TYPE_ASSOCIATIVE_ARRAY:
485 s += sizeof(uint32);
486 node = amf_associative_array_first(data);
487 while (node != NULL) {
488 s += sizeof(uint16) + (size_t)amf_string_get_size(amf_associative_array_get_name(node));
489 s += (size_t)amf_data_size(amf_associative_array_get_data(node));
490 node = amf_associative_array_next(node);
491 }
492 s += sizeof(uint16) + sizeof(uint8);
493 break;
494 case AMF_TYPE_ARRAY:
495 s += sizeof(uint32);
496 node = amf_array_first(data);
497 while (node != NULL) {
498 s += (size_t)amf_data_size(amf_array_get(node));
499 node = amf_array_next(node);
500 }
501 break;
502 case AMF_TYPE_DATE:
503 s += sizeof(number64) + sizeof(sint16);
504 break;
505 /*case AMF_TYPE_SIMPLEOBJECT:*/
506 case AMF_TYPE_XML:
507 case AMF_TYPE_CLASS:
508 case AMF_TYPE_END:
509 break; /* end of composite object */
510 default:
511 break;
512 }
513 }
514 return s;
515 }
516
517 /* write a number */
amf_number_write(amf_data * data,amf_write_proc write_proc,void * user_data)518 static size_t amf_number_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
519 number64 n = swap_number64(data->number_data);
520 return write_proc(&n, sizeof(number64_be), user_data);
521 }
522
523 /* write a boolean */
amf_boolean_write(amf_data * data,amf_write_proc write_proc,void * user_data)524 static size_t amf_boolean_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
525 return write_proc(&(data->boolean_data), sizeof(uint8), user_data);
526 }
527
528 /* write a string */
amf_string_write(amf_data * data,amf_write_proc write_proc,void * user_data)529 static size_t amf_string_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
530 uint16 s;
531 size_t w = 0;
532
533 s = swap_uint16(data->string_data.size);
534 w = write_proc(&s, sizeof(uint16_be), user_data);
535 if (data->string_data.size > 0) {
536 w += write_proc(data->string_data.mbstr, (size_t)(data->string_data.size), user_data);
537 }
538
539 return w;
540 }
541
542 /* write an object */
amf_object_write(amf_data * data,amf_write_proc write_proc,void * user_data)543 static size_t amf_object_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
544 amf_node * node;
545 size_t w = 0;
546 uint16_be filler = swap_uint16(0);
547 uint8 terminator = AMF_TYPE_END;
548
549 node = amf_object_first(data);
550 while (node != NULL) {
551 w += amf_string_write(amf_object_get_name(node), write_proc, user_data);
552 w += amf_data_write(amf_object_get_data(node), write_proc, user_data);
553 node = amf_object_next(node);
554 }
555
556 /* empty string is the last element */
557 w += write_proc(&filler, sizeof(uint16_be), user_data);
558 /* an object ends with 0x09 */
559 w += write_proc(&terminator, sizeof(uint8), user_data);
560
561 return w;
562 }
563
564 /* write an associative array */
amf_associative_array_write(amf_data * data,amf_write_proc write_proc,void * user_data)565 static size_t amf_associative_array_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
566 amf_node * node;
567 size_t w = 0;
568 uint32_be s;
569 uint16_be filler = swap_uint16(0);
570 uint8 terminator = AMF_TYPE_END;
571
572 s = swap_uint32(data->list_data.size) / 2;
573 w += write_proc(&s, sizeof(uint32_be), user_data);
574 node = amf_associative_array_first(data);
575 while (node != NULL) {
576 w += amf_string_write(amf_associative_array_get_name(node), write_proc, user_data);
577 w += amf_data_write(amf_associative_array_get_data(node), write_proc, user_data);
578 node = amf_associative_array_next(node);
579 }
580
581 /* empty string is the last element */
582 w += write_proc(&filler, sizeof(uint16_be), user_data);
583 /* an object ends with 0x09 */
584 w += write_proc(&terminator, sizeof(uint8), user_data);
585
586 return w;
587 }
588
589 /* write an array */
amf_array_write(amf_data * data,amf_write_proc write_proc,void * user_data)590 static size_t amf_array_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
591 amf_node * node;
592 size_t w = 0;
593 uint32_be s;
594
595 s = swap_uint32(data->list_data.size);
596 w += write_proc(&s, sizeof(uint32_be), user_data);
597 node = amf_array_first(data);
598 while (node != NULL) {
599 w += amf_data_write(amf_array_get(node), write_proc, user_data);
600 node = amf_array_next(node);
601 }
602
603 return w;
604 }
605
606 /* write a date */
amf_date_write(amf_data * data,amf_write_proc write_proc,void * user_data)607 static size_t amf_date_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
608 size_t w = 0;
609 number64_be milli;
610 sint16_be tz;
611
612 milli = swap_number64(data->date_data.milliseconds);
613 w += write_proc(&milli, sizeof(number64_be), user_data);
614 tz = swap_sint16(data->date_data.timezone);
615 w += write_proc(&tz, sizeof(sint16_be), user_data);
616
617 return w;
618 }
619
620 /* write amf data to stream */
amf_data_write(amf_data * data,amf_write_proc write_proc,void * user_data)621 size_t amf_data_write(amf_data * data, amf_write_proc write_proc, void * user_data) {
622 size_t s = 0;
623 if (data != NULL) {
624 s += write_proc(&(data->type), sizeof(byte), user_data);
625 switch (data->type) {
626 case AMF_TYPE_NUMBER:
627 s += amf_number_write(data, write_proc, user_data);
628 break;
629 case AMF_TYPE_BOOLEAN:
630 s += amf_boolean_write(data, write_proc, user_data);
631 break;
632 case AMF_TYPE_STRING:
633 s += amf_string_write(data, write_proc, user_data);
634 break;
635 case AMF_TYPE_OBJECT:
636 s += amf_object_write(data, write_proc, user_data);
637 break;
638 case AMF_TYPE_NULL:
639 case AMF_TYPE_UNDEFINED:
640 break;
641 /*case AMF_TYPE_REFERENCE:*/
642 case AMF_TYPE_ASSOCIATIVE_ARRAY:
643 s += amf_associative_array_write(data, write_proc, user_data);
644 break;
645 case AMF_TYPE_ARRAY:
646 s += amf_array_write(data, write_proc, user_data);
647 break;
648 case AMF_TYPE_DATE:
649 s += amf_date_write(data, write_proc, user_data);
650 break;
651 /*case AMF_TYPE_SIMPLEOBJECT:*/
652 case AMF_TYPE_XML:
653 case AMF_TYPE_CLASS:
654 case AMF_TYPE_END:
655 break; /* end of composite object */
656 default:
657 break;
658 }
659 }
660 return s;
661 }
662
663 /* data type */
amf_data_get_type(amf_data * data)664 byte amf_data_get_type(amf_data * data) {
665 return (data != NULL) ? data->type : AMF_TYPE_NULL;
666 }
667
668 /* clone AMF data */
amf_data_clone(amf_data * data)669 amf_data * amf_data_clone(amf_data * data) {
670 /* we copy data recursively */
671 if (data != NULL) {
672 switch (data->type) {
673 case AMF_TYPE_NUMBER: return amf_number_new(amf_number_get_value(data));
674 case AMF_TYPE_BOOLEAN: return amf_boolean_new(amf_boolean_get_value(data));
675 case AMF_TYPE_STRING:
676 if (data->string_data.mbstr != NULL) {
677 return amf_string_new((byte *)strdup((char *)amf_string_get_bytes(data)), amf_string_get_size(data));
678 }
679 else {
680 return amf_str(NULL);
681 }
682 case AMF_TYPE_NULL: return NULL;
683 case AMF_TYPE_UNDEFINED: return NULL;
684 /*case AMF_TYPE_REFERENCE:*/
685 case AMF_TYPE_OBJECT:
686 case AMF_TYPE_ASSOCIATIVE_ARRAY:
687 case AMF_TYPE_ARRAY:
688 {
689 amf_data * d = amf_data_new(data->type);
690 if (d != NULL) {
691 amf_list_init(&d->list_data);
692 amf_list_clone(&data->list_data, &d->list_data);
693 }
694 return d;
695 }
696 case AMF_TYPE_DATE: return amf_date_new(amf_date_get_milliseconds(data), amf_date_get_timezone(data));
697 /*case AMF_TYPE_SIMPLEOBJECT:*/
698 case AMF_TYPE_XML: return NULL;
699 case AMF_TYPE_CLASS: return NULL;
700 }
701 }
702 return NULL;
703 }
704
705 /* free AMF data */
amf_data_free(amf_data * data)706 void amf_data_free(amf_data * data) {
707 if (data != NULL) {
708 switch (data->type) {
709 case AMF_TYPE_NUMBER: break;
710 case AMF_TYPE_BOOLEAN: break;
711 case AMF_TYPE_STRING:
712 if (data->string_data.mbstr != NULL) {
713 free(data->string_data.mbstr);
714 } break;
715 case AMF_TYPE_NULL: break;
716 case AMF_TYPE_UNDEFINED: break;
717 /*case AMF_TYPE_REFERENCE:*/
718 case AMF_TYPE_OBJECT:
719 case AMF_TYPE_ASSOCIATIVE_ARRAY:
720 case AMF_TYPE_ARRAY: amf_list_clear(&data->list_data); break;
721 case AMF_TYPE_DATE: break;
722 /*case AMF_TYPE_SIMPLEOBJECT:*/
723 case AMF_TYPE_XML: break;
724 case AMF_TYPE_CLASS: break;
725 default: break;
726 }
727 free(data);
728 }
729 }
730
731 /* dump AMF data into a stream as text */
amf_data_dump(FILE * stream,amf_data * data,int indent_level)732 void amf_data_dump(FILE * stream, amf_data * data, int indent_level) {
733 if (data != NULL) {
734 amf_node * node;
735 time_t time;
736 struct tm * t;
737 char datestr[128];
738 switch (data->type) {
739 case AMF_TYPE_NUMBER:
740 fprintf(stream, "%.12g", data->number_data);
741 break;
742 case AMF_TYPE_BOOLEAN:
743 fprintf(stream, "%s", (data->boolean_data) ? "true" : "false");
744 break;
745 case AMF_TYPE_STRING:
746 fprintf(stream, "\'%.*s\'", data->string_data.size, data->string_data.mbstr);
747 break;
748 case AMF_TYPE_OBJECT:
749 node = amf_object_first(data);
750 fprintf(stream, "{\n");
751 while (node != NULL) {
752 fprintf(stream, "%*s", (indent_level+1)*4, "");
753 amf_data_dump(stream, amf_object_get_name(node), indent_level+1);
754 fprintf(stream, ": ");
755 amf_data_dump(stream, amf_object_get_data(node), indent_level+1);
756 node = amf_object_next(node);
757 fprintf(stream, "\n");
758 }
759 fprintf(stream, "%*s", indent_level*4 + 1, "}");
760 break;
761 case AMF_TYPE_NULL:
762 fprintf(stream, "null");
763 break;
764 case AMF_TYPE_UNDEFINED:
765 fprintf(stream, "undefined");
766 break;
767 /*case AMF_TYPE_REFERENCE:*/
768 case AMF_TYPE_ASSOCIATIVE_ARRAY:
769 node = amf_associative_array_first(data);
770 fprintf(stream, "{\n");
771 while (node != NULL) {
772 fprintf(stream, "%*s", (indent_level+1)*4, "");
773 amf_data_dump(stream, amf_associative_array_get_name(node), indent_level+1);
774 fprintf(stream, " => ");
775 amf_data_dump(stream, amf_associative_array_get_data(node), indent_level+1);
776 node = amf_associative_array_next(node);
777 fprintf(stream, "\n");
778 }
779 fprintf(stream, "%*s", indent_level*4 + 1, "}");
780 break;
781 case AMF_TYPE_ARRAY:
782 node = amf_array_first(data);
783 fprintf(stream, "[\n");
784 while (node != NULL) {
785 fprintf(stream, "%*s", (indent_level+1)*4, "");
786 amf_data_dump(stream, node->data, indent_level+1);
787 node = amf_array_next(node);
788 fprintf(stream, "\n");
789 }
790 fprintf(stream, "%*s", indent_level*4 + 1, "]");
791 break;
792 case AMF_TYPE_DATE:
793 time = amf_date_to_time_t(data);
794 tzset();
795 t = localtime(&time);
796 strftime(datestr, sizeof(datestr), "%a, %d %b %Y %H:%M:%S %z", t);
797 fprintf(stream, "%s", datestr);
798 break;
799 /*case AMF_TYPE_SIMPLEOBJECT:*/
800 case AMF_TYPE_XML: break;
801 case AMF_TYPE_CLASS: break;
802 default: break;
803 }
804 }
805 }
806
807 /* number functions */
amf_number_new(number64 value)808 amf_data * amf_number_new(number64 value) {
809 amf_data * data = amf_data_new(AMF_TYPE_NUMBER);
810 if (data != NULL) {
811 data->number_data = value;
812 }
813 return data;
814 }
815
amf_number_get_value(amf_data * data)816 number64 amf_number_get_value(amf_data * data) {
817 return (data != NULL) ? data->number_data : 0;
818 }
819
amf_number_set_value(amf_data * data,number64 value)820 void amf_number_set_value(amf_data * data, number64 value) {
821 if (data != NULL) {
822 data->number_data = value;
823 }
824 }
825
826 /* boolean functions */
amf_boolean_new(uint8 value)827 amf_data * amf_boolean_new(uint8 value) {
828 amf_data * data = amf_data_new(AMF_TYPE_BOOLEAN);
829 if (data != NULL) {
830 data->boolean_data = value;
831 }
832 return data;
833 }
834
amf_boolean_get_value(amf_data * data)835 uint8 amf_boolean_get_value(amf_data * data) {
836 return (data != NULL) ? data->boolean_data : 0;
837 }
838
amf_boolean_set_value(amf_data * data,uint8 value)839 void amf_boolean_set_value(amf_data * data, uint8 value) {
840 if (data != NULL) {
841 data->boolean_data = value;
842 }
843 }
844
845 /* string functions */
amf_string_new(byte * str,uint16 size)846 amf_data * amf_string_new(byte * str, uint16 size) {
847 amf_data * data = amf_data_new(AMF_TYPE_STRING);
848 if (data != NULL) {
849 data->string_data.size = size;
850 data->string_data.mbstr = (byte*)calloc(size+1, sizeof(byte));
851 if (data->string_data.mbstr != NULL) {
852 if (size > 0) {
853 memcpy(data->string_data.mbstr, str, size);
854 }
855 }
856 else {
857 amf_data_free(data);
858 return NULL;
859 }
860 }
861 return data;
862 }
863
amf_str(const char * str)864 amf_data * amf_str(const char * str) {
865 return amf_string_new((byte *)str, (uint16)(str != NULL ? strlen(str) : 0));
866 }
867
amf_string_get_size(amf_data * data)868 uint16 amf_string_get_size(amf_data * data) {
869 return (data != NULL) ? data->string_data.size : 0;
870 }
871
amf_string_get_bytes(amf_data * data)872 byte * amf_string_get_bytes(amf_data * data) {
873 return (data != NULL) ? data->string_data.mbstr : NULL;
874 }
875
876 /* object functions */
amf_object_new(void)877 amf_data * amf_object_new(void) {
878 amf_data * data = amf_data_new(AMF_TYPE_OBJECT);
879 if (data != NULL) {
880 amf_list_init(&data->list_data);
881 }
882 return data;
883 }
884
amf_object_size(amf_data * data)885 uint32 amf_object_size(amf_data * data) {
886 return (data != NULL) ? data->list_data.size / 2 : 0;
887 }
888
amf_object_add(amf_data * data,const char * name,amf_data * element)889 amf_data * amf_object_add(amf_data * data, const char * name, amf_data * element) {
890 if (data != NULL) {
891 if (amf_list_push(&data->list_data, amf_str(name)) != NULL) {
892 if (amf_list_push(&data->list_data, element) != NULL) {
893 return element;
894 }
895 else {
896 amf_data_free(amf_list_pop(&data->list_data));
897 }
898 }
899 }
900 return NULL;
901 }
902
amf_object_get(amf_data * data,const char * name)903 amf_data * amf_object_get(amf_data * data, const char * name) {
904 if (data != NULL) {
905 amf_node * node = amf_list_first(&(data->list_data));
906 while (node != NULL) {
907 if (strncmp((char*)(node->data->string_data.mbstr), name, (size_t)(node->data->string_data.size)) == 0) {
908 node = node->next;
909 return (node != NULL) ? node->data : NULL;
910 }
911 /* we have to skip the element data to reach the next name */
912 node = node->next->next;
913 }
914 }
915 return NULL;
916 }
917
amf_object_set(amf_data * data,const char * name,amf_data * element)918 amf_data * amf_object_set(amf_data * data, const char * name, amf_data * element) {
919 if (data != NULL) {
920 amf_node * node = amf_list_first(&(data->list_data));
921 while (node != NULL) {
922 if (strncmp((char*)(node->data->string_data.mbstr), name, (size_t)(node->data->string_data.size)) == 0) {
923 node = node->next;
924 if (node != NULL && node->data != NULL) {
925 amf_data_free(node->data);
926 node->data = element;
927 return element;
928 }
929 }
930 /* we have to skip the element data to reach the next name */
931 node = node->next->next;
932 }
933 }
934 return NULL;
935 }
936
amf_object_delete(amf_data * data,const char * name)937 amf_data * amf_object_delete(amf_data * data, const char * name) {
938 if (data != NULL) {
939 amf_node * node = amf_list_first(&data->list_data);
940 while (node != NULL) {
941 node = node->next;
942 if (strncmp((char*)(node->data->string_data.mbstr), name, (size_t)(node->data->string_data.size)) == 0) {
943 amf_node * data_node = node->next;
944 amf_data_free(amf_list_delete(&data->list_data, node));
945 return amf_list_delete(&data->list_data, data_node);
946 }
947 else {
948 node = node->next;
949 }
950 }
951 }
952 return NULL;
953 }
954
amf_object_first(amf_data * data)955 amf_node * amf_object_first(amf_data * data) {
956 return (data != NULL) ? amf_list_first(&data->list_data) : NULL;
957 }
958
amf_object_last(amf_data * data)959 amf_node * amf_object_last(amf_data * data) {
960 if (data != NULL) {
961 amf_node * node = amf_list_last(&data->list_data);
962 if (node != NULL) {
963 return node->prev;
964 }
965 }
966 return NULL;
967 }
968
amf_object_next(amf_node * node)969 amf_node * amf_object_next(amf_node * node) {
970 if (node != NULL) {
971 amf_node * next = node->next;
972 if (next != NULL) {
973 return next->next;
974 }
975 }
976 return NULL;
977 }
978
amf_object_prev(amf_node * node)979 amf_node * amf_object_prev(amf_node * node) {
980 if (node != NULL) {
981 amf_node * prev = node->prev;
982 if (prev != NULL) {
983 return prev->prev;
984 }
985 }
986 return NULL;
987 }
988
amf_object_get_name(amf_node * node)989 amf_data * amf_object_get_name(amf_node * node) {
990 return (node != NULL) ? node->data : NULL;
991 }
992
amf_object_get_data(amf_node * node)993 amf_data * amf_object_get_data(amf_node * node) {
994 if (node != NULL) {
995 amf_node * next = node->next;
996 if (next != NULL) {
997 return next->data;
998 }
999 }
1000 return NULL;
1001 }
1002
1003 /* associative array functions */
amf_associative_array_new(void)1004 amf_data * amf_associative_array_new(void) {
1005 amf_data * data = amf_data_new(AMF_TYPE_ASSOCIATIVE_ARRAY);
1006 if (data != NULL) {
1007 amf_list_init(&data->list_data);
1008 }
1009 return data;
1010 }
1011
1012 /* array functions */
amf_array_new(void)1013 amf_data * amf_array_new(void) {
1014 amf_data * data = amf_data_new(AMF_TYPE_ARRAY);
1015 if (data != NULL) {
1016 amf_list_init(&data->list_data);
1017 }
1018 return data;
1019 }
1020
amf_array_size(amf_data * data)1021 uint32 amf_array_size(amf_data * data) {
1022 return (data != NULL) ? data->list_data.size : 0;
1023 }
1024
amf_array_push(amf_data * data,amf_data * element)1025 amf_data * amf_array_push(amf_data * data, amf_data * element) {
1026 return (data != NULL) ? amf_list_push(&data->list_data, element) : NULL;
1027 }
1028
amf_array_pop(amf_data * data)1029 amf_data * amf_array_pop(amf_data * data) {
1030 return (data != NULL) ? amf_list_pop(&data->list_data) : NULL;
1031 }
1032
amf_array_first(amf_data * data)1033 amf_node * amf_array_first(amf_data * data) {
1034 return (data != NULL) ? amf_list_first(&data->list_data) : NULL;
1035 }
1036
amf_array_last(amf_data * data)1037 amf_node * amf_array_last(amf_data * data) {
1038 return (data != NULL) ? amf_list_last(&data->list_data) : NULL;
1039 }
1040
amf_array_next(amf_node * node)1041 amf_node * amf_array_next(amf_node * node) {
1042 return (node != NULL) ? node->next : NULL;
1043 }
1044
amf_array_prev(amf_node * node)1045 amf_node * amf_array_prev(amf_node * node) {
1046 return (node != NULL) ? node->prev : NULL;
1047 }
1048
amf_array_get(amf_node * node)1049 amf_data * amf_array_get(amf_node * node) {
1050 return (node != NULL) ? node->data : NULL;
1051 }
1052
amf_array_get_at(amf_data * data,uint32 n)1053 amf_data * amf_array_get_at(amf_data * data, uint32 n) {
1054 return (data != NULL) ? amf_list_get_at(&data->list_data, n) : NULL;
1055 }
1056
amf_array_delete(amf_data * data,amf_node * node)1057 amf_data * amf_array_delete(amf_data * data, amf_node * node) {
1058 return (data != NULL) ? amf_list_delete(&data->list_data, node) : NULL;
1059 }
1060
amf_array_insert_before(amf_data * data,amf_node * node,amf_data * element)1061 amf_data * amf_array_insert_before(amf_data * data, amf_node * node, amf_data * element) {
1062 return (data != NULL) ? amf_list_insert_before(&data->list_data, node, element) : NULL;
1063 }
1064
amf_array_insert_after(amf_data * data,amf_node * node,amf_data * element)1065 amf_data * amf_array_insert_after(amf_data * data, amf_node * node, amf_data * element) {
1066 return (data != NULL) ? amf_list_insert_after(&data->list_data, node, element) : NULL;
1067 }
1068
1069 /* date functions */
amf_date_new(number64 milliseconds,sint16 timezone)1070 amf_data * amf_date_new(number64 milliseconds, sint16 timezone) {
1071 amf_data * data = amf_data_new(AMF_TYPE_DATE);
1072 if (data != NULL) {
1073 data->date_data.milliseconds = milliseconds;
1074 data->date_data.timezone = timezone;
1075 }
1076 return data;
1077 }
1078
amf_date_get_milliseconds(amf_data * data)1079 number64 amf_date_get_milliseconds(amf_data * data) {
1080 return (data != NULL) ? data->date_data.milliseconds : 0.0;
1081 }
1082
amf_date_get_timezone(amf_data * data)1083 sint16 amf_date_get_timezone(amf_data * data) {
1084 return (data != NULL) ? data->date_data.timezone : 0;
1085 }
1086
amf_date_to_time_t(amf_data * data)1087 time_t amf_date_to_time_t(amf_data * data) {
1088 return (time_t)((data != NULL) ? data->date_data.milliseconds / 1000 : 0);
1089 }
1090