Skip to content

Instantly share code, notes, and snippets.

@bowd
Created June 30, 2012 19:23
Show Gist options
  • Save bowd/3025172 to your computer and use it in GitHub Desktop.
Save bowd/3025172 to your computer and use it in GitHub Desktop.
/**
* @file session_file.h
* @Author Bogdan Dumitru (dumbogdan@gmail.com)
* @date July, 2012
* @brief Functions related to the processing of Ableton Live Session files (.als)
*
* The functions regarding processing of ALS files. This is currently devided in
* three subsections with appropriate prefixes:
*
* (1) Regarding specifically to ALS files and entities:
* These are prefixed with ALS/als and refer to specific inner structures and
* functions of the als file and subsequent ALS reinterpretation this program stores.
*
* (2) Regarding virtual memory buffer:
* These are prefixed with VMEM/vmem and are used for working with a virtual memory
* chunk that is allocated and maintained for the storage of the session that is
* analysed.
*/
#ifndef _SESSION_FILE_H_
#define _SESSION_FILE_H_
#include <libxml/encoding.h>
#include <libxml/xmlwriter.h>
#include <libxml/parser.h>
#include <libxml/tree.h>
#include <openssl/evp.h>
/* General defines */
#define ALS_CONTROL_BYTES "ALSDATAFMTTREEFL"
#define ALS_CONTROL_BYTES_LENGTH 16
#define ALS_VERSION_MAJOR 0
#define ALS_VERSION_MINOR 1
#define PATH_INITIAL_SIZE 256
#define VMEM_INITIAL_SIZE 262144
/* ALS related structures */
typedef enum {
ALS_ELEMENT = 23,
ALS_DATA
} als_node_type;
typedef struct _als_attribute {
uint16_t name_size;
uint16_t value_size;
char data[];
} als_attribute;
typedef struct _als_node als_node;
typedef struct _als_element_node {
uint16_t name_size;
uint16_t no_attrs;
uint16_t no_children;
char data[];
} als_element_node;
typedef struct _als_data_node {
uint32_t size;
char data[];
} als_data_node;
struct _als_node {
uint32_t size;
char id[16];
als_node_type type;
union {
als_element_node element;
als_data_node data;
};
};
typedef struct {
uint16_t encoding_size;
uint16_t version_size;
char data[];
} als_payload;
typedef struct {
uint32_t pula;
} als_index;
typedef struct {
char control_bytes[ALS_CONTROL_BYTES_LENGTH];
uint16_t version_major;
uint16_t version_minor;
char index_md5[16];
uint32_t index_size;
char payload_md5[16];
uint32_t payload_size;
char data[];
} als_file;
/* VMEM related structures */
typedef struct {
uint32_t alloc_size;
uint32_t used;
char *p;
} vmem;
typedef struct {
vmem *mem;
uint32_t offset;
} vmem_element;
/* Path structures */
/* VMEM macros */
/**
* Checks if there is enough space to have an entity of the given size at the
* given pointer inside the memory block defined by `mem`.
* If it's true it returns the specific pointer. If not it first alters the
* memory block and then returns the pointer.
*/
#define VMEMCHECK(ptr, size, mem) \
((ptr)+(size) < (mem)->p + (mem)->alloc_size ? \
(ptr) : vmem_extend((mem), (ptr)))
/**
* Tries to cast the location at `ptr` in `mem` as the given type.
* Uses VMEM_CHECK with sizeof(type).
*/
#define VMEMCAST(type, ptr, mem) \
((type *) (VMEM_CHECK(sizeof(type), ptr, mem)))
/**
* Performes a memcpy but with VMEM_CHECK in the middle
*/
#define VMEMCPY(p, s, size, mem) memcpy((char *) VMEM_CHECK(size, p, mem), s, size)
/* vmem_element to als element macros */
/**
* Casts a vmem_element `el` to an als of type `type`
*/
#define ALS_EL(type, el) \
((type *) (el->mem->p + el->offset))
/* Shorthand functions for the given ALS types */
#define ALS_FILE(el) ALS_EL(als_file, el)
#define ALS_PAYLOAD(el) ALS_EL(als_payload, el)
#define ALS_NODE(el) ALS_EL(als_node, el)
#define ALS_ATTR(el) ALS_EL(als_attribute, el)
#define VMEM_EL(ptr, mem, type) \
((vmem_element *) vmem_element_at(ptr, mem, sizeof(type)))
#define VMEM_FILE(ptr, mem) (VMEM_EL(ptr, mem, als_file))
#define VMEM_PAYLOAD(ptr, mem) (VMEM_EL(ptr, mem, als_payload))
#define VMEM_NODE(ptr, mem) (VMEM_EL(ptr, mem, als_node))
#define VMEM_ATTR(ptr, mem) (VMEM_EL(ptr, mem, als_attribute))
/* DEPRECATED
#define ALS_CAST(type, el) VMEM_CAST(type, (el->mem->p + el->offset), el->mem)
#define ALS_UPDATE(type, el) ((type *) (el->mem->p + el->offset))
*/
/**
* Specific ALS element accessor macros based off of vmem_element in order
* to maintain locality when and if the data buffer is reallocated and moved
*/
/*
* ===================================================================
* als_attribute getter/setter macros.
* ===================================================================
* Explicit getters
*/
#define ALS_ATTR_NAME_SIZE(el) ( ALS_ATTR(el)->name_size )
#define ALS_ATTR_VALUE_SIZE(el) ( ALS_ATTR(el)->value_size )
#define ALS_ATTR_DATA(el) ( ALS_ATTR(el)->data )
/*
* Implicit getters
*/
#define ALS_ATTR_NAME(el) ((char *) ALS_ATTR(el)->data)
#define ALS_ATTR_VALUE(el) ((char *) (ALS_ATTR(el)->data + ALS_ATTR_NAME_SIZE(el)))
#define ALS_ATTR_SIZE(el) ( sizeof(uint16_t) * 2 + \
sizeof(char) * ( ALS_ATTR_NAME_SIZE(el) + \
ALS_ATTR_VALUE_SIZE(el) ))
/*
* Explicit setters
*/
#define ALS_ATTR_SET_NAME_SIZE(el, sz) (ALS_ATTR(el)->name_size = sz)
#define ALS_ATTR_SET_VALUE_SIZE(el,sz) (ALS_ATTR(el)->value_size = sz)
/*
* Implicit setters
*/
#define ALS_NODE_SET_NAME(el, nm, len) \
do { ALS_ATTR_SET_NAME_SIZE(el, len); \
VMEMCPY(ALS_ATTR_NAME(el), nm, len, el->mem); } while(false)
#define ALS_NODE_SET_VALUE(el, vl, len) \
do { ALS_ATTR_SET_VALUE_SIZE(el, len); \
VMEMCPY(ALS_ATTR_VALUE(el), vl, len, el->mmem); } while(false)
/*
* ===================================================================
* als_node getter/setter macros
* ===================================================================
* Explicit getters
*/
#define ALS_NODE_SIZE(el) (ALS_NODE(el)->size)
#define ALS_NODE_ID(el) (ALS_NODE(el)->id )
#define ALS_NODE_TYPE(el) (ALS_NODE(el)->type)
/* als_element_node */
#define ALS_NODE_NAME_SIZE(el) (ALS_NODE(el)->element.name_size )
#define ALS_NODE_NO_ATTRS(el) (ALS_NODE(el)->element.no_attrs )
#define ALS_NODE_NO_CHILDREN(el) (ALS_NODE(el)->element.no_children)
#define ALS_NODE_EL_DATA(el) (ALS_NODE(el)->element.data )
/* als_data_node */
#define ALS_NODE_DATA_SIZE(el) (ALS_NODE(el)->data.size)
#define ALS_NODE_DATA(el) (ALS_NODE(el)->data.data)
/**
* Implicit getters
*/
#define ALS_NODE_NAME(el) ((char *) ALS_NODE_EL_DATA(el))
#define ALS_NODE_ATTR_OFFSETS_PTR(el) (ALS_NODE_EL_DATA(el) + ALS_NODE_NAME_SIZE(el))
#define ALS_NODE_ATTR_OFFSETS(el) \
((uint32_t *) ALS_NODE_ATTR_OFFSETS_PTR(el))
#define ALS_NODE_ATTR_OFFSET(el, i) \
((uint32_t) ALS_NODE_ATTR_OFFSETS(el)[i])
#define ALS_NODe_ATTR_PTR(el, i) \
(ALS_NODE_EL_DATA(el) + ALS_NODE_ATTR_OFFSET(el, i))
#define ALS_NODE_ATTR(el, i) \
(VMEM_ATTR(ALS_NODE_ATTR_PTR(el, i), el->mem))
#define ALS_NODE_CHILD_OFFSETS_PTR(el) \
(ALS_NODE_ATTR_OFFSETS_PTR(el) + sizeof(uint32_t) * ALS_NODE_NO_ATTRS(el))
#define ALS_NODE_CHILD_OFFSETS(el) \
((uint32_t *) ALS_NODE_CHILD_OFFSETS_PTR(el))
#define ALS_NODE_CHILD_OFFSET(el, i) \
((uint32_t) ALS_NODE_ATTR_OFFSETS(el)[i])
#define ALS_NODE_CHILD_PTR(el, i) \
(ALS_NODE_EL_DATA(el) + ALS_NODE_CHILD_OFFSET(el, i))
#define ALS_NODE_CHILD(el, i) \
(VMEM_NODE(ALS_NODE_CHILD_PTR(el, i), el->mem))
/*
* Explicit setters
*/
#define ALS_NODE_SET_SIZE(el, sz) (ALS_NODE(el)->size = sz)
#define ALS_NODE_SET_TYPE(el, tp) (ALS_NODE(el)->type = tp)
#define ALS_NODE_SET_NAME_SIZE(el, sz) (ALS_NODE(el)->element.name_size = sz)
#define ALS_NODE_SET_NO_ATTRS(el, na) (ALS_NODE(el)->element.no_attrs = na)
#define ALS_NODE_SET_NO_CHILDREN(el, nc) (ALS_NODE(el)->element.no_children = nc)
#define ALS_NODe_SET_DATA_SIZE(el, ds) (ALS_NODE(el)->data.size = ds)
#define ALS_NODE_SET_ID(el, id) \
(memcpy(ALS_NODE_ID(el), id, 16))
/**
* Implicit setters
*/
#define ALS_NODE_SET_NAME(el, nm, len) \
do { ALS_NODE_SET_NAME_SIZE(el, len); \
VMEMCPY(ALS_NODE_NAME(el), nm, len, el->mem); } while(false)
#define ALS_NODE_INIT_ATTR(el, i) \
do { if (i == 0) { /* FIRST ATTR */ \
uint32_t *offsets = (uint32_t *) VMEMCHECK( \
ALS_NODE_ATTR_OFFSETS_PTR(el), \
sizeof(uint32_t) * ALS_NODE_NO_ATTRS(el), el->mem); \
offsets[0] = sizeof(uint32_t) * ( ALS_NODE_NO_ATTRS(el) + \
ALS_NODE_NO_CHILDREN(el) ); \
} else { \
uint32_t *offsets = ALS_NODE_ATTR_OFFSETS(el); \
vmem_element *prev_attr = ALS_NODE_ATTR(el, (i-1)) \
offsets[i] = offsets[i-1] + ALS_ATTR_SIZE(prev_attr); \
free(prev_attr); \
}
#define ALS_NODE_INIT_CHILD(el, i) \
do { if (i == 0) { /* FIRST CHILD */ \
uint32_t *offsets = (uint32_t *) VMEMCHECK( \
ALS_NODE_CHILD_OFFSETS_PTR(el), \
sizeof(uint32_t) * ALS_NODE_NO_CHILDREN(el), \
el->mem); \
if (ALS_NODE_NO_ATTRS(el) == 0) { /* NO_ATTRIBUTES */ \
offsets[0] = sizeof(uint32_t) * ALS_NODE_NO_CHILDREN(el); \
} else { \
vmem_element *last_attr = \
ALS_NODE_ATTR(el, ALS_NODE_NO_ATTRS(el)-1); \
offsets[0] = \
ALS_NODE_ATTR_OFFSET(el, ALS_NODE_NO_ATTRS(el)-1) + \
ALS_ATTR_SIZE(last_attr); \
free(last_attr); \
} \
} else { \
uint32_t *offsets = ALS_NODE_CHILD_OFFSETS(el); \
vmem_element *prev_child = ALS_NODE_CHILD(el, (i-1)) \
offsets[i] = offsets[i-1] + ALS_NODE_SIZE(prev_child); \
free(prev_child); \
}
/**
* ========================================================================
* als_payload setter/getter macros
* ========================================================================
* Explicit getters
*/
#define ALS_PAYLOAD_ENCODING_SIZE(el) (ALS_PAYLOAD(el)->encoding_size)
#define ALS_PAYLOAD_VERSION_SIZE(el) (ALS_PAYLOAD(el)->version_size)
#define ALS_PAYLOAD_DATA(el) (ALS_PAYLOAD(el)->data)
/**
* Implicit getters
*/
#define ALS_PAYLOAD_SIZE(el) \
((uint32_t) 2*sizeof(uint16_t) + \
sizeof(char) * ( ALS_PAYLOAD_ENCODING_SIZE(el) + \
ALS_PAYLOAD_VERSION_SIZE(el) ) + \
#define ALS_PAYLOAD_ENCODING(el) ((char *) ALS_PAYLOAD_DATA(el))
#define ALS_PAYLOAD_VERSION(el) ((char *) (ALS_PAYLOAD_DATA(el) + \
ALS_PAYLOAD_ENCODING_SIZE(el)))
#define ALS_PAYLOAD_ROOT_PTR(el) \
( ALS_PAYLOAD_VERSION(el) + ALS_PAYLOAD_VERSION_SIZE(el) )
#define ALS_PAYLOAD_ROOT(el) \
(VMEM_NODE(ALS_PAYLOAD_ROOT_PTR(el), el->mem))
#define ALS_PAYLOAD_SIZE(el) \
((uint32_t) 2*sizeof(uint16_t) + \
sizeof(char) * ( ALS_PAYLOAD_ENCODING_SIZE(el) + \
ALS_PAYLOAD_VERSION_SIZE(el) ) + \
ALS_NODE(ALS_PAYLOAD_ROOT_PTR(el))->size
/**
* Explicit setters
*/
#define ALS_PAYLOAD_SET_ENCODING_SIZE(el, sz) \
(ALS_PAYLOAD(el)->encoding_size = sz)
#define ALS_PAYLOAD_SET_VERSION_SIZE(el, sz) \
(ALS_PAYLOAD(el)->version_size = sz)
/**
* Implicit setters
*/
#define ALS_PAYLOAD_SET_ENCODING(el, en, len) \
do { ALS_PAYLOAD_SET_ENCODING_SIZE(el, len); \
VMEMCPY(ALS_PAYLOAD_ENCODING(el), en, len, el->mem); } while(false)
#define ALS_PAYLOAD_SET_VERSION(el, vs, len) \
do { ALS_PAYLOAD_SET_VERSION_SIZE(el, len); \
VMEMCPY(ALS_PAYLOAD_VERSION(el), vs, len, el->mem); } while(false)
/**
* ========================================================================
* als_file getter/setter macros
* ========================================================================
* Explicit getters
*/
#define ALS_FILE_CONTROL_BYTES(el) (ALS_FILE(el)->control_bytes)
#define ALS_FILE_VERSION_MAJOR(el) (ALS_FILE(el)->version_major)
#define ALS_FILE_VERSION_MINOR(el) (ALS_FILE(el)->version_minor)
#define ALS_FILE_INDEX_MD5(el) (ALS_FILE(el)->index_md5)
#define ALS_FILE_INDEX_SIZE(el) (ALS_FILE(el)->index_size)
#define ALS_FILE_PAYLOAD_MD5(el) (ALS_FILE(el)->payload_md5)
#define ALS_FILE_PAYLOAD_SIZE(el) (ALS_FILE(el)->payload_size)
#define ALS_FILE_DATA(el) (ALS_FILE(el)->data)
/**
* Implicit getters
*/
#define ALS_FILE_PAYLOAD_PTR(el) (ALS_FILE_DATA(el))
#define ALS_FILE_INDEX_PTR(el) (ALS_FILE_DATA(el) + ALS_FILE_PAYLOAD_SIZE(el))
#define ALS_FILE_PAYLOAD(el) \
(VMEM_PAYLOAD(ALS_FILE_PAYLOAD_PTR(el), el->mem))
/**
* TODO: Decide how to handle the index.
*/
#define ALS_FILE_INDEX(el) \
(NULL)
/**
* Explicit setters
*/
#define ALS_FILE_SET_CONTROL_BYTES(el) \
(memcpy(ALS_FILE_CONTROL_BYTES(el), ALS_CONTROL_BYTES, ALS_CONTROL_BYTES_LENGTH))
#define ALS_FILE_SET_VERSION_MAJOR(el, vm) (ALS_FILE(el)->version_major = vm)
#define ALS_FILE_SET_VERSION_MINOR(el, vm) (ALS_FILE(el)->version_minor = vm)
#define ALS_FILE_SET_INDEX_SIZE(el, sz) (ALS_FILE(el)->index_size = sz)
#define ALS_FILE_SET_PAYLOAD_SIZE(el, sz) (ALS_FILE(el)->payload_size = sz)
/* ALS functions */
void als_load_xml();
//void als_write_session_to_file(als_file *als, char * storage_file);
void als_parse_node(vmem_element *node, xmlNode *xml_node,
EVP_MD_CTX *path, als_node_type type);
void als_set_header(vmem_element *file);
/* Path manipulation functions */
vmem *path_init(char *content, uint32_t size);
void path_push(vmem *path, vmem_element *node);
void path_pop(vmem *path);
void path_destroy(vmem *path);
char *path_element(vmem_element *node);
/* VMEM manipulation functions */
vmem *vmem_init(uint32_t size);
void vmem_cpy(char *dest, char *source, uint32_t size, vmem *mem);
char *vmem_extend(vmem *mem, char *p);
void vmem_attr_init_offset(vmem_element *node, int attr_index);
void vmem_child_init_offset(vmem_element *node, int child_index);
vmem_element *vmem_element_at(char *p, vmem *mem, uint32_t size);
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment