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