2 * \file mlt_properties.c
3 * \brief Properties class definition
4 * \see mlt_properties_s
6 * Copyright (C) 2003-2009 Ushodaya Enterprises Limited
7 * \author Charles Yates <charles.yates@pandora.be>
8 * \author Dan Dennedy <dan@dennedy.org>
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.
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.
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
25 #include "mlt_properties.h"
26 #include "mlt_property.h"
27 #include "mlt_deque.h"
29 #include "mlt_factory.h"
37 #include <sys/types.h>
43 /** \brief private implementation of the property list */
52 mlt_properties mirror;
54 pthread_mutex_t mutex;
59 /* Memory leak checks */
61 //#define _MLT_PROPERTY_CHECKS_ 2
62 #ifdef _MLT_PROPERTY_CHECKS_
63 static int properties_created = 0;
64 static int properties_destroyed = 0;
67 /** Initialize a properties object that was already allocated.
69 * This does allocate its ::property_list, and it adds a reference count.
70 * \public \memberof mlt_properties_s
71 * \param self the properties structure to initialize
72 * \param child an opaque pointer to a subclass object
73 * \return true if failed
76 int mlt_properties_init( mlt_properties self, void *child )
80 #ifdef _MLT_PROPERTY_CHECKS_
81 // Increment number of properties created
82 properties_created ++;
86 memset( self, 0, sizeof( struct mlt_properties_s ) );
88 // Assign the child of the object
91 // Allocate the local structure
92 self->local = calloc( sizeof( property_list ), 1 );
94 // Increment the ref count
95 ( ( property_list * )self->local )->ref_count = 1;
96 pthread_mutex_init( &( ( property_list * )self->local )->mutex, NULL );;
99 // Check that initialisation was successful
100 return self != NULL && self->local == NULL;
103 /** Create a properties object.
105 * This allocates the properties structure and calls mlt_properties_init() on it.
106 * Free the properties object with mlt_properties_close().
107 * \public \memberof mlt_properties_s
108 * \return a new properties object
111 mlt_properties mlt_properties_new( )
113 // Construct a standalone properties object
114 mlt_properties self = calloc( sizeof( struct mlt_properties_s ), 1 );
117 mlt_properties_init( self, NULL );
119 // Return the pointer
123 /** Set the numeric locale used for string/double conversions.
125 * \public \memberof mlt_properties_s
126 * \param self a properties list
127 * \param locale the locale name
128 * \return true if error
131 int mlt_properties_set_lcnumeric( mlt_properties self, const char *locale )
135 if ( self && locale )
137 property_list *list = self->local;
140 freelocale( list->locale );
141 list->locale = newlocale( LC_NUMERIC, locale, NULL );
142 error = list->locale == NULL;
150 /** Get the numeric locale for this properties object.
152 * \public \memberof mlt_properties_s
153 * \param self a properties list
154 * \return the locale name if this properties has a specific locale it is using, NULL otherwise
157 const char* mlt_properties_get_lcnumeric( mlt_properties self )
159 property_list *list = self->local;
160 const char *result = NULL;
164 #if defined(__DARWIN__)
165 result = querylocale( LC_NUMERIC, list->locale );
166 #elif defined(__linux__)
167 result = list->locale->__names[ LC_NUMERIC ];
169 // TODO: not yet sure what to do on other platforms
175 static int load_properties( mlt_properties self, const char *filename )
178 FILE *file = fopen( filename, "r" );
180 // Load contents of file
185 char last[ 1024 ] = "";
187 // Read each string from the file
188 while( fgets( temp, 1024, file ) )
191 temp[ strlen( temp ) - 1 ] = '\0';
193 // Check if the line starts with a .
194 if ( temp[ 0 ] == '.' )
197 sprintf( temp2, "%s%s", last, temp );
198 strcpy( temp, temp2 );
200 else if ( strchr( temp, '=' ) )
202 strcpy( last, temp );
203 *( strchr( last, '=' ) ) = '\0';
206 // Parse and set the property
207 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
208 mlt_properties_parse( self, temp );
214 return file? 0 : errno;
217 /** Create a properties object by reading a .properties text file.
219 * Free the properties object with mlt_properties_close().
220 * \deprecated Please start using mlt_properties_parse_yaml().
221 * \public \memberof mlt_properties_s
222 * \param filename the absolute file name
223 * \return a new properties object
226 mlt_properties mlt_properties_load( const char *filename )
228 // Construct a standalone properties object
229 mlt_properties self = mlt_properties_new( );
232 load_properties( self, filename );
234 // Return the pointer
238 /** Set properties from a preset.
240 * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}.
241 * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD"
242 * could be an encoding preset for a widescreen NTSC DVD Video.
243 * Do not specify the type and service in the preset name parameter; these are
244 * inferred automatically from the service to which you are applying the preset.
245 * Using the example above and assuming you are calling this function on the
246 * avformat consumer, the name passed to the function should simply be DVD.
247 * Note that the profile portion of the path is optional, but a profile-specific
248 * preset with the same name as a more generic one is given a higher priority.
249 * \todo Look in a user-specific location - somewhere in the home directory.
251 * \public \memberof mlt_properties_s
252 * \param self a properties list
253 * \param name the name of a preset in a well-known location or the explicit path
254 * \return true if error
257 int mlt_properties_preset( mlt_properties self, const char *name )
259 struct stat stat_buff;
262 if ( !( self && name && strlen( name ) ) )
265 // See if name is an explicit file
266 if ( ! stat( name, &stat_buff ) )
268 return load_properties( self, name );
272 // Look for profile-specific preset before a generic one.
273 char *data = getenv( "MLT_PRESETS_PATH" );
274 const char *type = mlt_properties_get( self, "mlt_type" );
275 const char *service = mlt_properties_get( self, "mlt_service" );
276 const char *profile = mlt_environment( "MLT_PROFILE" );
281 data = strdup( data );
285 data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + 9 );
286 strcpy( data, mlt_environment( "MLT_DATA" ) );
287 strcat( data, "/presets" );
289 if ( data && type && service )
291 char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) );
292 sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name );
293 if ( load_properties( self, path ) )
295 sprintf( path, "%s/%s/%s/%s", data, type, service, name );
296 error = load_properties( self, path );
309 /** Generate a hash key.
311 * \private \memberof mlt_properties_s
312 * \param name a string
316 static inline int generate_hash( const char *name )
321 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
325 /** Copy a serializable property to a properties list that is mirroring this one.
327 * Special case - when a container (such as loader) is protecting another
328 * producer, we need to ensure that properties are passed through to the
330 * \private \memberof mlt_properties_s
331 * \param self a properties list
332 * \param name the name of the property to copy
335 static inline void mlt_properties_do_mirror( mlt_properties self, const char *name )
337 property_list *list = self->local;
338 if ( list->mirror != NULL )
340 char *value = mlt_properties_get( self, name );
342 mlt_properties_set( list->mirror, name, value );
346 /** Increment the reference count.
348 * \public \memberof mlt_properties_s
349 * \param self a properties list
350 * \return the new reference count
353 int mlt_properties_inc_ref( mlt_properties self )
358 property_list *list = self->local;
359 pthread_mutex_lock( &list->mutex );
360 result = ++ list->ref_count;
361 pthread_mutex_unlock( &list->mutex );
366 /** Decrement the reference count.
368 * \public \memberof mlt_properties_s
369 * \param self a properties list
370 * \return the new reference count
373 int mlt_properties_dec_ref( mlt_properties self )
378 property_list *list = self->local;
379 pthread_mutex_lock( &list->mutex );
380 result = -- list->ref_count;
381 pthread_mutex_unlock( &list->mutex );
386 /** Get the reference count.
388 * \public \memberof mlt_properties_s
389 * \param self a properties list
390 * \return the current reference count
393 int mlt_properties_ref_count( mlt_properties self )
397 property_list *list = self->local;
398 return list->ref_count;
403 /** Set a properties list to be a mirror copy of another.
405 * Note that this does not copy all existing properties. Rather, you must
406 * call this before setting the properties that you wish to copy.
407 * \public \memberof mlt_properties_s
408 * \param that the properties which will receive copies of the properties as they are set.
409 * \param self the properties to mirror
412 void mlt_properties_mirror( mlt_properties self, mlt_properties that )
414 property_list *list = self->local;
418 /** Copy all serializable properties to another properties list.
420 * \public \memberof mlt_properties_s
421 * \param self The properties to copy to
422 * \param that The properties to copy from
426 int mlt_properties_inherit( mlt_properties self, mlt_properties that )
428 int count = mlt_properties_count( that );
430 for ( i = 0; i < count; i ++ )
432 char *value = mlt_properties_get_value( that, i );
435 char *name = mlt_properties_get_name( that, i );
436 mlt_properties_set( self, name, value );
442 /** Pass all serializable properties that match a prefix to another properties object
444 * \public \memberof mlt_properties_s
445 * \param self the properties to copy to
446 * \param that The properties to copy from
447 * \param prefix the property names to match (required)
451 int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix )
453 int count = mlt_properties_count( that );
454 int length = strlen( prefix );
456 for ( i = 0; i < count; i ++ )
458 char *name = mlt_properties_get_name( that, i );
459 if ( !strncmp( name, prefix, length ) )
461 char *value = mlt_properties_get_value( that, i );
463 mlt_properties_set( self, name + length, value );
469 /** Locate a property by name.
471 * \private \memberof mlt_properties_s
472 * \param self a properties list
473 * \param name the property to lookup by name
474 * \return the property or NULL for failure
477 static inline mlt_property mlt_properties_find( mlt_properties self, const char *name )
479 property_list *list = self->local;
480 mlt_property value = NULL;
481 int key = generate_hash( name );
483 mlt_properties_lock( self );
485 int i = list->hash[ key ] - 1;
488 // Check if we're hashed
489 if ( list->count > 0 &&
490 name[ 0 ] == list->name[ i ][ 0 ] &&
491 !strcmp( list->name[ i ], name ) )
492 value = list->value[ i ];
495 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
496 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
497 value = list->value[ i ];
499 mlt_properties_unlock( self );
504 /** Add a new property.
506 * \private \memberof mlt_properties_s
507 * \param self a properties list
508 * \param name the name of the new property
509 * \return the new property
512 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
514 property_list *list = self->local;
515 int key = generate_hash( name );
518 mlt_properties_lock( self );
520 // Check that we have space and resize if necessary
521 if ( list->count == list->size )
524 list->name = realloc( list->name, list->size * sizeof( const char * ) );
525 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
528 // Assign name/value pair
529 list->name[ list->count ] = strdup( name );
530 list->value[ list->count ] = mlt_property_init( );
532 // Assign to hash table
533 if ( list->hash[ key ] == 0 )
534 list->hash[ key ] = list->count + 1;
536 // Return and increment count accordingly
537 result = list->value[ list->count ++ ];
539 mlt_properties_unlock( self );
544 /** Fetch a property by name and add one if not found.
546 * \private \memberof mlt_properties_s
547 * \param self a properties list
548 * \param name the property to lookup or add
549 * \return the property
552 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
554 // Try to find an existing property first
555 mlt_property property = mlt_properties_find( self, name );
557 // If it wasn't found, create one
558 if ( property == NULL )
559 property = mlt_properties_add( self, name );
561 // Return the property
565 /** Copy a property to another properties list.
567 * \public \memberof mlt_properties_s
568 * \author Zach <zachary.drew@gmail.com>
569 * \param self the properties to copy to
570 * \param that the properties to copy from
571 * \param name the name of the property to copy
574 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
576 // Make sure the source property isn't null.
577 mlt_property that_prop = mlt_properties_find( that, name );
578 if( that_prop == NULL )
581 mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
584 /** Copy all properties specified in a comma-separated list to another properties list.
586 * White space is also a delimiter.
587 * \public \memberof mlt_properties_s
588 * \author Zach <zachary.drew@gmail.com>
589 * \param self the properties to copy to
590 * \param that the properties to copy from
591 * \param list a delimited list of property names
596 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
598 char *props = strdup( list );
600 const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
605 count = strcspn( ptr, delim );
607 if( ptr[count] == '\0' )
610 ptr[count] = '\0'; // Make it a real string
612 mlt_properties_pass_property( self, that, ptr );
615 ptr += strspn( ptr, delim );
624 /** Set a property to a string.
626 * The property name "properties" is reserved to load the preset in \p value.
627 * When the value begins with '@' then it is interpreted as a very simple math
628 * expression containing only the +, -, *, and / operators.
629 * The event "property-changed" is fired after the property has been set.
631 * This makes a copy of the string value you supply.
632 * \public \memberof mlt_properties_s
633 * \param self a properties list
634 * \param name the property to set
635 * \param value the property's new value
636 * \return true if error
639 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
643 // Fetch the property to work with
644 mlt_property property = mlt_properties_fetch( self, name );
646 // Set it if not NULL
647 if ( property == NULL )
649 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
651 else if ( value == NULL )
653 error = mlt_property_set_string( property, value );
654 mlt_properties_do_mirror( self, name );
656 else if ( *value != '@' )
658 error = mlt_property_set_string( property, value );
659 mlt_properties_do_mirror( self, name );
660 if ( !strcmp( name, "properties" ) )
661 mlt_properties_preset( self, value );
663 else if ( value[ 0 ] == '@' )
672 while ( *value != '\0' )
674 int length = strcspn( value, "+-*/" );
676 // Get the identifier
677 strncpy( id, value, length );
681 // Determine the value
682 if ( isdigit( id[ 0 ] ) )
683 current = atof( id );
685 current = mlt_properties_get_double( self, id );
687 // Apply the operation
700 total = total / current;
705 op = *value != '\0' ? *value ++ : ' ';
708 error = mlt_property_set_double( property, total );
709 mlt_properties_do_mirror( self, name );
712 mlt_events_fire( self, "property-changed", name, NULL );
717 /** Set or default a property to a string.
719 * This makes a copy of the string value you supply.
720 * \public \memberof mlt_properties_s
721 * \param self a properties list
722 * \param name the property to set
723 * \param value the string value to set or NULL to use the default
724 * \param def the default string if value is NULL
725 * \return true if error
728 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
730 return mlt_properties_set( self, name, value == NULL ? def : value );
733 /** Get a string value by name.
735 * Do not free the returned string. It's lifetime is controlled by the property
736 * and this properties object.
737 * \public \memberof mlt_properties_s
738 * \param self a properties list
739 * \param name the property to get
740 * \return the property's string value or NULL if it does not exist
743 char *mlt_properties_get( mlt_properties self, const char *name )
745 mlt_property value = mlt_properties_find( self, name );
746 property_list *list = self->local;
747 return value == NULL ? NULL : mlt_property_get_string_l( value, list->locale );
750 /** Get a property name by index.
752 * Do not free the returned string.
753 * \public \memberof mlt_properties_s
754 * \param self a properties list
755 * \param index the numeric index of the property
756 * \return the name of the property or NULL if index is out of range
759 char *mlt_properties_get_name( mlt_properties self, int index )
761 property_list *list = self->local;
762 if ( index >= 0 && index < list->count )
763 return list->name[ index ];
767 /** Get a property's string value by index.
769 * Do not free the returned string.
770 * \public \memberof mlt_properties_s
771 * \param self a properties list
772 * \param index the numeric index of the property
773 * \return the property value as a string or NULL if the index is out of range
776 char *mlt_properties_get_value( mlt_properties self, int index )
778 property_list *list = self->local;
779 if ( index >= 0 && index < list->count )
780 return mlt_property_get_string_l( list->value[ index ], list->locale );
784 /** Get a data value by index.
786 * Do not free the returned pointer if you supplied a destructor function when you
788 * \public \memberof mlt_properties_s
789 * \param self a properties list
790 * \param index the numeric index of the property
791 * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
794 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
796 property_list *list = self->local;
797 if ( index >= 0 && index < list->count )
798 return mlt_property_get_data( list->value[ index ], size );
802 /** Return the number of items in the list.
804 * \public \memberof mlt_properties_s
805 * \param self a properties list
806 * \return the number of property objects
809 int mlt_properties_count( mlt_properties self )
811 property_list *list = self->local;
815 /** Set a value by parsing a name=value string.
817 * \public \memberof mlt_properties_s
818 * \param self a properties list
819 * \param namevalue a string containing name and value delimited by '='
820 * \return true if there was an error
823 int mlt_properties_parse( mlt_properties self, const char *namevalue )
825 char *name = strdup( namevalue );
828 char *ptr = strchr( name, '=' );
836 value = strdup( ptr );
841 value = strdup( ptr );
842 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
843 value[ strlen( value ) - 1 ] = '\0';
848 value = strdup( "" );
851 error = mlt_properties_set( self, name, value );
859 /** Get an integer associated to the name.
861 * \public \memberof mlt_properties_s
862 * \param self a properties list
863 * \param name the property to get
864 * \return The integer value, 0 if not found (which may also be a legitimate value)
867 int mlt_properties_get_int( mlt_properties self, const char *name )
869 mlt_property value = mlt_properties_find( self, name );
870 return value == NULL ? 0 : mlt_property_get_int( value );
873 /** Set a property to an integer value.
875 * \public \memberof mlt_properties_s
876 * \param self a properties list
877 * \param name the property to set
878 * \param value the integer
879 * \return true if error
882 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
886 // Fetch the property to work with
887 mlt_property property = mlt_properties_fetch( self, name );
889 // Set it if not NULL
890 if ( property != NULL )
892 error = mlt_property_set_int( property, value );
893 mlt_properties_do_mirror( self, name );
896 mlt_events_fire( self, "property-changed", name, NULL );
901 /** Get a 64-bit integer associated to the name.
903 * \public \memberof mlt_properties_s
904 * \param self a properties list
905 * \param name the property to get
906 * \return the integer value, 0 if not found (which may also be a legitimate value)
909 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
911 mlt_property value = mlt_properties_find( self, name );
912 return value == NULL ? 0 : mlt_property_get_int64( value );
915 /** Set a property to a 64-bit integer value.
917 * \public \memberof mlt_properties_s
918 * \param self a properties list
919 * \param name the property to set
920 * \param value the integer
921 * \return true if error
924 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
928 // Fetch the property to work with
929 mlt_property property = mlt_properties_fetch( self, name );
931 // Set it if not NULL
932 if ( property != NULL )
934 error = mlt_property_set_int64( property, value );
935 mlt_properties_do_mirror( self, name );
938 mlt_events_fire( self, "property-changed", name, NULL );
943 /** Get a floating point value associated to the name.
945 * \public \memberof mlt_properties_s
946 * \param self a properties list
947 * \param name the property to get
948 * \return the floating point, 0 if not found (which may also be a legitimate value)
951 double mlt_properties_get_double( mlt_properties self, const char *name )
953 mlt_property value = mlt_properties_find( self, name );
954 property_list *list = self->local;
955 return value == NULL ? 0 : mlt_property_get_double_l( value, list->locale );
958 /** Set a property to a floating point value.
960 * \public \memberof mlt_properties_s
961 * \param self a properties list
962 * \param name the property to set
963 * \param value the floating point value
964 * \return true if error
967 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
971 // Fetch the property to work with
972 mlt_property property = mlt_properties_fetch( self, name );
974 // Set it if not NULL
975 if ( property != NULL )
977 error = mlt_property_set_double( property, value );
978 mlt_properties_do_mirror( self, name );
981 mlt_events_fire( self, "property-changed", name, NULL );
986 /** Get a position value associated to the name.
988 * \public \memberof mlt_properties_s
989 * \param self a properties list
990 * \param name the property to get
991 * \return the position, 0 if not found (which may also be a legitimate value)
994 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
996 mlt_property value = mlt_properties_find( self, name );
997 return value == NULL ? 0 : mlt_property_get_position( value );
1000 /** Set a property to a position value.
1002 * \public \memberof mlt_properties_s
1003 * \param self a properties list
1004 * \param name the property to get
1005 * \param value the position
1006 * \return true if error
1009 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1013 // Fetch the property to work with
1014 mlt_property property = mlt_properties_fetch( self, name );
1016 // Set it if not NULL
1017 if ( property != NULL )
1019 error = mlt_property_set_position( property, value );
1020 mlt_properties_do_mirror( self, name );
1023 mlt_events_fire( self, "property-changed", name, NULL );
1028 /** Get a binary data value associated to the name.
1030 * Do not free the returned pointer if you supplied a destructor function
1031 * when you set this property.
1032 * \public \memberof mlt_properties_s
1033 * \param self a properties list
1034 * \param name the property to get
1035 * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1038 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1040 mlt_property value = mlt_properties_find( self, name );
1041 return value == NULL ? NULL : mlt_property_get_data( value, length );
1044 /** Store binary data as a property.
1046 * \public \memberof mlt_properties_s
1047 * \param self a properties list
1048 * \param name the property to set
1049 * \param value an opaque pointer to binary data
1050 * \param length the size of the binary data in bytes (optional)
1051 * \param destroy a function to deallocate the binary data when the property is closed (optional)
1052 * \param serialise a function that can serialize the binary data as text (optional)
1053 * \return true if error
1056 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1060 // Fetch the property to work with
1061 mlt_property property = mlt_properties_fetch( self, name );
1063 // Set it if not NULL
1064 if ( property != NULL )
1065 error = mlt_property_set_data( property, value, length, destroy, serialise );
1067 mlt_events_fire( self, "property-changed", name, NULL );
1072 /** Rename a property.
1074 * \public \memberof mlt_properties_s
1075 * \param self a properties list
1076 * \param source the property to rename
1077 * \param dest the new name
1078 * \return true if the name is already in use
1081 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1083 mlt_property value = mlt_properties_find( self, dest );
1085 if ( value == NULL )
1087 property_list *list = self->local;
1091 mlt_properties_lock( self );
1092 for ( i = 0; i < list->count; i ++ )
1094 if ( !strcmp( list->name[ i ], source ) )
1096 free( list->name[ i ] );
1097 list->name[ i ] = strdup( dest );
1098 list->hash[ generate_hash( dest ) ] = i + 1;
1102 mlt_properties_unlock( self );
1105 return value != NULL;
1108 /** Dump the properties to a file handle.
1110 * \public \memberof mlt_properties_s
1111 * \param self a properties list
1112 * \param output a file handle
1115 void mlt_properties_dump( mlt_properties self, FILE *output )
1117 property_list *list = self->local;
1119 for ( i = 0; i < list->count; i ++ )
1120 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1121 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1124 /** Output the properties to a file handle.
1126 * This version includes reference counts and does not put each property on a new line.
1127 * \public \memberof mlt_properties_s
1128 * \param self a properties pointer
1129 * \param title a string to preface the output
1130 * \param output a file handle
1132 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1134 if ( output == NULL ) output = stderr;
1135 fprintf( output, "%s: ", title );
1138 property_list *list = self->local;
1140 fprintf( output, "[ ref=%d", list->ref_count );
1141 for ( i = 0; i < list->count; i ++ )
1142 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1143 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1145 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1146 fprintf( output, " ]" );
1148 fprintf( output, "\n" );
1151 /** Save the properties to a file by name.
1153 * This uses the dump format - one line per property.
1154 * \public \memberof mlt_properties_s
1155 * \param self a properties list
1156 * \param filename the name of a file to create or overwrite
1157 * \return true if there was an error
1160 int mlt_properties_save( mlt_properties self, const char *filename )
1163 FILE *f = fopen( filename, "w" );
1166 mlt_properties_dump( self, f );
1173 /* This is a very basic cross platform fnmatch replacement - it will fail in
1174 * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1177 /** Test whether a filename or pathname matches a shell-style pattern.
1179 * \private \memberof mlt_properties_s
1180 * \param wild a string containing a wildcard pattern
1181 * \param file the name of a file to test against
1182 * \return true if the file name matches the wildcard pattern
1185 static int mlt_fnmatch( const char *wild, const char *file )
1190 while( f < strlen( file ) && w < strlen( wild ) )
1192 if ( wild[ w ] == '*' )
1195 if ( w == strlen( wild ) )
1197 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1200 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1205 else if ( wild[ 0 ] == '*' )
1215 return strlen( file ) == f && strlen( wild ) == w;
1218 /** Compare the string or serialized value of two properties.
1220 * \private \memberof mlt_properties_s
1221 * \param self a property
1222 * \param that a property
1223 * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1226 static int mlt_compare( const void *self, const void *that )
1228 return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1231 /** Get the contents of a directory.
1233 * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1234 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1235 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1236 * \public \memberof mlt_properties_s
1237 * \param self a properties list
1238 * \param dirname the name of the directory
1239 * \param pattern a wildcard pattern to filter the directory listing
1240 * \param sort Do you want to sort the directory listing?
1241 * \return the number of items in the directory listing
1244 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1246 DIR *dir = opendir( dirname );
1251 struct dirent *de = readdir( dir );
1252 char fullname[ 1024 ];
1255 sprintf( key, "%d", mlt_properties_count( self ) );
1256 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1257 if ( pattern == NULL )
1258 mlt_properties_set( self, key, fullname );
1259 else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1260 mlt_properties_set( self, key, fullname );
1261 de = readdir( dir );
1267 if ( sort && mlt_properties_count( self ) )
1269 property_list *list = self->local;
1270 mlt_properties_lock( self );
1271 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1272 mlt_properties_unlock( self );
1275 return mlt_properties_count( self );
1278 /** Close a properties object.
1280 * Deallocates the properties object and everything it contains.
1281 * \public \memberof mlt_properties_s
1282 * \param self a properties object
1285 void mlt_properties_close( mlt_properties self )
1287 if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1289 if ( self->close != NULL )
1291 self->close( self->close_object );
1295 property_list *list = self->local;
1298 #if _MLT_PROPERTY_CHECKS_ == 1
1300 mlt_properties_debug( self, "Closing", stderr );
1303 #ifdef _MLT_PROPERTY_CHECKS_
1304 // Increment destroyed count
1305 properties_destroyed ++;
1307 // Show current stats - these should match when the app is closed
1308 mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1311 // Clean up names and values
1312 for ( index = list->count - 1; index >= 0; index -- )
1314 mlt_property_close( list->value[ index ] );
1315 free( list->name[ index ] );
1320 freelocale( list->locale );
1322 // Clear up the list
1323 pthread_mutex_destroy( &list->mutex );
1325 free( list->value );
1328 // Free self now if self has no child
1329 if ( self->child == NULL )
1335 /** Determine if the properties list is really just a sequence or ordered list.
1337 * \public \memberof mlt_properties_s
1338 * \param properties a properties list
1339 * \return true if all of the property names are numeric (a sequence)
1342 int mlt_properties_is_sequence( mlt_properties properties )
1345 int n = mlt_properties_count( properties );
1346 for ( i = 0; i < n; i++ )
1347 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1352 /** \brief YAML Tiny Parser context structure
1354 * YAML is a nifty text format popular in the Ruby world as a cleaner,
1355 * less verbose alternative to XML. See this Wikipedia topic for an overview:
1356 * http://en.wikipedia.org/wiki/YAML
1357 * The YAML specification is at:
1359 * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1360 * using here (for the same reasons):
1361 * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1365 struct yaml_parser_context
1372 unsigned int block_indent;
1375 typedef struct yaml_parser_context *yaml_parser;
1377 /** Remove spaces from the left side of a string.
1379 * \param s the string to trim
1380 * \return the number of characters removed
1383 static unsigned int ltrim( char **s )
1387 int n = strlen( c );
1388 for ( i = 0; i < n && *c == ' '; i++, c++ );
1393 /** Remove spaces from the right side of a string.
1395 * \param s the string to trim
1396 * \return the number of characters removed
1399 static unsigned int rtrim( char *s )
1401 int n = strlen( s );
1403 for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1408 /** Parse a line of YAML Tiny.
1410 * Adds a property if needed.
1411 * \private \memberof yaml_parser_context
1412 * \param context a YAML Tiny Parser context
1413 * \param namevalue a line of YAML Tiny
1414 * \return true if there was an error
1417 static int parse_yaml( yaml_parser context, const char *namevalue )
1419 char *name_ = strdup( namevalue );
1423 char *ptr = strchr( name, ':' );
1424 unsigned int indent = ltrim( &name );
1425 mlt_properties properties = mlt_deque_peek_front( context->stack );
1427 // Ascending one more levels in the tree
1428 if ( indent < context->level )
1431 unsigned int n = ( context->level - indent ) / 2;
1432 for ( i = 0; i < n; i++ )
1433 mlt_deque_pop_front( context->stack );
1434 properties = mlt_deque_peek_front( context->stack );
1435 context->level = indent;
1438 // Descending a level in the tree
1439 else if ( indent > context->level && context->block == 0 )
1441 context->level = indent;
1444 // If there is a colon that is not part of a block
1445 if ( ptr && ( indent == context->level ) )
1447 // Reset block processing
1448 if ( context->block_name )
1450 free( context->block_name );
1451 context->block_name = NULL;
1455 // Terminate the name and setup the value pointer
1459 char *comment = strchr( ptr, '#' );
1465 // Trim leading and trailing spaces from bare value
1469 // No value means a child
1470 if ( strcmp( ptr, "" ) == 0 )
1472 mlt_properties child = mlt_properties_new();
1473 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1474 mlt_properties_set_data( properties, name, child, 0,
1475 ( mlt_destructor )mlt_properties_close, NULL );
1476 mlt_deque_push_front( context->stack, child );
1482 // A dash indicates a sequence item
1483 if ( name[0] == '-' )
1485 mlt_properties child = mlt_properties_new();
1488 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1489 snprintf( key, sizeof(key), "%d", context->index++ );
1490 mlt_properties_set_data( properties, key, child, 0,
1491 ( mlt_destructor )mlt_properties_close, NULL );
1492 mlt_deque_push_front( context->stack, child );
1495 context->level += ltrim( &name ) + 1;
1503 value = strdup( ptr );
1504 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1505 value[ strlen( value ) - 1 ] = 0;
1508 // Value is folded or unfolded block
1509 else if ( *ptr == '|' || *ptr == '>' )
1511 context->block = *ptr;
1512 context->block_name = strdup( name );
1513 context->block_indent = 0;
1514 value = strdup( "" );
1520 value = strdup( ptr );
1524 // A list of scalars
1525 else if ( name[0] == '-' )
1527 // Reset block processing
1528 if ( context->block_name )
1530 free( context->block_name );
1531 context->block_name = NULL;
1537 snprintf( key, sizeof(key), "%d", context->index++ );
1541 char *comment = strchr( ptr, '#' );
1545 // Trim leading and trailing spaces from bare value
1553 value = strdup( ptr );
1554 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1555 value[ strlen( value ) - 1 ] = 0;
1558 // Value is folded or unfolded block
1559 else if ( *ptr == '|' || *ptr == '>' )
1561 context->block = *ptr;
1562 context->block_name = strdup( key );
1563 context->block_indent = 0;
1564 value = strdup( "" );
1570 value = strdup( ptr );
1574 name = name_ = strdup( key );
1578 else if ( context->block == '|' )
1580 if ( context->block_indent == 0 )
1581 context->block_indent = indent;
1582 if ( indent > context->block_indent )
1583 name = &name_[ context->block_indent ];
1585 char *old_value = mlt_properties_get( properties, context->block_name );
1586 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1587 strcpy( value, old_value );
1588 if ( strcmp( old_value, "" ) )
1589 strcat( value, "\n" );
1590 strcat( value, name );
1591 name = context->block_name;
1595 else if ( context->block == '>' )
1599 char *old_value = mlt_properties_get( properties, context->block_name );
1601 // Blank line (prepended with spaces) is new line
1602 if ( strcmp( name, "" ) == 0 )
1604 value = calloc( 1, strlen( old_value ) + 2 );
1605 strcat( value, old_value );
1606 strcat( value, "\n" );
1608 // Concatenate with space
1611 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1612 strcat( value, old_value );
1613 if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1614 strcat( value, " " );
1615 strcat( value, name );
1617 name = context->block_name;
1622 value = strdup( "" );
1625 error = mlt_properties_set( properties, name, value );
1627 if ( !strcmp( name, "LC_NUMERIC" ) )
1628 mlt_properties_set_lcnumeric( properties, value );
1636 /** Parse a YAML Tiny file by name.
1638 * \public \memberof mlt_properties_s
1639 * \param filename the name of a text file containing YAML Tiny
1640 * \return a new properties list
1643 mlt_properties mlt_properties_parse_yaml( const char *filename )
1645 // Construct a standalone properties object
1646 mlt_properties self = mlt_properties_new( );
1651 FILE *file = fopen( filename, "r" );
1653 // Load contents of file
1658 char *ptemp = &temp[ 0 ];
1660 // Default to LC_NUMERIC = C
1661 mlt_properties_set_lcnumeric( self, "C" );
1664 yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1665 context->stack = mlt_deque_init();
1666 mlt_deque_push_front( context->stack, self );
1668 // Read each string from the file
1669 while( fgets( temp, 1024, file ) )
1671 // Check for end-of-stream
1672 if ( strncmp( ptemp, "...", 3 ) == 0 )
1676 temp[ strlen( temp ) - 1 ] = '\0';
1678 // Skip blank lines, comment lines, and document separator
1679 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1680 && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1681 parse_yaml( context, temp );
1686 mlt_deque_close( context->stack );
1687 if ( context->block_name )
1688 free( context->block_name );
1693 // Return the pointer
1698 * YAML Tiny Serializer
1701 /** How many bytes to grow at a time */
1702 #define STRBUF_GROWTH (1024)
1704 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1714 typedef struct strbuf_s *strbuf;
1716 /** Create a new string buffer
1718 * \private \memberof strbuf_s
1719 * \return a new string buffer
1722 static strbuf strbuf_new( )
1724 strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1725 buffer->size = STRBUF_GROWTH;
1726 buffer->string = calloc( 1, buffer->size );
1730 /** Destroy a string buffer
1732 * \private \memberof strbuf_s
1733 * \param buffer the string buffer to close
1736 static void strbuf_close( strbuf buffer )
1738 // We do not free buffer->string; strbuf user must save that pointer
1744 /** Format a string into a string buffer
1746 * A variable number of arguments follows the format string - one for each
1748 * \private \memberof strbuf_s
1749 * \param buffer the string buffer to write into
1750 * \param format a string that contains text and formatting instructions
1751 * \return the formatted string
1754 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1756 while ( buffer->string )
1759 va_start( ap, format );
1760 size_t len = strlen( buffer->string );
1761 size_t remain = buffer->size - len - 1;
1762 int need = vsnprintf( buffer->string + len, remain, format, ap );
1764 if ( need > -1 && need < remain )
1766 buffer->string[ len ] = 0;
1767 buffer->size += need + STRBUF_GROWTH;
1768 buffer->string = realloc( buffer->string, buffer->size );
1770 return buffer->string;
1773 /** Indent a line of YAML Tiny.
1775 * \private \memberof strbuf_s
1776 * \param output a string buffer
1777 * \param indent the number of spaces to indent
1780 static inline void indent_yaml( strbuf output, int indent )
1783 for ( j = 0; j < indent; j++ )
1784 strbuf_printf( output, " " );
1787 /** Convert a line string into a YAML block literal.
1789 * \private \memberof strbuf_s
1790 * \param output a string buffer
1791 * \param value the string to format as a block literal
1792 * \param indent the number of spaces to indent
1795 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1797 char *v = strdup( value );
1799 char *eol = strchr( sol, '\n' );
1803 indent_yaml( output, indent );
1805 strbuf_printf( output, "%s\n", sol );
1807 eol = strchr( sol, '\n' );
1809 indent_yaml( output, indent );
1810 strbuf_printf( output, "%s\n", sol );
1813 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1815 * \private \memberof mlt_properties_s
1816 * \param self a properties list
1817 * \param output a string buffer to hold the serialized YAML Tiny
1818 * \param indent the number of spaces to indent (for recursion, initialize to 0)
1819 * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1822 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1824 property_list *list = self->local;
1827 for ( i = 0; i < list->count; i ++ )
1829 // This implementation assumes that all data elements are property lists.
1830 // Unfortunately, we do not have run time type identification.
1831 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1833 if ( mlt_properties_is_sequence( self ) )
1835 // Ignore hidden/non-serialisable items
1836 if ( list->name[ i ][ 0 ] != '_' )
1838 // Indicate a sequence item
1839 indent_yaml( output, indent );
1840 strbuf_printf( output, "- " );
1842 // If the value can be represented as a string
1843 const char *value = mlt_properties_get( self, list->name[ i ] );
1844 if ( value && strcmp( value, "" ) )
1846 // Determine if this is an unfolded block literal
1847 if ( strchr( value, '\n' ) )
1849 strbuf_printf( output, "|\n" );
1850 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1854 strbuf_printf( output, "%s\n", value );
1860 serialise_yaml( child, output, indent + 2, 1 );
1864 // Assume this is a normal map-oriented properties list
1865 const char *value = mlt_properties_get( self, list->name[ i ] );
1867 // Ignore hidden/non-serialisable items
1868 // If the value can be represented as a string
1869 if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1871 if ( is_parent_sequence == 0 )
1872 indent_yaml( output, indent );
1874 is_parent_sequence = 0;
1876 // Determine if this is an unfolded block literal
1877 if ( strchr( value, '\n' ) )
1879 strbuf_printf( output, "%s: |\n", list->name[ i ] );
1880 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1884 strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
1888 // Output a child as a map item
1891 indent_yaml( output, indent );
1892 strbuf_printf( output, "%s:\n", list->name[ i ] );
1895 serialise_yaml( child, output, indent + 2, 0 );
1901 /** Serialize a properties list as a string of YAML Tiny.
1903 * The caller MUST free the returned string!
1904 * This operates on properties containing properties as a hierarchical data
1906 * \public \memberof mlt_properties_s
1907 * \param self a properties list
1908 * \return a string containing YAML Tiny that represents the properties list
1911 char *mlt_properties_serialise_yaml( mlt_properties self )
1913 const char *lc_numeric = mlt_properties_get_lcnumeric( self );
1914 strbuf b = strbuf_new();
1915 strbuf_printf( b, "---\n" );
1916 mlt_properties_set_lcnumeric( self, "C" );
1917 serialise_yaml( self, b, 0, 0 );
1918 mlt_properties_set_lcnumeric( self, lc_numeric );
1919 strbuf_printf( b, "...\n" );
1920 char *ret = b->string;
1925 /** Protect a properties list against concurrent access.
1927 * \public \memberof mlt_properties_s
1928 * \param self a properties list
1931 void mlt_properties_lock( mlt_properties self )
1934 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
1937 /** End protecting a properties list against concurrent access.
1939 * \public \memberof mlt_properties_s
1940 * \param self a properties list
1943 void mlt_properties_unlock( mlt_properties self )
1946 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );