]> git.sesse.net Git - mlt/blob - src/framework/mlt_properties.c
ff3c5cce17f1c933d5a31fc60e93fe8394f6530d
[mlt] / src / framework / mlt_properties.c
1 /**
2  * \file mlt_properties.c
3  * \brief Properties class definition
4  * \see mlt_properties_s
5  *
6  * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7  * \author Charles Yates <charles.yates@pandora.be>
8  * \author Dan Dennedy <dan@dennedy.org>
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Lesser General Public
12  * License as published by the Free Software Foundation; either
13  * version 2.1 of the License, or (at your option) any later version.
14  *
15  * This library 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 GNU
18  * Lesser General Public License for more details.
19  *
20  * You should have received a copy of the GNU Lesser General Public
21  * License along with this library; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24
25 #include "mlt_properties.h"
26 #include "mlt_property.h"
27 #include "mlt_deque.h"
28 #include "mlt_log.h"
29 #include "mlt_factory.h"
30
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <ctype.h>
35 #include <stdarg.h>
36 #include <pthread.h>
37 #include <sys/types.h>
38 #include <dirent.h>
39 #include <sys/stat.h>
40 #include <errno.h>
41 #include <locale.h>
42
43 #define PRESETS_DIR "/presets"
44
45 /** \brief private implementation of the property list */
46
47 typedef struct
48 {
49         int hash[ 199 ];
50         char **name;
51         mlt_property *value;
52         int count;
53         int size;
54         mlt_properties mirror;
55         int ref_count;
56         pthread_mutex_t mutex;
57         locale_t locale;
58 }
59 property_list;
60
61 /* Memory leak checks */
62
63 //#define _MLT_PROPERTY_CHECKS_ 2
64 #ifdef _MLT_PROPERTY_CHECKS_
65 static int properties_created = 0;
66 static int properties_destroyed = 0;
67 #endif
68
69 /** Initialize a properties object that was already allocated.
70  *
71  * This does allocate its ::property_list, and it adds a reference count.
72  * \public \memberof mlt_properties_s
73  * \param self the properties structure to initialize
74  * \param child an opaque pointer to a subclass object
75  * \return true if failed
76  */
77
78 int mlt_properties_init( mlt_properties self, void *child )
79 {
80         if ( self != NULL )
81         {
82 #ifdef _MLT_PROPERTY_CHECKS_
83                 // Increment number of properties created
84                 properties_created ++;
85 #endif
86
87                 // NULL all methods
88                 memset( self, 0, sizeof( struct mlt_properties_s ) );
89
90                 // Assign the child of the object
91                 self->child = child;
92
93                 // Allocate the local structure
94                 self->local = calloc( 1, sizeof( property_list ) );
95
96                 // Increment the ref count
97                 ( ( property_list * )self->local )->ref_count = 1;
98                 pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );;
99         }
100
101         // Check that initialisation was successful
102         return self != NULL && self->local == NULL;
103 }
104
105 /** Create a properties object.
106  *
107  * This allocates the properties structure and calls mlt_properties_init() on it.
108  * Free the properties object with mlt_properties_close().
109  * \public \memberof mlt_properties_s
110  * \return a new properties object
111  */
112
113 mlt_properties mlt_properties_new( )
114 {
115         // Construct a standalone properties object
116         mlt_properties self = calloc( 1, sizeof( struct mlt_properties_s ) );
117
118         // Initialise self
119         mlt_properties_init( self, NULL );
120
121         // Return the pointer
122         return self;
123 }
124
125 /** Set the numeric locale used for string/double conversions.
126  *
127  * \public \memberof mlt_properties_s
128  * \param self a properties list
129  * \param locale the locale name
130  * \return true if error
131  */
132
133 int mlt_properties_set_lcnumeric( mlt_properties self, const char *locale )
134 {
135         int error = 0;
136
137         if ( self && locale )
138         {
139                 property_list *list = self->local;
140
141 #if defined(__linux__) || defined(__DARWIN__)
142                 if ( list->locale )
143                         freelocale( list->locale );
144                 list->locale = newlocale( LC_NUMERIC_MASK, locale, NULL );
145 #endif
146                 error = list->locale == NULL;
147         }
148         else
149                 error = 1;
150
151         return error;
152 }
153
154 /** Get the numeric locale for this properties object.
155  *
156  * Do not free the result.
157  * \public \memberof mlt_properties_s
158  * \param self a properties list
159  * \return the locale name if this properties has a specific locale it is using, NULL otherwise
160  */
161
162 const char* mlt_properties_get_lcnumeric( mlt_properties self )
163 {
164         property_list *list = self->local;
165         const char *result = NULL;
166
167         if ( list->locale )
168         {
169 #if defined(__DARWIN__)
170                 result = querylocale( LC_NUMERIC, list->locale );
171 #elif defined(__linux__)
172                 result = list->locale->__names[ LC_NUMERIC ];
173 #else
174                 // TODO: not yet sure what to do on other platforms
175 #endif
176         }
177         return result;
178 }
179
180 static int load_properties( mlt_properties self, const char *filename )
181 {
182         // Open the file
183         FILE *file = fopen( filename, "r" );
184
185         // Load contents of file
186         if ( file != NULL )
187         {
188                 // Temp string
189                 char temp[ 1024 ];
190                 char last[ 1024 ] = "";
191
192                 // Read each string from the file
193                 while( fgets( temp, 1024, file ) )
194                 {
195                         // Chomp the new line character from the string
196                         int x = strlen( temp ) - 1;
197                         if ( temp[x] == '\n' || temp[x] == '\r' )
198                                 temp[x] = '\0';
199
200                         // Check if the line starts with a .
201                         if ( temp[ 0 ] == '.' )
202                         {
203                                 char temp2[ 1024 ];
204                                 sprintf( temp2, "%s%s", last, temp );
205                                 strcpy( temp, temp2 );
206                         }
207                         else if ( strchr( temp, '=' ) )
208                         {
209                                 strcpy( last, temp );
210                                 *( strchr( last, '=' ) ) = '\0';
211                         }
212
213                         // Parse and set the property
214                         if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
215                                 mlt_properties_parse( self, temp );
216                 }
217
218                 // Close the file
219                 fclose( file );
220         }
221         return file? 0 : errno;
222 }
223
224 /** Create a properties object by reading a .properties text file.
225  *
226  * Free the properties object with mlt_properties_close().
227  * \deprecated Please start using mlt_properties_parse_yaml().
228  * \public \memberof mlt_properties_s
229  * \param filename the absolute file name
230  * \return a new properties object
231  */
232
233 mlt_properties mlt_properties_load( const char *filename )
234 {
235         // Construct a standalone properties object
236         mlt_properties self = mlt_properties_new( );
237
238         if ( self != NULL )
239                 load_properties( self, filename );
240
241         // Return the pointer
242         return self;
243 }
244
245 /** Set properties from a preset.
246  *
247  * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}.
248  * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD"
249  * could be an encoding preset for a widescreen NTSC DVD Video.
250  * Do not specify the type and service in the preset name parameter; these are
251  * inferred automatically from the service to which you are applying the preset.
252  * Using the example above and assuming you are calling this function on the
253  * avformat consumer, the name passed to the function should simply be DVD.
254  * Note that the profile portion of the path is optional, but a profile-specific
255  * preset with the same name as a more generic one is given a higher priority.
256  * \todo Look in a user-specific location - somewhere in the home directory.
257  *
258  * \public \memberof mlt_properties_s
259  * \param self a properties list
260  * \param name the name of a preset in a well-known location or the explicit path
261  * \return true if error
262  */
263
264 int mlt_properties_preset( mlt_properties self, const char *name )
265 {
266         struct stat stat_buff;
267
268         // validate input
269         if ( !( self && name && strlen( name ) ) )
270                 return 1;
271
272         // See if name is an explicit file
273         if ( ! stat( name, &stat_buff ) )
274         {
275                 return load_properties( self, name );
276         }
277         else
278         {
279                 // Look for profile-specific preset before a generic one.
280                 char *data          = getenv( "MLT_PRESETS_PATH" );
281                 const char *type    = mlt_properties_get( self, "mlt_type" );
282                 const char *service = mlt_properties_get( self, "mlt_service" );
283                 const char *profile = mlt_environment( "MLT_PROFILE" );
284                 int error = 0;
285
286                 if ( data )
287                 {
288                         data = strdup( data );
289                 }
290                 else
291                 {
292                         data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + strlen( PRESETS_DIR ) + 1 );
293                         strcpy( data, mlt_environment( "MLT_DATA" ) );
294                         strcat( data, PRESETS_DIR );
295                 }
296                 if ( data && type && service )
297                 {
298                         char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) );
299                         sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name );
300                         if ( load_properties( self, path ) )
301                         {
302                                 sprintf( path, "%s/%s/%s/%s", data, type, service, name );
303                                 error = load_properties( self, path );
304                         }
305                         free( path );
306                 }
307                 else
308                 {
309                         error = 1;
310                 }
311                 free( data );
312                 return error;
313         }
314 }
315
316 /** Generate a hash key.
317  *
318  * \private \memberof mlt_properties_s
319  * \param name a string
320  * \return an integer
321  */
322
323 static inline int generate_hash( const char *name )
324 {
325         int hash = 0;
326         int i = 1;
327         while ( *name )
328                 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
329         return hash;
330 }
331
332 /** Copy a serializable property to a properties list that is mirroring this one.
333  *
334  * Special case - when a container (such as loader) is protecting another
335  * producer, we need to ensure that properties are passed through to the
336  * real producer.
337  * \private \memberof mlt_properties_s
338  * \param self a properties list
339  * \param name the name of the property to copy
340  */
341
342 static inline void mlt_properties_do_mirror( mlt_properties self, const char *name )
343 {
344         if ( !self ) return;
345         property_list *list = self->local;
346         if ( list->mirror != NULL )
347         {
348                 char *value = mlt_properties_get( self, name );
349                 if ( value != NULL )
350                         mlt_properties_set( list->mirror, name, value );
351         }
352 }
353
354 /** Increment the reference count.
355  *
356  * \public \memberof mlt_properties_s
357  * \param self a properties list
358  * \return the new reference count
359  */
360
361 int mlt_properties_inc_ref( mlt_properties self )
362 {
363         int result = 0;
364         if ( self != NULL )
365         {
366                 property_list *list = self->local;
367                 pthread_mutex_lock( &list->mutex );
368                 result = ++ list->ref_count;
369                 pthread_mutex_unlock( &list->mutex );
370         }
371         return result;
372 }
373
374 /** Decrement the reference count.
375  *
376  * \public \memberof mlt_properties_s
377  * \param self a properties list
378  * \return the new reference count
379  */
380
381 int mlt_properties_dec_ref( mlt_properties self )
382 {
383         int result = 0;
384         if ( self != NULL )
385         {
386                 property_list *list = self->local;
387                 pthread_mutex_lock( &list->mutex );
388                 result = -- list->ref_count;
389                 pthread_mutex_unlock( &list->mutex );
390         }
391         return result;
392 }
393
394 /** Get the reference count.
395  *
396  * \public \memberof mlt_properties_s
397  * \param self a properties list
398  * \return the current reference count
399  */
400
401 int mlt_properties_ref_count( mlt_properties self )
402 {
403         if ( self != NULL )
404         {
405                 property_list *list = self->local;
406                 return list->ref_count;
407         }
408         return 0;
409 }
410
411 /** Set a properties list to be a mirror copy of another.
412  *
413  * Note that this does not copy all existing properties. Rather, you must
414  * call this before setting the properties that you wish to copy.
415  * \public \memberof mlt_properties_s
416  * \param that the properties which will receive copies of the properties as they are set.
417  * \param self the properties to mirror
418  */
419
420 void mlt_properties_mirror( mlt_properties self, mlt_properties that )
421 {
422         if ( !self ) return;
423         property_list *list = self->local;
424         list->mirror = that;
425 }
426
427 /** Copy all serializable properties to another properties list.
428  *
429  * \public \memberof mlt_properties_s
430  * \param self The properties to copy to
431  * \param that The properties to copy from
432  * \return true if error
433  */
434
435 int mlt_properties_inherit( mlt_properties self, mlt_properties that )
436 {
437         if ( !self || !that ) return 1;
438         int count = mlt_properties_count( that );
439         int i = 0;
440         for ( i = 0; i < count; i ++ )
441         {
442                 char *value = mlt_properties_get_value( that, i );
443                 if ( value != NULL )
444                 {
445                         char *name = mlt_properties_get_name( that, i );
446                         mlt_properties_set( self, name, value );
447                 }
448         }
449         return 0;
450 }
451
452 /** Pass all serializable properties that match a prefix to another properties object
453  *
454  * \public \memberof mlt_properties_s
455  * \param self the properties to copy to
456  * \param that The properties to copy from
457  * \param prefix the property names to match (required)
458  * \return true if error
459  */
460
461 int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix )
462 {
463         if ( !self || !that ) return 1;
464         int count = mlt_properties_count( that );
465         int length = strlen( prefix );
466         int i = 0;
467         for ( i = 0; i < count; i ++ )
468         {
469                 char *name = mlt_properties_get_name( that, i );
470                 if ( !strncmp( name, prefix, length ) )
471                 {
472                         char *value = mlt_properties_get_value( that, i );
473                         if ( value != NULL )
474                                 mlt_properties_set( self, name + length, value );
475                 }
476         }
477         return 0;
478 }
479
480 /** Locate a property by name.
481  *
482  * \private \memberof mlt_properties_s
483  * \param self a properties list
484  * \param name the property to lookup by name
485  * \return the property or NULL for failure
486  */
487
488 static inline mlt_property mlt_properties_find( mlt_properties self, const char *name )
489 {
490         if ( !self || !name ) return NULL;
491         property_list *list = self->local;
492         mlt_property value = NULL;
493         int key = generate_hash( name );
494
495         mlt_properties_lock( self );
496
497         int i = list->hash[ key ] - 1;
498         if ( i >= 0 )
499         {
500                 // Check if we're hashed
501                 if ( list->count > 0 &&
502                         name[ 0 ] == list->name[ i ][ 0 ] &&
503                         !strcmp( list->name[ i ], name ) )
504                         value = list->value[ i ];
505
506                 // Locate the item
507                 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
508                         if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
509                                 value = list->value[ i ];
510         }
511         mlt_properties_unlock( self );
512
513         return value;
514 }
515
516 /** Add a new property.
517  *
518  * \private \memberof mlt_properties_s
519  * \param self a properties list
520  * \param name the name of the new property
521  * \return the new property
522  */
523
524 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
525 {
526         property_list *list = self->local;
527         int key = generate_hash( name );
528         mlt_property result;
529
530         mlt_properties_lock( self );
531
532         // Check that we have space and resize if necessary
533         if ( list->count == list->size )
534         {
535                 list->size += 50;
536                 list->name = realloc( list->name, list->size * sizeof( const char * ) );
537                 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
538         }
539
540         // Assign name/value pair
541         list->name[ list->count ] = strdup( name );
542         list->value[ list->count ] = mlt_property_init( );
543
544         // Assign to hash table
545         if ( list->hash[ key ] == 0 )
546                 list->hash[ key ] = list->count + 1;
547
548         // Return and increment count accordingly
549         result = list->value[ list->count ++ ];
550
551         mlt_properties_unlock( self );
552
553         return result;
554 }
555
556 /** Fetch a property by name and add one if not found.
557  *
558  * \private \memberof mlt_properties_s
559  * \param self a properties list
560  * \param name the property to lookup or add
561  * \return the property
562  */
563
564 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
565 {
566         // Try to find an existing property first
567         mlt_property property = mlt_properties_find( self, name );
568
569         // If it wasn't found, create one
570         if ( property == NULL )
571                 property = mlt_properties_add( self, name );
572
573         // Return the property
574         return property;
575 }
576
577 /** Copy a property to another properties list.
578  *
579  * \public \memberof mlt_properties_s
580  * \author Zach <zachary.drew@gmail.com>
581  * \param self the properties to copy to
582  * \param that the properties to copy from
583  * \param name the name of the property to copy
584  */
585
586 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
587 {
588         // Make sure the source property isn't null.
589         mlt_property that_prop = mlt_properties_find( that, name );
590         if( that_prop == NULL )
591                 return;
592
593         mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
594 }
595
596 /** Copy all properties specified in a comma-separated list to another properties list.
597  *
598  * White space is also a delimiter.
599  * \public \memberof mlt_properties_s
600  * \author Zach <zachary.drew@gmail.com>
601  * \param self the properties to copy to
602  * \param that the properties to copy from
603  * \param list a delimited list of property names
604  * \return true if error
605  */
606
607
608 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
609 {
610         if ( !self || !that || !list ) return 1;
611         char *props = strdup( list );
612         char *ptr = props;
613         const char *delim = " ,\t\n";   // Any combination of spaces, commas, tabs, and newlines
614         int count, done = 0;
615
616         while( !done )
617         {
618                 count = strcspn( ptr, delim );
619
620                 if( ptr[count] == '\0' )
621                         done = 1;
622                 else
623                         ptr[count] = '\0';      // Make it a real string
624
625                 mlt_properties_pass_property( self, that, ptr );
626
627                 ptr += count + 1;
628                 if ( !done )
629                         ptr += strspn( ptr, delim );
630         }
631
632         free( props );
633
634         return 0;
635 }
636
637
638 /** Set a property to a string.
639  *
640  * The property name "properties" is reserved to load the preset in \p value.
641  * When the value begins with '@' then it is interpreted as a very simple math
642  * expression containing only the +, -, *, and / operators.
643  * The event "property-changed" is fired after the property has been set.
644  *
645  * This makes a copy of the string value you supply.
646  * \public \memberof mlt_properties_s
647  * \param self a properties list
648  * \param name the property to set
649  * \param value the property's new value
650  * \return true if error
651  */
652
653 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
654 {
655         int error = 1;
656
657         if ( !self || !name ) return error;
658
659         // Fetch the property to work with
660         mlt_property property = mlt_properties_fetch( self, name );
661
662         // Set it if not NULL
663         if ( property == NULL )
664         {
665                 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
666         }
667         else if ( value == NULL )
668         {
669                 error = mlt_property_set_string( property, value );
670                 mlt_properties_do_mirror( self, name );
671         }
672         else if ( *value != '@' )
673         {
674                 error = mlt_property_set_string( property, value );
675                 mlt_properties_do_mirror( self, name );
676                 if ( !strcmp( name, "properties" ) )
677                         mlt_properties_preset( self, value );
678         }
679         else if ( value[ 0 ] == '@' )
680         {
681                 double total = 0;
682                 double current = 0;
683                 char id[ 255 ];
684                 char op = '+';
685
686                 value ++;
687
688                 while ( *value != '\0' )
689                 {
690                         int length = strcspn( value, "+-*/" );
691
692                         // Get the identifier
693                         strncpy( id, value, length );
694                         id[ length ] = '\0';
695                         value += length;
696
697                         // Determine the value
698                         if ( isdigit( id[ 0 ] ) )
699                                 current = atof( id );
700                         else
701                                 current = mlt_properties_get_double( self, id );
702
703                         // Apply the operation
704                         switch( op )
705                         {
706                                 case '+':
707                                         total += current;
708                                         break;
709                                 case '-':
710                                         total -= current;
711                                         break;
712                                 case '*':
713                                         total *= current;
714                                         break;
715                                 case '/':
716                                         total = total / current;
717                                         break;
718                         }
719
720                         // Get the next op
721                         op = *value != '\0' ? *value ++ : ' ';
722                 }
723
724                 error = mlt_property_set_double( property, total );
725                 mlt_properties_do_mirror( self, name );
726         }
727
728         mlt_events_fire( self, "property-changed", name, NULL );
729
730         return error;
731 }
732
733 /** Set or default a property to a string.
734  *
735  * This makes a copy of the string value you supply.
736  * \public \memberof mlt_properties_s
737  * \param self a properties list
738  * \param name the property to set
739  * \param value the string value to set or NULL to use the default
740  * \param def the default string if value is NULL
741  * \return true if error
742  */
743
744 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
745 {
746         return mlt_properties_set( self, name, value == NULL ? def : value );
747 }
748
749 /** Get a string value by name.
750  *
751  * Do not free the returned string. It's lifetime is controlled by the property
752  * and this properties object.
753  * \public \memberof mlt_properties_s
754  * \param self a properties list
755  * \param name the property to get
756  * \return the property's string value or NULL if it does not exist
757  */
758
759 char *mlt_properties_get( mlt_properties self, const char *name )
760 {
761         mlt_property value = mlt_properties_find( self, name );
762         property_list *list = self->local;
763         return value == NULL ? NULL : mlt_property_get_string_l( value, list->locale );
764 }
765
766 /** Get a property name by index.
767  *
768  * Do not free the returned string.
769  * \public \memberof mlt_properties_s
770  * \param self a properties list
771  * \param index the numeric index of the property
772  * \return the name of the property or NULL if index is out of range
773  */
774
775 char *mlt_properties_get_name( mlt_properties self, int index )
776 {
777         if ( !self ) return NULL;
778         property_list *list = self->local;
779         if ( index >= 0 && index < list->count )
780                 return list->name[ index ];
781         return NULL;
782 }
783
784 /** Get a property's string value by index.
785  *
786  * Do not free the returned string.
787  * \public \memberof mlt_properties_s
788  * \param self a properties list
789  * \param index the numeric index of the property
790  * \return the property value as a string or NULL if the index is out of range
791  */
792
793 char *mlt_properties_get_value( mlt_properties self, int index )
794 {
795         if ( !self ) return NULL;
796         property_list *list = self->local;
797         if ( index >= 0 && index < list->count )
798                 return mlt_property_get_string_l( list->value[ index ], list->locale );
799         return NULL;
800 }
801
802 /** Get a data value by index.
803  *
804  * Do not free the returned pointer if you supplied a destructor function when you
805  * set this property.
806  * \public \memberof mlt_properties_s
807  * \param self a properties list
808  * \param index the numeric index of the property
809  * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
810  */
811
812 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
813 {
814         if ( !self ) return NULL;
815         property_list *list = self->local;
816         if ( index >= 0 && index < list->count )
817                 return mlt_property_get_data( list->value[ index ], size );
818         return NULL;
819 }
820
821 /** Return the number of items in the list.
822  *
823  * \public \memberof mlt_properties_s
824  * \param self a properties list
825  * \return the number of property objects or -1 if error
826  */
827
828 int mlt_properties_count( mlt_properties self )
829 {
830         if ( !self ) return -1;
831         property_list *list = self->local;
832         return list->count;
833 }
834
835 /** Set a value by parsing a name=value string.
836  *
837  * \public \memberof mlt_properties_s
838  * \param self a properties list
839  * \param namevalue a string containing name and value delimited by '='
840  * \return true if there was an error
841  */
842
843 int mlt_properties_parse( mlt_properties self, const char *namevalue )
844 {
845         if ( !self ) return 1;
846         char *name = strdup( namevalue );
847         char *value = NULL;
848         int error = 0;
849         char *ptr = strchr( name, '=' );
850
851         if ( ptr )
852         {
853                 *( ptr ++ ) = '\0';
854
855                 if ( *ptr != '\"' )
856                 {
857                         value = strdup( ptr );
858                 }
859                 else
860                 {
861                         ptr ++;
862                         value = strdup( ptr );
863                         if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
864                                 value[ strlen( value ) - 1 ] = '\0';
865                 }
866         }
867         else
868         {
869                 value = strdup( "" );
870         }
871
872         error = mlt_properties_set( self, name, value );
873
874         free( name );
875         free( value );
876
877         return error;
878 }
879
880 /** Get an integer associated to the name.
881  *
882  * \public \memberof mlt_properties_s
883  * \param self a properties list
884  * \param name the property to get
885  * \return The integer value, 0 if not found (which may also be a legitimate value)
886  */
887
888 int mlt_properties_get_int( mlt_properties self, const char *name )
889 {
890         mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
891         double fps = mlt_profile_fps( profile );
892         property_list *list = self->local;
893         mlt_property value = mlt_properties_find( self, name );
894         return value == NULL ? 0 : mlt_property_get_int( value, fps, list->locale );
895 }
896
897 /** Set a property to an integer value.
898  *
899  * \public \memberof mlt_properties_s
900  * \param self a properties list
901  * \param name the property to set
902  * \param value the integer
903  * \return true if error
904  */
905
906 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
907 {
908         int error = 1;
909
910         if ( !self || !name ) return error;
911
912         // Fetch the property to work with
913         mlt_property property = mlt_properties_fetch( self, name );
914
915         // Set it if not NULL
916         if ( property != NULL )
917         {
918                 error = mlt_property_set_int( property, value );
919                 mlt_properties_do_mirror( self, name );
920         }
921
922         mlt_events_fire( self, "property-changed", name, NULL );
923
924         return error;
925 }
926
927 /** Get a 64-bit integer associated to the name.
928  *
929  * \public \memberof mlt_properties_s
930  * \param self a properties list
931  * \param name the property to get
932  * \return the integer value, 0 if not found (which may also be a legitimate value)
933  */
934
935 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
936 {
937         mlt_property value = mlt_properties_find( self, name );
938         return value == NULL ? 0 : mlt_property_get_int64( value );
939 }
940
941 /** Set a property to a 64-bit integer value.
942  *
943  * \public \memberof mlt_properties_s
944  * \param self a properties list
945  * \param name the property to set
946  * \param value the integer
947  * \return true if error
948  */
949
950 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
951 {
952         int error = 1;
953
954         if ( !self || !name ) return error;
955
956         // Fetch the property to work with
957         mlt_property property = mlt_properties_fetch( self, name );
958
959         // Set it if not NULL
960         if ( property != NULL )
961         {
962                 error = mlt_property_set_int64( property, value );
963                 mlt_properties_do_mirror( self, name );
964         }
965
966         mlt_events_fire( self, "property-changed", name, NULL );
967
968         return error;
969 }
970
971 /** Get a floating point value associated to the name.
972  *
973  * \public \memberof mlt_properties_s
974  * \param self a properties list
975  * \param name the property to get
976  * \return the floating point, 0 if not found (which may also be a legitimate value)
977  */
978
979 double mlt_properties_get_double( mlt_properties self, const char *name )
980 {
981         mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
982         double fps = mlt_profile_fps( profile );
983         mlt_property value = mlt_properties_find( self, name );
984         property_list *list = self->local;
985         return value == NULL ? 0 : mlt_property_get_double( value, fps, list->locale );
986 }
987
988 /** Set a property to a floating point value.
989  *
990  * \public \memberof mlt_properties_s
991  * \param self a properties list
992  * \param name the property to set
993  * \param value the floating point value
994  * \return true if error
995  */
996
997 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
998 {
999         int error = 1;
1000
1001         if ( !self || !name ) return error;
1002
1003         // Fetch the property to work with
1004         mlt_property property = mlt_properties_fetch( self, name );
1005
1006         // Set it if not NULL
1007         if ( property != NULL )
1008         {
1009                 error = mlt_property_set_double( property, value );
1010                 mlt_properties_do_mirror( self, name );
1011         }
1012
1013         mlt_events_fire( self, "property-changed", name, NULL );
1014
1015         return error;
1016 }
1017
1018 /** Get a position value associated to the name.
1019  *
1020  * \public \memberof mlt_properties_s
1021  * \param self a properties list
1022  * \param name the property to get
1023  * \return the position, 0 if not found (which may also be a legitimate value)
1024  */
1025
1026 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
1027 {
1028         mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
1029         double fps = mlt_profile_fps( profile );
1030         property_list *list = self->local;
1031         mlt_property value = mlt_properties_find( self, name );
1032         return value == NULL ? 0 : mlt_property_get_position( value, fps, list->locale );
1033 }
1034
1035 /** Set a property to a position value.
1036  *
1037  * \public \memberof mlt_properties_s
1038  * \param self a properties list
1039  * \param name the property to get
1040  * \param value the position
1041  * \return true if error
1042  */
1043
1044 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1045 {
1046         int error = 1;
1047
1048         if ( !self || !name ) return error;
1049
1050         // Fetch the property to work with
1051         mlt_property property = mlt_properties_fetch( self, name );
1052
1053         // Set it if not NULL
1054         if ( property != NULL )
1055         {
1056                 error = mlt_property_set_position( property, value );
1057                 mlt_properties_do_mirror( self, name );
1058         }
1059
1060         mlt_events_fire( self, "property-changed", name, NULL );
1061
1062         return error;
1063 }
1064
1065 /** Get a binary data value associated to the name.
1066  *
1067  * Do not free the returned pointer if you supplied a destructor function
1068  * when you set this property.
1069  * \public \memberof mlt_properties_s
1070  * \param self a properties list
1071  * \param name the property to get
1072  * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1073  */
1074
1075 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1076 {
1077         mlt_property value = mlt_properties_find( self, name );
1078         return value == NULL ? NULL : mlt_property_get_data( value, length );
1079 }
1080
1081 /** Store binary data as a property.
1082  *
1083  * \public \memberof mlt_properties_s
1084  * \param self a properties list
1085  * \param name the property to set
1086  * \param value an opaque pointer to binary data
1087  * \param length the size of the binary data in bytes (optional)
1088  * \param destroy a function to deallocate the binary data when the property is closed (optional)
1089  * \param serialise a function that can serialize the binary data as text (optional)
1090  * \return true if error
1091  */
1092
1093 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1094 {
1095         int error = 1;
1096
1097         if ( !self || !name ) return error;
1098
1099         // Fetch the property to work with
1100         mlt_property property = mlt_properties_fetch( self, name );
1101
1102         // Set it if not NULL
1103         if ( property != NULL )
1104                 error = mlt_property_set_data( property, value, length, destroy, serialise );
1105
1106         mlt_events_fire( self, "property-changed", name, NULL );
1107
1108         return error;
1109 }
1110
1111 /** Rename a property.
1112  *
1113  * \public \memberof mlt_properties_s
1114  * \param self a properties list
1115  * \param source the property to rename
1116  * \param dest the new name
1117  * \return true if the name is already in use
1118  */
1119
1120 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1121 {
1122         mlt_property value = mlt_properties_find( self, dest );
1123
1124         if ( value == NULL )
1125         {
1126                 property_list *list = self->local;
1127                 int i = 0;
1128
1129                 // Locate the item
1130                 mlt_properties_lock( self );
1131                 for ( i = 0; i < list->count; i ++ )
1132                 {
1133                         if ( !strcmp( list->name[ i ], source ) )
1134                         {
1135                                 free( list->name[ i ] );
1136                                 list->name[ i ] = strdup( dest );
1137                                 list->hash[ generate_hash( dest ) ] = i + 1;
1138                                 break;
1139                         }
1140                 }
1141                 mlt_properties_unlock( self );
1142         }
1143
1144         return value != NULL;
1145 }
1146
1147 /** Dump the properties to a file handle.
1148  *
1149  * \public \memberof mlt_properties_s
1150  * \param self a properties list
1151  * \param output a file handle
1152  */
1153
1154 void mlt_properties_dump( mlt_properties self, FILE *output )
1155 {
1156         if ( !self || !output ) return;
1157         property_list *list = self->local;
1158         int i = 0;
1159         for ( i = 0; i < list->count; i ++ )
1160                 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1161                         fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1162 }
1163
1164 /** Output the properties to a file handle.
1165  *
1166  * This version includes reference counts and does not put each property on a new line.
1167  * \public \memberof mlt_properties_s
1168  * \param self a properties pointer
1169  * \param title a string to preface the output
1170  * \param output a file handle
1171  */
1172 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1173 {
1174         if ( !self || !output ) return;
1175         if ( output == NULL ) output = stderr;
1176         fprintf( output, "%s: ", title );
1177         if ( self != NULL )
1178         {
1179                 property_list *list = self->local;
1180                 int i = 0;
1181                 fprintf( output, "[ ref=%d", list->ref_count );
1182                 for ( i = 0; i < list->count; i ++ )
1183                         if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1184                                 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1185                         else
1186                                 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1187                 fprintf( output, " ]" );
1188         }
1189         fprintf( output, "\n" );
1190 }
1191
1192 /** Save the properties to a file by name.
1193  *
1194  * This uses the dump format - one line per property.
1195  * \public \memberof mlt_properties_s
1196  * \param self a properties list
1197  * \param filename the name of a file to create or overwrite
1198  * \return true if there was an error
1199  */
1200
1201 int mlt_properties_save( mlt_properties self, const char *filename )
1202 {
1203         int error = 1;
1204         if ( !self || !filename ) return error;
1205         FILE *f = fopen( filename, "w" );
1206         if ( f != NULL )
1207         {
1208                 mlt_properties_dump( self, f );
1209                 fclose( f );
1210                 error = 0;
1211         }
1212         return error;
1213 }
1214
1215 /* This is a very basic cross platform fnmatch replacement - it will fail in
1216  * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1217  */
1218
1219 /** Test whether a filename or pathname matches a shell-style pattern.
1220  *
1221  * \private \memberof mlt_properties_s
1222  * \param wild a string containing a wildcard pattern
1223  * \param file the name of a file to test against
1224  * \return true if the file name matches the wildcard pattern
1225  */
1226
1227 static int mlt_fnmatch( const char *wild, const char *file )
1228 {
1229         int f = 0;
1230         int w = 0;
1231
1232         while( f < strlen( file ) && w < strlen( wild ) )
1233         {
1234                 if ( wild[ w ] == '*' )
1235                 {
1236                         w ++;
1237                         if ( w == strlen( wild ) )
1238                                 f = strlen( file );
1239                         while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1240                                 f ++;
1241                 }
1242                 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1243                 {
1244                         f ++;
1245                         w ++;
1246                 }
1247                 else if ( wild[ 0 ] == '*' )
1248                 {
1249                         w = 0;
1250                 }
1251                 else
1252                 {
1253                         return 0;
1254                 }
1255         }
1256
1257         return strlen( file ) == f &&  strlen( wild ) == w;
1258 }
1259
1260 /** Compare the string or serialized value of two properties.
1261  *
1262  * \private \memberof mlt_properties_s
1263  * \param self a property
1264  * \param that a property
1265  * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1266  */
1267
1268 static int mlt_compare( const void *self, const void *that )
1269 {
1270     return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1271 }
1272
1273 /** Get the contents of a directory.
1274  *
1275  * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1276  * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1277  * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1278  * \public \memberof mlt_properties_s
1279  * \param self a properties list
1280  * \param dirname the name of the directory
1281  * \param pattern a wildcard pattern to filter the directory listing
1282  * \param sort Do you want to sort the directory listing?
1283  * \return the number of items in the directory listing
1284  */
1285
1286 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1287 {
1288         DIR *dir = opendir( dirname );
1289
1290         if ( dir )
1291         {
1292                 char key[ 20 ];
1293                 struct dirent *de = readdir( dir );
1294                 char fullname[ 1024 ];
1295                 while( de != NULL )
1296                 {
1297                         sprintf( key, "%d", mlt_properties_count( self ) );
1298                         snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1299                         if ( pattern == NULL )
1300                                 mlt_properties_set( self, key, fullname );
1301                         else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1302                                 mlt_properties_set( self, key, fullname );
1303                         de = readdir( dir );
1304                 }
1305
1306                 closedir( dir );
1307         }
1308
1309         if ( sort && mlt_properties_count( self ) )
1310         {
1311                 property_list *list = self->local;
1312                 mlt_properties_lock( self );
1313                 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1314                 mlt_properties_unlock( self );
1315         }
1316
1317         return mlt_properties_count( self );
1318 }
1319
1320 /** Close a properties object.
1321  *
1322  * Deallocates the properties object and everything it contains.
1323  * \public \memberof mlt_properties_s
1324  * \param self a properties object
1325  */
1326
1327 void mlt_properties_close( mlt_properties self )
1328 {
1329         if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1330         {
1331                 if ( self->close != NULL )
1332                 {
1333                         self->close( self->close_object );
1334                 }
1335                 else
1336                 {
1337                         property_list *list = self->local;
1338                         int index = 0;
1339
1340 #if _MLT_PROPERTY_CHECKS_ == 1
1341                         // Show debug info
1342                         mlt_properties_debug( self, "Closing", stderr );
1343 #endif
1344
1345 #ifdef _MLT_PROPERTY_CHECKS_
1346                         // Increment destroyed count
1347                         properties_destroyed ++;
1348
1349                         // Show current stats - these should match when the app is closed
1350                         mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1351 #endif
1352
1353                         // Clean up names and values
1354                         for ( index = list->count - 1; index >= 0; index -- )
1355                         {
1356                                 mlt_property_close( list->value[ index ] );
1357                                 free( list->name[ index ] );
1358                         }
1359
1360 #if defined(__linux__) || defined(__DARWIN__)
1361                         // Cleanup locale
1362                         if ( list->locale )
1363                                 freelocale( list->locale );
1364 #endif
1365
1366                         // Clear up the list
1367                         pthread_mutex_destroy( &list->mutex );
1368                         free( list->name );
1369                         free( list->value );
1370                         free( list );
1371
1372                         // Free self now if self has no child
1373                         if ( self->child == NULL )
1374                                 free( self );
1375                 }
1376         }
1377 }
1378
1379 /** Determine if the properties list is really just a sequence or ordered list.
1380  *
1381  * \public \memberof mlt_properties_s
1382  * \param properties a properties list
1383  * \return true if all of the property names are numeric (a sequence)
1384  */
1385
1386 int mlt_properties_is_sequence( mlt_properties properties )
1387 {
1388         int i;
1389         int n = mlt_properties_count( properties );
1390         for ( i = 0; i < n; i++ )
1391                 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1392                         return 0;
1393         return 1;
1394 }
1395
1396 /** \brief YAML Tiny Parser context structure
1397  *
1398  * YAML is a nifty text format popular in the Ruby world as a cleaner,
1399  * less verbose alternative to XML. See this Wikipedia topic for an overview:
1400  * http://en.wikipedia.org/wiki/YAML
1401  * The YAML specification is at:
1402  * http://yaml.org/
1403  * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1404  * using here (for the same reasons):
1405  * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1406  * \private
1407  */
1408
1409 struct yaml_parser_context
1410 {
1411         mlt_deque stack;
1412         unsigned int level;
1413         int index;
1414         mlt_deque index_stack;
1415         char block;
1416         char *block_name;
1417         unsigned int block_indent;
1418
1419 };
1420 typedef struct yaml_parser_context *yaml_parser;
1421
1422 /** Remove spaces from the left side of a string.
1423  *
1424  * \param s the string to trim
1425  * \return the number of characters removed
1426  */
1427
1428 static unsigned int ltrim( char **s )
1429 {
1430         unsigned int i = 0;
1431         char *c = *s;
1432         int n = strlen( c );
1433         for ( i = 0; i < n && *c == ' '; i++, c++ );
1434         *s = c;
1435         return i;
1436 }
1437
1438 /** Remove spaces from the right side of a string.
1439  *
1440  * \param s the string to trim
1441  * \return the number of characters removed
1442  */
1443
1444 static unsigned int rtrim( char *s )
1445 {
1446         int n = strlen( s );
1447         int i;
1448         for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1449                 s[i - 1] = 0;
1450         return n - i;
1451 }
1452
1453 /** Parse a line of YAML Tiny.
1454  *
1455  * Adds a property if needed.
1456  * \private \memberof yaml_parser_context
1457  * \param context a YAML Tiny Parser context
1458  * \param namevalue a line of YAML Tiny
1459  * \return true if there was an error
1460  */
1461
1462 static int parse_yaml( yaml_parser context, const char *namevalue )
1463 {
1464         char *name_ = strdup( namevalue );
1465         char *name = name_;
1466         char *value = NULL;
1467         int error = 0;
1468         char *ptr = strchr( name, ':' );
1469         unsigned int indent = ltrim( &name );
1470         mlt_properties properties = mlt_deque_peek_back( context->stack );
1471
1472         // Ascending one more levels in the tree
1473         if ( indent < context->level )
1474         {
1475                 unsigned int i;
1476                 unsigned int n = ( context->level - indent ) / 2;
1477                 for ( i = 0; i < n; i++ )
1478                 {
1479                         mlt_deque_pop_back( context->stack );
1480                         context->index = mlt_deque_pop_back_int( context->index_stack );
1481                 }
1482                 properties = mlt_deque_peek_back( context->stack );
1483                 context->level = indent;
1484         }
1485
1486         // Descending a level in the tree
1487         else if ( indent > context->level && context->block == 0 )
1488         {
1489                 context->level = indent;
1490         }
1491
1492         // If there is a colon that is not part of a block
1493         if ( ptr && ( indent == context->level ) )
1494         {
1495                 // Reset block processing
1496                 if ( context->block_name )
1497                 {
1498                         free( context->block_name );
1499                         context->block_name = NULL;
1500                         context->block = 0;
1501                 }
1502
1503                 // Terminate the name and setup the value pointer
1504                 *( ptr ++ ) = 0;
1505
1506                 // Trim comment
1507                 char *comment = strchr( ptr, '#' );
1508                 if ( comment )
1509                 {
1510                         *comment = 0;
1511                 }
1512
1513                 // Trim leading and trailing spaces from bare value
1514                 ltrim( &ptr );
1515                 rtrim( ptr );
1516
1517                 // No value means a child
1518                 if ( strcmp( ptr, "" ) == 0 )
1519                 {
1520                         mlt_properties child = mlt_properties_new();
1521                         mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1522                         mlt_properties_set_data( properties, name, child, 0,
1523                                 ( mlt_destructor )mlt_properties_close, NULL );
1524                         mlt_deque_push_back( context->stack, child );
1525                         mlt_deque_push_back_int( context->index_stack, context->index );
1526                         context->index = 0;
1527                         free( name_ );
1528                         return error;
1529                 }
1530
1531                 // A dash indicates a sequence item
1532                 if ( name[0] == '-' )
1533                 {
1534                         mlt_properties child = mlt_properties_new();
1535                         char key[20];
1536
1537                         mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1538                         snprintf( key, sizeof(key), "%d", context->index++ );
1539                         mlt_properties_set_data( properties, key, child, 0,
1540                                 ( mlt_destructor )mlt_properties_close, NULL );
1541                         mlt_deque_push_back( context->stack, child );
1542                         mlt_deque_push_back_int( context->index_stack, context->index );
1543
1544                         name ++;
1545                         context->level += ltrim( &name ) + 1;
1546                         properties = child;
1547                 }
1548
1549                 // Value is quoted
1550                 if ( *ptr == '\"' )
1551                 {
1552                         ptr ++;
1553                         value = strdup( ptr );
1554                         if ( value && value[ strlen( value ) - 1 ] == '\"' )
1555                                 value[ strlen( value ) - 1 ] = 0;
1556                 }
1557
1558                 // Value is folded or unfolded block
1559                 else if ( *ptr == '|' || *ptr == '>' )
1560                 {
1561                         context->block = *ptr;
1562                         context->block_name = strdup( name );
1563                         context->block_indent = 0;
1564                         value = strdup( "" );
1565                 }
1566
1567                 // Bare value
1568                 else
1569                 {
1570                         value = strdup( ptr );
1571                 }
1572         }
1573
1574         // A list of scalars
1575         else if ( name[0] == '-' )
1576         {
1577                 // Reset block processing
1578                 if ( context->block_name )
1579                 {
1580                         free( context->block_name );
1581                         context->block_name = NULL;
1582                         context->block = 0;
1583                 }
1584
1585                 char key[20];
1586
1587                 snprintf( key, sizeof(key), "%d", context->index++ );
1588                 ptr = name + 1;
1589
1590                 // Trim comment
1591                 char *comment = strchr( ptr, '#' );
1592                 if ( comment )
1593                         *comment = 0;
1594
1595                 // Trim leading and trailing spaces from bare value
1596                 ltrim( &ptr );
1597                 rtrim( ptr );
1598
1599                 // Value is quoted
1600                 if ( *ptr == '\"' )
1601                 {
1602                         ptr ++;
1603                         value = strdup( ptr );
1604                         if ( value && value[ strlen( value ) - 1 ] == '\"' )
1605                                 value[ strlen( value ) - 1 ] = 0;
1606                 }
1607
1608                 // Value is folded or unfolded block
1609                 else if ( *ptr == '|' || *ptr == '>' )
1610                 {
1611                         context->block = *ptr;
1612                         context->block_name = strdup( key );
1613                         context->block_indent = 0;
1614                         value = strdup( "" );
1615                 }
1616
1617                 // Bare value
1618                 else
1619                 {
1620                         value = strdup( ptr );
1621                 }
1622
1623                 free( name_ );
1624                 name = name_ = strdup( key );
1625         }
1626
1627         // Non-folded block
1628         else if ( context->block == '|' )
1629         {
1630                 if ( context->block_indent == 0 )
1631                         context->block_indent = indent;
1632                 if ( indent > context->block_indent )
1633                         name = &name_[ context->block_indent ];
1634                 rtrim( name );
1635                 char *old_value = mlt_properties_get( properties, context->block_name );
1636                 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1637                 strcpy( value, old_value );
1638                 if ( strcmp( old_value, "" ) )
1639                         strcat( value, "\n" );
1640                 strcat( value, name );
1641                 name = context->block_name;
1642         }
1643
1644         // Folded block
1645         else if ( context->block == '>' )
1646         {
1647                 ltrim( &name );
1648                 rtrim( name );
1649                 char *old_value = mlt_properties_get( properties, context->block_name );
1650
1651                 // Blank line (prepended with spaces) is new line
1652                 if ( strcmp( name, "" ) == 0 )
1653                 {
1654                         value = calloc( 1, strlen( old_value ) + 2 );
1655                         strcat( value, old_value );
1656                         strcat( value, "\n" );
1657                 }
1658                 // Concatenate with space
1659                 else
1660                 {
1661                         value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1662                         strcat( value, old_value );
1663                         if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1664                                 strcat( value, " " );
1665                         strcat( value, name );
1666                 }
1667                 name = context->block_name;
1668         }
1669
1670         else
1671         {
1672                 value = strdup( "" );
1673         }
1674
1675         error = mlt_properties_set( properties, name, value );
1676
1677         if ( !strcmp( name, "LC_NUMERIC" ) )
1678                 mlt_properties_set_lcnumeric( properties, value );
1679
1680         free( name_ );
1681         free( value );
1682
1683         return error;
1684 }
1685
1686 /** Parse a YAML Tiny file by name.
1687  *
1688  * \public \memberof mlt_properties_s
1689  * \param filename the name of a text file containing YAML Tiny
1690  * \return a new properties list
1691  */
1692
1693 mlt_properties mlt_properties_parse_yaml( const char *filename )
1694 {
1695         // Construct a standalone properties object
1696         mlt_properties self = mlt_properties_new( );
1697
1698         if ( self )
1699         {
1700                 // Open the file
1701                 FILE *file = fopen( filename, "r" );
1702
1703                 // Load contents of file
1704                 if ( file )
1705                 {
1706                         // Temp string
1707                         char temp[ 1024 ];
1708                         char *ptemp = &temp[ 0 ];
1709
1710                         // Default to LC_NUMERIC = C
1711                         mlt_properties_set_lcnumeric( self, "C" );
1712
1713                         // Parser context
1714                         yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1715                         context->stack = mlt_deque_init();
1716                         context->index_stack = mlt_deque_init();
1717                         mlt_deque_push_back( context->stack, self );
1718                         mlt_deque_push_back_int( context->index_stack, 0 );
1719
1720                         // Read each string from the file
1721                         while( fgets( temp, 1024, file ) )
1722                         {
1723                                 // Check for end-of-stream
1724                                 if ( strncmp( ptemp, "...", 3 ) == 0 )
1725                                         break;
1726
1727                                 // Chomp the string
1728                                 temp[ strlen( temp ) - 1 ] = '\0';
1729
1730                                 // Skip blank lines, comment lines, and document separator
1731                                 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1732                                      && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1733                                         parse_yaml( context, temp );
1734                         }
1735
1736                         // Close the file
1737                         fclose( file );
1738                         mlt_deque_close( context->stack );
1739                         mlt_deque_close( context->index_stack );
1740                         if ( context->block_name )
1741                                 free( context->block_name );
1742                         free( context );
1743                 }
1744         }
1745
1746         // Return the pointer
1747         return self;
1748 }
1749
1750 /*
1751  * YAML Tiny Serializer
1752  */
1753
1754 /** How many bytes to grow at a time */
1755 #define STRBUF_GROWTH (1024)
1756
1757 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1758  * \private
1759  */
1760
1761 struct strbuf_s
1762 {
1763         size_t size;
1764         char *string;
1765 };
1766
1767 typedef struct strbuf_s *strbuf;
1768
1769 /** Create a new string buffer
1770  *
1771  * \private \memberof strbuf_s
1772  * \return a new string buffer
1773  */
1774
1775 static strbuf strbuf_new( )
1776 {
1777         strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1778         buffer->size = STRBUF_GROWTH;
1779         buffer->string = calloc( 1, buffer->size );
1780         return buffer;
1781 }
1782
1783 /** Destroy a string buffer
1784  *
1785  * \private \memberof strbuf_s
1786  * \param buffer the string buffer to close
1787  */
1788
1789 static void strbuf_close( strbuf buffer )
1790 {
1791         // We do not free buffer->string; strbuf user must save that pointer
1792         // and free it.
1793         if ( buffer )
1794                 free( buffer );
1795 }
1796
1797 /** Format a string into a string buffer
1798  *
1799  * A variable number of arguments follows the format string - one for each
1800  * format specifier.
1801  * \private \memberof strbuf_s
1802  * \param buffer the string buffer to write into
1803  * \param format a string that contains text and formatting instructions
1804  * \return the formatted string
1805  */
1806
1807 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1808 {
1809         while ( buffer->string )
1810         {
1811                 va_list ap;
1812                 va_start( ap, format );
1813                 size_t len = strlen( buffer->string );
1814                 size_t remain = buffer->size - len - 1;
1815                 int need = vsnprintf( buffer->string + len, remain, format, ap );
1816                 va_end( ap );
1817                 if ( need > -1 && need < remain )
1818                         break;
1819                 buffer->string[ len ] = 0;
1820                 buffer->size += need + STRBUF_GROWTH;
1821                 buffer->string = realloc( buffer->string, buffer->size );
1822         }
1823         return buffer->string;
1824 }
1825
1826 /** Indent a line of YAML Tiny.
1827  *
1828  * \private \memberof strbuf_s
1829  * \param output a string buffer
1830  * \param indent the number of spaces to indent
1831  */
1832
1833 static inline void indent_yaml( strbuf output, int indent )
1834 {
1835         int j;
1836         for ( j = 0; j < indent; j++ )
1837                 strbuf_printf( output, " " );
1838 }
1839
1840 static void strbuf_escape( strbuf output, const char *value, char c )
1841 {
1842         char *v = strdup( value );
1843         char *s = v;
1844         char *found = strchr( s, c );
1845
1846         while ( found )
1847         {
1848                 *found = '\0';
1849                 strbuf_printf( output, "%s\\%c", s, c );
1850                 s = found + 1;
1851                 found = strchr( s, c );
1852         }
1853         strbuf_printf( output, "%s", s );
1854         free( v );
1855 }
1856
1857 /** Convert a line string into a YAML block literal.
1858  *
1859  * \private \memberof strbuf_s
1860  * \param output a string buffer
1861  * \param value the string to format as a block literal
1862  * \param indent the number of spaces to indent
1863  */
1864
1865 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1866 {
1867         char *v = strdup( value );
1868         char *sol = v;
1869         char *eol = strchr( sol, '\n' );
1870
1871         while ( eol )
1872         {
1873                 indent_yaml( output, indent );
1874                 *eol = '\0';
1875                 strbuf_printf( output, "%s\n", sol );
1876                 sol = eol + 1;
1877                 eol = strchr( sol, '\n' );
1878         }
1879         indent_yaml( output, indent );
1880         strbuf_printf( output, "%s\n", sol );
1881         free( v );
1882 }
1883
1884 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1885  *
1886  * \private \memberof mlt_properties_s
1887  * \param self a properties list
1888  * \param output a string buffer to hold the serialized YAML Tiny
1889  * \param indent the number of spaces to indent (for recursion, initialize to 0)
1890  * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1891  */
1892
1893 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1894 {
1895         property_list *list = self->local;
1896         int i = 0;
1897
1898         for ( i = 0; i < list->count; i ++ )
1899         {
1900                 // This implementation assumes that all data elements are property lists.
1901                 // Unfortunately, we do not have run time type identification.
1902                 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1903
1904                 if ( mlt_properties_is_sequence( self ) )
1905                 {
1906                         // Ignore hidden/non-serialisable items
1907                         if ( list->name[ i ][ 0 ] != '_' )
1908                         {
1909                                 // Indicate a sequence item
1910                                 indent_yaml( output, indent );
1911                                 strbuf_printf( output, "- " );
1912
1913                                 // If the value can be represented as a string
1914                                 const char *value = mlt_properties_get( self, list->name[ i ] );
1915                                 if ( value && strcmp( value, "" ) )
1916                                 {
1917                                         // Determine if this is an unfolded block literal
1918                                         if ( strchr( value, '\n' ) )
1919                                         {
1920                                                 strbuf_printf( output, "|\n" );
1921                                                 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1922                                         }
1923                                         else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1924                                         {
1925                                                 strbuf_printf( output, "\"" );
1926                                                 strbuf_escape( output, value, '"' );
1927                                                 strbuf_printf( output, "\"\n", value );
1928                                         }
1929                                         else
1930                                         {
1931                                                 strbuf_printf( output, "%s\n", value );
1932                                         }
1933                                 }
1934                         }
1935                         // Recurse on child
1936                         if ( child )
1937                                 serialise_yaml( child, output, indent + 2, 1 );
1938                 }
1939                 else
1940                 {
1941                         // Assume this is a normal map-oriented properties list
1942                         const char *value = mlt_properties_get( self, list->name[ i ] );
1943
1944                         // Ignore hidden/non-serialisable items
1945                         // If the value can be represented as a string
1946                         if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1947                         {
1948                                 if ( is_parent_sequence == 0 )
1949                                         indent_yaml( output, indent );
1950                                 else
1951                                         is_parent_sequence = 0;
1952
1953                                 // Determine if this is an unfolded block literal
1954                                 if ( strchr( value, '\n' ) )
1955                                 {
1956                                         strbuf_printf( output, "%s: |\n", list->name[ i ] );
1957                                         output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1958                                 }
1959                                 else if ( strchr( value, ':' ) || strchr( value, '[' ) )
1960                                 {
1961                                         strbuf_printf( output, "%s: \"", list->name[ i ] );
1962                                         strbuf_escape( output, value, '"' );
1963                                         strbuf_printf( output, "\"\n" );
1964                                 }
1965                                 else
1966                                 {
1967                                         strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
1968                                 }
1969                         }
1970
1971                         // Output a child as a map item
1972                         if ( child )
1973                         {
1974                                 indent_yaml( output, indent );
1975                                 strbuf_printf( output, "%s:\n", list->name[ i ] );
1976
1977                                 // Recurse on child
1978                                 serialise_yaml( child, output, indent + 2, 0 );
1979                         }
1980                 }
1981         }
1982 }
1983
1984 /** Serialize a properties list as a string of YAML Tiny.
1985  *
1986  * The caller MUST free the returned string!
1987  * This operates on properties containing properties as a hierarchical data
1988  * structure.
1989  * \public \memberof mlt_properties_s
1990  * \param self a properties list
1991  * \return a string containing YAML Tiny that represents the properties list
1992  */
1993
1994 char *mlt_properties_serialise_yaml( mlt_properties self )
1995 {
1996         if ( !self ) return NULL;
1997         const char *lc_numeric = mlt_properties_get_lcnumeric( self );
1998         strbuf b = strbuf_new();
1999         strbuf_printf( b, "---\n" );
2000         mlt_properties_set_lcnumeric( self, "C" );
2001         serialise_yaml( self, b, 0, 0 );
2002         mlt_properties_set_lcnumeric( self, lc_numeric );
2003         strbuf_printf( b, "...\n" );
2004         char *ret = b->string;
2005         strbuf_close( b );
2006         return ret;
2007 }
2008
2009 /** Protect a properties list against concurrent access.
2010  *
2011  * \public \memberof mlt_properties_s
2012  * \param self a properties list
2013  */
2014
2015 void mlt_properties_lock( mlt_properties self )
2016 {
2017         if ( self )
2018                 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
2019 }
2020
2021 /** End protecting a properties list against concurrent access.
2022  *
2023  * \public \memberof mlt_properties_s
2024  * \param self a properties list
2025  */
2026
2027 void mlt_properties_unlock( mlt_properties self )
2028 {
2029         if ( self )
2030                 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );
2031 }
2032
2033 /** Get a time string associated to the name.
2034  *
2035  * Do not free the returned string. It's lifetime is controlled by the property.
2036  * \public \memberof mlt_properties_s
2037  * \param self a properties list
2038  * \param name the property to get
2039  * \param format the time format that you want
2040  * \return the property's time value or NULL if \p name does not exist or there is no profile
2041  */
2042
2043 char *mlt_properties_get_time( mlt_properties self, const char* name, mlt_time_format format )
2044 {
2045         mlt_profile profile = mlt_properties_get_data( self, "_profile", NULL );
2046         if ( profile )
2047         {
2048                 double fps = mlt_profile_fps( profile );
2049                 mlt_property value = mlt_properties_find( self, name );
2050                 property_list *list = self->local;
2051                 return value == NULL ? NULL : mlt_property_get_time( value, format, fps, list->locale );
2052         }
2053         return NULL;
2054 }