PageRenderTime 115ms CodeModel.GetById 44ms app.highlight 63ms RepoModel.GetById 1ms app.codeStats 1ms

/src/amf.c

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