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;
139 #if defined(__linux__) || defined(__DARWIN__)
141 freelocale( list->locale );
142 list->locale = newlocale( LC_NUMERIC_MASK, locale, NULL );
144 error = list->locale == NULL;
152 /** Get the numeric locale for this properties object.
154 * Do not free the result.
155 * \public \memberof mlt_properties_s
156 * \param self a properties list
157 * \return the locale name if this properties has a specific locale it is using, NULL otherwise
160 const char* mlt_properties_get_lcnumeric( mlt_properties self )
162 property_list *list = self->local;
163 const char *result = NULL;
167 #if defined(__DARWIN__)
168 result = querylocale( LC_NUMERIC, list->locale );
169 #elif defined(__linux__)
170 result = list->locale->__names[ LC_NUMERIC ];
172 // TODO: not yet sure what to do on other platforms
178 static int load_properties( mlt_properties self, const char *filename )
181 FILE *file = fopen( filename, "r" );
183 // Load contents of file
188 char last[ 1024 ] = "";
190 // Read each string from the file
191 while( fgets( temp, 1024, file ) )
194 temp[ strlen( temp ) - 1 ] = '\0';
196 // Check if the line starts with a .
197 if ( temp[ 0 ] == '.' )
200 sprintf( temp2, "%s%s", last, temp );
201 strcpy( temp, temp2 );
203 else if ( strchr( temp, '=' ) )
205 strcpy( last, temp );
206 *( strchr( last, '=' ) ) = '\0';
209 // Parse and set the property
210 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
211 mlt_properties_parse( self, temp );
217 return file? 0 : errno;
220 /** Create a properties object by reading a .properties text file.
222 * Free the properties object with mlt_properties_close().
223 * \deprecated Please start using mlt_properties_parse_yaml().
224 * \public \memberof mlt_properties_s
225 * \param filename the absolute file name
226 * \return a new properties object
229 mlt_properties mlt_properties_load( const char *filename )
231 // Construct a standalone properties object
232 mlt_properties self = mlt_properties_new( );
235 load_properties( self, filename );
237 // Return the pointer
241 /** Set properties from a preset.
243 * Presets are typically installed to $prefix/share/mlt/presets/{type}/{service}/[{profile}/]{name}.
244 * For example, "/usr/share/mlt/presets/consumer/avformat/dv_ntsc_wide/DVD"
245 * could be an encoding preset for a widescreen NTSC DVD Video.
246 * Do not specify the type and service in the preset name parameter; these are
247 * inferred automatically from the service to which you are applying the preset.
248 * Using the example above and assuming you are calling this function on the
249 * avformat consumer, the name passed to the function should simply be DVD.
250 * Note that the profile portion of the path is optional, but a profile-specific
251 * preset with the same name as a more generic one is given a higher priority.
252 * \todo Look in a user-specific location - somewhere in the home directory.
254 * \public \memberof mlt_properties_s
255 * \param self a properties list
256 * \param name the name of a preset in a well-known location or the explicit path
257 * \return true if error
260 int mlt_properties_preset( mlt_properties self, const char *name )
262 struct stat stat_buff;
265 if ( !( self && name && strlen( name ) ) )
268 // See if name is an explicit file
269 if ( ! stat( name, &stat_buff ) )
271 return load_properties( self, name );
275 // Look for profile-specific preset before a generic one.
276 char *data = getenv( "MLT_PRESETS_PATH" );
277 const char *type = mlt_properties_get( self, "mlt_type" );
278 const char *service = mlt_properties_get( self, "mlt_service" );
279 const char *profile = mlt_environment( "MLT_PROFILE" );
284 data = strdup( data );
288 data = malloc( strlen( mlt_environment( "MLT_DATA" ) ) + 9 );
289 strcpy( data, mlt_environment( "MLT_DATA" ) );
290 strcat( data, "/presets" );
292 if ( data && type && service )
294 char *path = malloc( 5 + strlen(name) + strlen(data) + strlen(type) + strlen(service) + ( profile? strlen(profile) : 0 ) );
295 sprintf( path, "%s/%s/%s/%s/%s", data, type, service, profile, name );
296 if ( load_properties( self, path ) )
298 sprintf( path, "%s/%s/%s/%s", data, type, service, name );
299 error = load_properties( self, path );
312 /** Generate a hash key.
314 * \private \memberof mlt_properties_s
315 * \param name a string
319 static inline int generate_hash( const char *name )
324 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
328 /** Copy a serializable property to a properties list that is mirroring this one.
330 * Special case - when a container (such as loader) is protecting another
331 * producer, we need to ensure that properties are passed through to the
333 * \private \memberof mlt_properties_s
334 * \param self a properties list
335 * \param name the name of the property to copy
338 static inline void mlt_properties_do_mirror( mlt_properties self, const char *name )
340 property_list *list = self->local;
341 if ( list->mirror != NULL )
343 char *value = mlt_properties_get( self, name );
345 mlt_properties_set( list->mirror, name, value );
349 /** Increment the reference count.
351 * \public \memberof mlt_properties_s
352 * \param self a properties list
353 * \return the new reference count
356 int mlt_properties_inc_ref( mlt_properties self )
361 property_list *list = self->local;
362 pthread_mutex_lock( &list->mutex );
363 result = ++ list->ref_count;
364 pthread_mutex_unlock( &list->mutex );
369 /** Decrement the reference count.
371 * \public \memberof mlt_properties_s
372 * \param self a properties list
373 * \return the new reference count
376 int mlt_properties_dec_ref( mlt_properties self )
381 property_list *list = self->local;
382 pthread_mutex_lock( &list->mutex );
383 result = -- list->ref_count;
384 pthread_mutex_unlock( &list->mutex );
389 /** Get the reference count.
391 * \public \memberof mlt_properties_s
392 * \param self a properties list
393 * \return the current reference count
396 int mlt_properties_ref_count( mlt_properties self )
400 property_list *list = self->local;
401 return list->ref_count;
406 /** Set a properties list to be a mirror copy of another.
408 * Note that this does not copy all existing properties. Rather, you must
409 * call this before setting the properties that you wish to copy.
410 * \public \memberof mlt_properties_s
411 * \param that the properties which will receive copies of the properties as they are set.
412 * \param self the properties to mirror
415 void mlt_properties_mirror( mlt_properties self, mlt_properties that )
417 property_list *list = self->local;
421 /** Copy all serializable properties to another properties list.
423 * \public \memberof mlt_properties_s
424 * \param self The properties to copy to
425 * \param that The properties to copy from
429 int mlt_properties_inherit( mlt_properties self, mlt_properties that )
431 int count = mlt_properties_count( that );
433 for ( i = 0; i < count; i ++ )
435 char *value = mlt_properties_get_value( that, i );
438 char *name = mlt_properties_get_name( that, i );
439 mlt_properties_set( self, name, value );
445 /** Pass all serializable properties that match a prefix to another properties object
447 * \public \memberof mlt_properties_s
448 * \param self the properties to copy to
449 * \param that The properties to copy from
450 * \param prefix the property names to match (required)
454 int mlt_properties_pass( mlt_properties self, mlt_properties that, const char *prefix )
456 int count = mlt_properties_count( that );
457 int length = strlen( prefix );
459 for ( i = 0; i < count; i ++ )
461 char *name = mlt_properties_get_name( that, i );
462 if ( !strncmp( name, prefix, length ) )
464 char *value = mlt_properties_get_value( that, i );
466 mlt_properties_set( self, name + length, value );
472 /** Locate a property by name.
474 * \private \memberof mlt_properties_s
475 * \param self a properties list
476 * \param name the property to lookup by name
477 * \return the property or NULL for failure
480 static inline mlt_property mlt_properties_find( mlt_properties self, const char *name )
482 property_list *list = self->local;
483 mlt_property value = NULL;
484 int key = generate_hash( name );
486 mlt_properties_lock( self );
488 int i = list->hash[ key ] - 1;
491 // Check if we're hashed
492 if ( list->count > 0 &&
493 name[ 0 ] == list->name[ i ][ 0 ] &&
494 !strcmp( list->name[ i ], name ) )
495 value = list->value[ i ];
498 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
499 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
500 value = list->value[ i ];
502 mlt_properties_unlock( self );
507 /** Add a new property.
509 * \private \memberof mlt_properties_s
510 * \param self a properties list
511 * \param name the name of the new property
512 * \return the new property
515 static mlt_property mlt_properties_add( mlt_properties self, const char *name )
517 property_list *list = self->local;
518 int key = generate_hash( name );
521 mlt_properties_lock( self );
523 // Check that we have space and resize if necessary
524 if ( list->count == list->size )
527 list->name = realloc( list->name, list->size * sizeof( const char * ) );
528 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
531 // Assign name/value pair
532 list->name[ list->count ] = strdup( name );
533 list->value[ list->count ] = mlt_property_init( );
535 // Assign to hash table
536 if ( list->hash[ key ] == 0 )
537 list->hash[ key ] = list->count + 1;
539 // Return and increment count accordingly
540 result = list->value[ list->count ++ ];
542 mlt_properties_unlock( self );
547 /** Fetch a property by name and add one if not found.
549 * \private \memberof mlt_properties_s
550 * \param self a properties list
551 * \param name the property to lookup or add
552 * \return the property
555 static mlt_property mlt_properties_fetch( mlt_properties self, const char *name )
557 // Try to find an existing property first
558 mlt_property property = mlt_properties_find( self, name );
560 // If it wasn't found, create one
561 if ( property == NULL )
562 property = mlt_properties_add( self, name );
564 // Return the property
568 /** Copy a property to another properties list.
570 * \public \memberof mlt_properties_s
571 * \author Zach <zachary.drew@gmail.com>
572 * \param self the properties to copy to
573 * \param that the properties to copy from
574 * \param name the name of the property to copy
577 void mlt_properties_pass_property( mlt_properties self, mlt_properties that, const char *name )
579 // Make sure the source property isn't null.
580 mlt_property that_prop = mlt_properties_find( that, name );
581 if( that_prop == NULL )
584 mlt_property_pass( mlt_properties_fetch( self, name ), that_prop );
587 /** Copy all properties specified in a comma-separated list to another properties list.
589 * White space is also a delimiter.
590 * \public \memberof mlt_properties_s
591 * \author Zach <zachary.drew@gmail.com>
592 * \param self the properties to copy to
593 * \param that the properties to copy from
594 * \param list a delimited list of property names
599 int mlt_properties_pass_list( mlt_properties self, mlt_properties that, const char *list )
601 char *props = strdup( list );
603 const char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
608 count = strcspn( ptr, delim );
610 if( ptr[count] == '\0' )
613 ptr[count] = '\0'; // Make it a real string
615 mlt_properties_pass_property( self, that, ptr );
618 ptr += strspn( ptr, delim );
627 /** Set a property to a string.
629 * The property name "properties" is reserved to load the preset in \p value.
630 * When the value begins with '@' then it is interpreted as a very simple math
631 * expression containing only the +, -, *, and / operators.
632 * The event "property-changed" is fired after the property has been set.
634 * This makes a copy of the string value you supply.
635 * \public \memberof mlt_properties_s
636 * \param self a properties list
637 * \param name the property to set
638 * \param value the property's new value
639 * \return true if error
642 int mlt_properties_set( mlt_properties self, const char *name, const char *value )
646 // Fetch the property to work with
647 mlt_property property = mlt_properties_fetch( self, name );
649 // Set it if not NULL
650 if ( property == NULL )
652 mlt_log( NULL, MLT_LOG_FATAL, "Whoops - %s not found (should never occur)\n", name );
654 else if ( value == NULL )
656 error = mlt_property_set_string( property, value );
657 mlt_properties_do_mirror( self, name );
659 else if ( *value != '@' )
661 error = mlt_property_set_string( property, value );
662 mlt_properties_do_mirror( self, name );
663 if ( !strcmp( name, "properties" ) )
664 mlt_properties_preset( self, value );
666 else if ( value[ 0 ] == '@' )
675 while ( *value != '\0' )
677 int length = strcspn( value, "+-*/" );
679 // Get the identifier
680 strncpy( id, value, length );
684 // Determine the value
685 if ( isdigit( id[ 0 ] ) )
686 current = atof( id );
688 current = mlt_properties_get_double( self, id );
690 // Apply the operation
703 total = total / current;
708 op = *value != '\0' ? *value ++ : ' ';
711 error = mlt_property_set_double( property, total );
712 mlt_properties_do_mirror( self, name );
715 mlt_events_fire( self, "property-changed", name, NULL );
720 /** Set or default a property to a string.
722 * This makes a copy of the string value you supply.
723 * \public \memberof mlt_properties_s
724 * \param self a properties list
725 * \param name the property to set
726 * \param value the string value to set or NULL to use the default
727 * \param def the default string if value is NULL
728 * \return true if error
731 int mlt_properties_set_or_default( mlt_properties self, const char *name, const char *value, const char *def )
733 return mlt_properties_set( self, name, value == NULL ? def : value );
736 /** Get a string value by name.
738 * Do not free the returned string. It's lifetime is controlled by the property
739 * and this properties object.
740 * \public \memberof mlt_properties_s
741 * \param self a properties list
742 * \param name the property to get
743 * \return the property's string value or NULL if it does not exist
746 char *mlt_properties_get( mlt_properties self, const char *name )
748 mlt_property value = mlt_properties_find( self, name );
749 property_list *list = self->local;
750 return value == NULL ? NULL : mlt_property_get_string_l( value, list->locale );
753 /** Get a property name by index.
755 * Do not free the returned string.
756 * \public \memberof mlt_properties_s
757 * \param self a properties list
758 * \param index the numeric index of the property
759 * \return the name of the property or NULL if index is out of range
762 char *mlt_properties_get_name( mlt_properties self, int index )
764 property_list *list = self->local;
765 if ( index >= 0 && index < list->count )
766 return list->name[ index ];
770 /** Get a property's string value by index.
772 * Do not free the returned string.
773 * \public \memberof mlt_properties_s
774 * \param self a properties list
775 * \param index the numeric index of the property
776 * \return the property value as a string or NULL if the index is out of range
779 char *mlt_properties_get_value( mlt_properties self, int index )
781 property_list *list = self->local;
782 if ( index >= 0 && index < list->count )
783 return mlt_property_get_string_l( list->value[ index ], list->locale );
787 /** Get a data value by index.
789 * Do not free the returned pointer if you supplied a destructor function when you
791 * \public \memberof mlt_properties_s
792 * \param self a properties list
793 * \param index the numeric index of the property
794 * \param[out] size the size of the binary data in bytes or NULL if the index is out of range
797 void *mlt_properties_get_data_at( mlt_properties self, int index, int *size )
799 property_list *list = self->local;
800 if ( index >= 0 && index < list->count )
801 return mlt_property_get_data( list->value[ index ], size );
805 /** Return the number of items in the list.
807 * \public \memberof mlt_properties_s
808 * \param self a properties list
809 * \return the number of property objects
812 int mlt_properties_count( mlt_properties self )
814 property_list *list = self->local;
818 /** Set a value by parsing a name=value string.
820 * \public \memberof mlt_properties_s
821 * \param self a properties list
822 * \param namevalue a string containing name and value delimited by '='
823 * \return true if there was an error
826 int mlt_properties_parse( mlt_properties self, const char *namevalue )
828 char *name = strdup( namevalue );
831 char *ptr = strchr( name, '=' );
839 value = strdup( ptr );
844 value = strdup( ptr );
845 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
846 value[ strlen( value ) - 1 ] = '\0';
851 value = strdup( "" );
854 error = mlt_properties_set( self, name, value );
862 /** Get an integer associated to the name.
864 * \public \memberof mlt_properties_s
865 * \param self a properties list
866 * \param name the property to get
867 * \return The integer value, 0 if not found (which may also be a legitimate value)
870 int mlt_properties_get_int( mlt_properties self, const char *name )
872 mlt_property value = mlt_properties_find( self, name );
873 return value == NULL ? 0 : mlt_property_get_int( value );
876 /** Set a property to an integer value.
878 * \public \memberof mlt_properties_s
879 * \param self a properties list
880 * \param name the property to set
881 * \param value the integer
882 * \return true if error
885 int mlt_properties_set_int( mlt_properties self, const char *name, int value )
889 // Fetch the property to work with
890 mlt_property property = mlt_properties_fetch( self, name );
892 // Set it if not NULL
893 if ( property != NULL )
895 error = mlt_property_set_int( property, value );
896 mlt_properties_do_mirror( self, name );
899 mlt_events_fire( self, "property-changed", name, NULL );
904 /** Get a 64-bit integer associated to the name.
906 * \public \memberof mlt_properties_s
907 * \param self a properties list
908 * \param name the property to get
909 * \return the integer value, 0 if not found (which may also be a legitimate value)
912 int64_t mlt_properties_get_int64( mlt_properties self, const char *name )
914 mlt_property value = mlt_properties_find( self, name );
915 return value == NULL ? 0 : mlt_property_get_int64( value );
918 /** Set a property to a 64-bit integer value.
920 * \public \memberof mlt_properties_s
921 * \param self a properties list
922 * \param name the property to set
923 * \param value the integer
924 * \return true if error
927 int mlt_properties_set_int64( mlt_properties self, const char *name, int64_t value )
931 // Fetch the property to work with
932 mlt_property property = mlt_properties_fetch( self, name );
934 // Set it if not NULL
935 if ( property != NULL )
937 error = mlt_property_set_int64( property, value );
938 mlt_properties_do_mirror( self, name );
941 mlt_events_fire( self, "property-changed", name, NULL );
946 /** Get a floating point value associated to the name.
948 * \public \memberof mlt_properties_s
949 * \param self a properties list
950 * \param name the property to get
951 * \return the floating point, 0 if not found (which may also be a legitimate value)
954 double mlt_properties_get_double( mlt_properties self, const char *name )
956 mlt_property value = mlt_properties_find( self, name );
957 property_list *list = self->local;
958 return value == NULL ? 0 : mlt_property_get_double_l( value, list->locale );
961 /** Set a property to a floating point value.
963 * \public \memberof mlt_properties_s
964 * \param self a properties list
965 * \param name the property to set
966 * \param value the floating point value
967 * \return true if error
970 int mlt_properties_set_double( mlt_properties self, const char *name, double value )
974 // Fetch the property to work with
975 mlt_property property = mlt_properties_fetch( self, name );
977 // Set it if not NULL
978 if ( property != NULL )
980 error = mlt_property_set_double( property, value );
981 mlt_properties_do_mirror( self, name );
984 mlt_events_fire( self, "property-changed", name, NULL );
989 /** Get a position value associated to the name.
991 * \public \memberof mlt_properties_s
992 * \param self a properties list
993 * \param name the property to get
994 * \return the position, 0 if not found (which may also be a legitimate value)
997 mlt_position mlt_properties_get_position( mlt_properties self, const char *name )
999 mlt_property value = mlt_properties_find( self, name );
1000 return value == NULL ? 0 : mlt_property_get_position( value );
1003 /** Set a property to a position value.
1005 * \public \memberof mlt_properties_s
1006 * \param self a properties list
1007 * \param name the property to get
1008 * \param value the position
1009 * \return true if error
1012 int mlt_properties_set_position( mlt_properties self, const char *name, mlt_position value )
1016 // Fetch the property to work with
1017 mlt_property property = mlt_properties_fetch( self, name );
1019 // Set it if not NULL
1020 if ( property != NULL )
1022 error = mlt_property_set_position( property, value );
1023 mlt_properties_do_mirror( self, name );
1026 mlt_events_fire( self, "property-changed", name, NULL );
1031 /** Get a binary data value associated to the name.
1033 * Do not free the returned pointer if you supplied a destructor function
1034 * when you set this property.
1035 * \public \memberof mlt_properties_s
1036 * \param self a properties list
1037 * \param name the property to get
1038 * \param[out] length The size of the binary data in bytes, if available (often it is not, you should know)
1041 void *mlt_properties_get_data( mlt_properties self, const char *name, int *length )
1043 mlt_property value = mlt_properties_find( self, name );
1044 return value == NULL ? NULL : mlt_property_get_data( value, length );
1047 /** Store binary data as a property.
1049 * \public \memberof mlt_properties_s
1050 * \param self a properties list
1051 * \param name the property to set
1052 * \param value an opaque pointer to binary data
1053 * \param length the size of the binary data in bytes (optional)
1054 * \param destroy a function to deallocate the binary data when the property is closed (optional)
1055 * \param serialise a function that can serialize the binary data as text (optional)
1056 * \return true if error
1059 int mlt_properties_set_data( mlt_properties self, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
1063 // Fetch the property to work with
1064 mlt_property property = mlt_properties_fetch( self, name );
1066 // Set it if not NULL
1067 if ( property != NULL )
1068 error = mlt_property_set_data( property, value, length, destroy, serialise );
1070 mlt_events_fire( self, "property-changed", name, NULL );
1075 /** Rename a property.
1077 * \public \memberof mlt_properties_s
1078 * \param self a properties list
1079 * \param source the property to rename
1080 * \param dest the new name
1081 * \return true if the name is already in use
1084 int mlt_properties_rename( mlt_properties self, const char *source, const char *dest )
1086 mlt_property value = mlt_properties_find( self, dest );
1088 if ( value == NULL )
1090 property_list *list = self->local;
1094 mlt_properties_lock( self );
1095 for ( i = 0; i < list->count; i ++ )
1097 if ( !strcmp( list->name[ i ], source ) )
1099 free( list->name[ i ] );
1100 list->name[ i ] = strdup( dest );
1101 list->hash[ generate_hash( dest ) ] = i + 1;
1105 mlt_properties_unlock( self );
1108 return value != NULL;
1111 /** Dump the properties to a file handle.
1113 * \public \memberof mlt_properties_s
1114 * \param self a properties list
1115 * \param output a file handle
1118 void mlt_properties_dump( mlt_properties self, FILE *output )
1120 property_list *list = self->local;
1122 for ( i = 0; i < list->count; i ++ )
1123 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1124 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1127 /** Output the properties to a file handle.
1129 * This version includes reference counts and does not put each property on a new line.
1130 * \public \memberof mlt_properties_s
1131 * \param self a properties pointer
1132 * \param title a string to preface the output
1133 * \param output a file handle
1135 void mlt_properties_debug( mlt_properties self, const char *title, FILE *output )
1137 if ( output == NULL ) output = stderr;
1138 fprintf( output, "%s: ", title );
1141 property_list *list = self->local;
1143 fprintf( output, "[ ref=%d", list->ref_count );
1144 for ( i = 0; i < list->count; i ++ )
1145 if ( mlt_properties_get( self, list->name[ i ] ) != NULL )
1146 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( self, list->name[ i ] ) );
1148 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( self, list->name[ i ], NULL ) );
1149 fprintf( output, " ]" );
1151 fprintf( output, "\n" );
1154 /** Save the properties to a file by name.
1156 * This uses the dump format - one line per property.
1157 * \public \memberof mlt_properties_s
1158 * \param self a properties list
1159 * \param filename the name of a file to create or overwrite
1160 * \return true if there was an error
1163 int mlt_properties_save( mlt_properties self, const char *filename )
1166 FILE *f = fopen( filename, "w" );
1169 mlt_properties_dump( self, f );
1176 /* This is a very basic cross platform fnmatch replacement - it will fail in
1177 * many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
1180 /** Test whether a filename or pathname matches a shell-style pattern.
1182 * \private \memberof mlt_properties_s
1183 * \param wild a string containing a wildcard pattern
1184 * \param file the name of a file to test against
1185 * \return true if the file name matches the wildcard pattern
1188 static int mlt_fnmatch( const char *wild, const char *file )
1193 while( f < strlen( file ) && w < strlen( wild ) )
1195 if ( wild[ w ] == '*' )
1198 if ( w == strlen( wild ) )
1200 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
1203 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
1208 else if ( wild[ 0 ] == '*' )
1218 return strlen( file ) == f && strlen( wild ) == w;
1221 /** Compare the string or serialized value of two properties.
1223 * \private \memberof mlt_properties_s
1224 * \param self a property
1225 * \param that a property
1226 * \return < 0 if \p self less than \p that, 0 if equal, or > 0 if \p self is greater than \p that
1229 static int mlt_compare( const void *self, const void *that )
1231 return strcmp( mlt_property_get_string( *( const mlt_property * )self ), mlt_property_get_string( *( const mlt_property * )that ) );
1234 /** Get the contents of a directory.
1236 * Obtains an optionally sorted list of the files found in a directory with a specific wild card.
1237 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
1238 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
1239 * \public \memberof mlt_properties_s
1240 * \param self a properties list
1241 * \param dirname the name of the directory
1242 * \param pattern a wildcard pattern to filter the directory listing
1243 * \param sort Do you want to sort the directory listing?
1244 * \return the number of items in the directory listing
1247 int mlt_properties_dir_list( mlt_properties self, const char *dirname, const char *pattern, int sort )
1249 DIR *dir = opendir( dirname );
1254 struct dirent *de = readdir( dir );
1255 char fullname[ 1024 ];
1258 sprintf( key, "%d", mlt_properties_count( self ) );
1259 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
1260 if ( pattern == NULL )
1261 mlt_properties_set( self, key, fullname );
1262 else if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
1263 mlt_properties_set( self, key, fullname );
1264 de = readdir( dir );
1270 if ( sort && mlt_properties_count( self ) )
1272 property_list *list = self->local;
1273 mlt_properties_lock( self );
1274 qsort( list->value, mlt_properties_count( self ), sizeof( mlt_property ), mlt_compare );
1275 mlt_properties_unlock( self );
1278 return mlt_properties_count( self );
1281 /** Close a properties object.
1283 * Deallocates the properties object and everything it contains.
1284 * \public \memberof mlt_properties_s
1285 * \param self a properties object
1288 void mlt_properties_close( mlt_properties self )
1290 if ( self != NULL && mlt_properties_dec_ref( self ) <= 0 )
1292 if ( self->close != NULL )
1294 self->close( self->close_object );
1298 property_list *list = self->local;
1301 #if _MLT_PROPERTY_CHECKS_ == 1
1303 mlt_properties_debug( self, "Closing", stderr );
1306 #ifdef _MLT_PROPERTY_CHECKS_
1307 // Increment destroyed count
1308 properties_destroyed ++;
1310 // Show current stats - these should match when the app is closed
1311 mlt_log( NULL, MLT_LOG_DEBUG, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
1314 // Clean up names and values
1315 for ( index = list->count - 1; index >= 0; index -- )
1317 mlt_property_close( list->value[ index ] );
1318 free( list->name[ index ] );
1321 #if defined(__linux__) || defined(__DARWIN__)
1324 freelocale( list->locale );
1327 // Clear up the list
1328 pthread_mutex_destroy( &list->mutex );
1330 free( list->value );
1333 // Free self now if self has no child
1334 if ( self->child == NULL )
1340 /** Determine if the properties list is really just a sequence or ordered list.
1342 * \public \memberof mlt_properties_s
1343 * \param properties a properties list
1344 * \return true if all of the property names are numeric (a sequence)
1347 int mlt_properties_is_sequence( mlt_properties properties )
1350 int n = mlt_properties_count( properties );
1351 for ( i = 0; i < n; i++ )
1352 if ( ! isdigit( mlt_properties_get_name( properties, i )[0] ) )
1357 /** \brief YAML Tiny Parser context structure
1359 * YAML is a nifty text format popular in the Ruby world as a cleaner,
1360 * less verbose alternative to XML. See this Wikipedia topic for an overview:
1361 * http://en.wikipedia.org/wiki/YAML
1362 * The YAML specification is at:
1364 * YAML::Tiny is a Perl module that specifies a subset of YAML that we are
1365 * using here (for the same reasons):
1366 * http://search.cpan.org/~adamk/YAML-Tiny-1.25/lib/YAML/Tiny.pm
1370 struct yaml_parser_context
1377 unsigned int block_indent;
1380 typedef struct yaml_parser_context *yaml_parser;
1382 /** Remove spaces from the left side of a string.
1384 * \param s the string to trim
1385 * \return the number of characters removed
1388 static unsigned int ltrim( char **s )
1392 int n = strlen( c );
1393 for ( i = 0; i < n && *c == ' '; i++, c++ );
1398 /** Remove spaces from the right side of a string.
1400 * \param s the string to trim
1401 * \return the number of characters removed
1404 static unsigned int rtrim( char *s )
1406 int n = strlen( s );
1408 for ( i = n; i > 0 && s[i - 1] == ' '; --i )
1413 /** Parse a line of YAML Tiny.
1415 * Adds a property if needed.
1416 * \private \memberof yaml_parser_context
1417 * \param context a YAML Tiny Parser context
1418 * \param namevalue a line of YAML Tiny
1419 * \return true if there was an error
1422 static int parse_yaml( yaml_parser context, const char *namevalue )
1424 char *name_ = strdup( namevalue );
1428 char *ptr = strchr( name, ':' );
1429 unsigned int indent = ltrim( &name );
1430 mlt_properties properties = mlt_deque_peek_front( context->stack );
1432 // Ascending one more levels in the tree
1433 if ( indent < context->level )
1436 unsigned int n = ( context->level - indent ) / 2;
1437 for ( i = 0; i < n; i++ )
1438 mlt_deque_pop_front( context->stack );
1439 properties = mlt_deque_peek_front( context->stack );
1440 context->level = indent;
1443 // Descending a level in the tree
1444 else if ( indent > context->level && context->block == 0 )
1446 context->level = indent;
1449 // If there is a colon that is not part of a block
1450 if ( ptr && ( indent == context->level ) )
1452 // Reset block processing
1453 if ( context->block_name )
1455 free( context->block_name );
1456 context->block_name = NULL;
1460 // Terminate the name and setup the value pointer
1464 char *comment = strchr( ptr, '#' );
1470 // Trim leading and trailing spaces from bare value
1474 // No value means a child
1475 if ( strcmp( ptr, "" ) == 0 )
1477 mlt_properties child = mlt_properties_new();
1478 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1479 mlt_properties_set_data( properties, name, child, 0,
1480 ( mlt_destructor )mlt_properties_close, NULL );
1481 mlt_deque_push_front( context->stack, child );
1487 // A dash indicates a sequence item
1488 if ( name[0] == '-' )
1490 mlt_properties child = mlt_properties_new();
1493 mlt_properties_set_lcnumeric( child, mlt_properties_get_lcnumeric( properties ) );
1494 snprintf( key, sizeof(key), "%d", context->index++ );
1495 mlt_properties_set_data( properties, key, child, 0,
1496 ( mlt_destructor )mlt_properties_close, NULL );
1497 mlt_deque_push_front( context->stack, child );
1500 context->level += ltrim( &name ) + 1;
1508 value = strdup( ptr );
1509 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1510 value[ strlen( value ) - 1 ] = 0;
1513 // Value is folded or unfolded block
1514 else if ( *ptr == '|' || *ptr == '>' )
1516 context->block = *ptr;
1517 context->block_name = strdup( name );
1518 context->block_indent = 0;
1519 value = strdup( "" );
1525 value = strdup( ptr );
1529 // A list of scalars
1530 else if ( name[0] == '-' )
1532 // Reset block processing
1533 if ( context->block_name )
1535 free( context->block_name );
1536 context->block_name = NULL;
1542 snprintf( key, sizeof(key), "%d", context->index++ );
1546 char *comment = strchr( ptr, '#' );
1550 // Trim leading and trailing spaces from bare value
1558 value = strdup( ptr );
1559 if ( value && value[ strlen( value ) - 1 ] == '\"' )
1560 value[ strlen( value ) - 1 ] = 0;
1563 // Value is folded or unfolded block
1564 else if ( *ptr == '|' || *ptr == '>' )
1566 context->block = *ptr;
1567 context->block_name = strdup( key );
1568 context->block_indent = 0;
1569 value = strdup( "" );
1575 value = strdup( ptr );
1579 name = name_ = strdup( key );
1583 else if ( context->block == '|' )
1585 if ( context->block_indent == 0 )
1586 context->block_indent = indent;
1587 if ( indent > context->block_indent )
1588 name = &name_[ context->block_indent ];
1590 char *old_value = mlt_properties_get( properties, context->block_name );
1591 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1592 strcpy( value, old_value );
1593 if ( strcmp( old_value, "" ) )
1594 strcat( value, "\n" );
1595 strcat( value, name );
1596 name = context->block_name;
1600 else if ( context->block == '>' )
1604 char *old_value = mlt_properties_get( properties, context->block_name );
1606 // Blank line (prepended with spaces) is new line
1607 if ( strcmp( name, "" ) == 0 )
1609 value = calloc( 1, strlen( old_value ) + 2 );
1610 strcat( value, old_value );
1611 strcat( value, "\n" );
1613 // Concatenate with space
1616 value = calloc( 1, strlen( old_value ) + strlen( name ) + 2 );
1617 strcat( value, old_value );
1618 if ( strcmp( old_value, "" ) && old_value[ strlen( old_value ) - 1 ] != '\n' )
1619 strcat( value, " " );
1620 strcat( value, name );
1622 name = context->block_name;
1627 value = strdup( "" );
1630 error = mlt_properties_set( properties, name, value );
1632 if ( !strcmp( name, "LC_NUMERIC" ) )
1633 mlt_properties_set_lcnumeric( properties, value );
1641 /** Parse a YAML Tiny file by name.
1643 * \public \memberof mlt_properties_s
1644 * \param filename the name of a text file containing YAML Tiny
1645 * \return a new properties list
1648 mlt_properties mlt_properties_parse_yaml( const char *filename )
1650 // Construct a standalone properties object
1651 mlt_properties self = mlt_properties_new( );
1656 FILE *file = fopen( filename, "r" );
1658 // Load contents of file
1663 char *ptemp = &temp[ 0 ];
1665 // Default to LC_NUMERIC = C
1666 mlt_properties_set_lcnumeric( self, "C" );
1669 yaml_parser context = calloc( 1, sizeof( struct yaml_parser_context ) );
1670 context->stack = mlt_deque_init();
1671 mlt_deque_push_front( context->stack, self );
1673 // Read each string from the file
1674 while( fgets( temp, 1024, file ) )
1676 // Check for end-of-stream
1677 if ( strncmp( ptemp, "...", 3 ) == 0 )
1681 temp[ strlen( temp ) - 1 ] = '\0';
1683 // Skip blank lines, comment lines, and document separator
1684 if ( strcmp( ptemp, "" ) && ptemp[ 0 ] != '#' && strncmp( ptemp, "---", 3 )
1685 && strncmp( ptemp, "%YAML", 5 ) && strncmp( ptemp, "% YAML", 6 ) )
1686 parse_yaml( context, temp );
1691 mlt_deque_close( context->stack );
1692 if ( context->block_name )
1693 free( context->block_name );
1698 // Return the pointer
1703 * YAML Tiny Serializer
1706 /** How many bytes to grow at a time */
1707 #define STRBUF_GROWTH (1024)
1709 /** \brief Private to mlt_properties_s, a self-growing buffer for building strings
1719 typedef struct strbuf_s *strbuf;
1721 /** Create a new string buffer
1723 * \private \memberof strbuf_s
1724 * \return a new string buffer
1727 static strbuf strbuf_new( )
1729 strbuf buffer = calloc( 1, sizeof( struct strbuf_s ) );
1730 buffer->size = STRBUF_GROWTH;
1731 buffer->string = calloc( 1, buffer->size );
1735 /** Destroy a string buffer
1737 * \private \memberof strbuf_s
1738 * \param buffer the string buffer to close
1741 static void strbuf_close( strbuf buffer )
1743 // We do not free buffer->string; strbuf user must save that pointer
1749 /** Format a string into a string buffer
1751 * A variable number of arguments follows the format string - one for each
1753 * \private \memberof strbuf_s
1754 * \param buffer the string buffer to write into
1755 * \param format a string that contains text and formatting instructions
1756 * \return the formatted string
1759 static char *strbuf_printf( strbuf buffer, const char *format, ... )
1761 while ( buffer->string )
1764 va_start( ap, format );
1765 size_t len = strlen( buffer->string );
1766 size_t remain = buffer->size - len - 1;
1767 int need = vsnprintf( buffer->string + len, remain, format, ap );
1769 if ( need > -1 && need < remain )
1771 buffer->string[ len ] = 0;
1772 buffer->size += need + STRBUF_GROWTH;
1773 buffer->string = realloc( buffer->string, buffer->size );
1775 return buffer->string;
1778 /** Indent a line of YAML Tiny.
1780 * \private \memberof strbuf_s
1781 * \param output a string buffer
1782 * \param indent the number of spaces to indent
1785 static inline void indent_yaml( strbuf output, int indent )
1788 for ( j = 0; j < indent; j++ )
1789 strbuf_printf( output, " " );
1792 /** Convert a line string into a YAML block literal.
1794 * \private \memberof strbuf_s
1795 * \param output a string buffer
1796 * \param value the string to format as a block literal
1797 * \param indent the number of spaces to indent
1800 static void output_yaml_block_literal( strbuf output, const char *value, int indent )
1802 char *v = strdup( value );
1804 char *eol = strchr( sol, '\n' );
1808 indent_yaml( output, indent );
1810 strbuf_printf( output, "%s\n", sol );
1812 eol = strchr( sol, '\n' );
1814 indent_yaml( output, indent );
1815 strbuf_printf( output, "%s\n", sol );
1818 /** Recursively serialize a properties list into a string buffer as YAML Tiny.
1820 * \private \memberof mlt_properties_s
1821 * \param self a properties list
1822 * \param output a string buffer to hold the serialized YAML Tiny
1823 * \param indent the number of spaces to indent (for recursion, initialize to 0)
1824 * \param is_parent_sequence Is this properties list really just a sequence (for recursion, initialize to 0)?
1827 static void serialise_yaml( mlt_properties self, strbuf output, int indent, int is_parent_sequence )
1829 property_list *list = self->local;
1832 for ( i = 0; i < list->count; i ++ )
1834 // This implementation assumes that all data elements are property lists.
1835 // Unfortunately, we do not have run time type identification.
1836 mlt_properties child = mlt_property_get_data( list->value[ i ], NULL );
1838 if ( mlt_properties_is_sequence( self ) )
1840 // Ignore hidden/non-serialisable items
1841 if ( list->name[ i ][ 0 ] != '_' )
1843 // Indicate a sequence item
1844 indent_yaml( output, indent );
1845 strbuf_printf( output, "- " );
1847 // If the value can be represented as a string
1848 const char *value = mlt_properties_get( self, list->name[ i ] );
1849 if ( value && strcmp( value, "" ) )
1851 // Determine if this is an unfolded block literal
1852 if ( strchr( value, '\n' ) )
1854 strbuf_printf( output, "|\n" );
1855 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( "|" ) );
1859 strbuf_printf( output, "%s\n", value );
1865 serialise_yaml( child, output, indent + 2, 1 );
1869 // Assume this is a normal map-oriented properties list
1870 const char *value = mlt_properties_get( self, list->name[ i ] );
1872 // Ignore hidden/non-serialisable items
1873 // If the value can be represented as a string
1874 if ( list->name[ i ][ 0 ] != '_' && value && strcmp( value, "" ) )
1876 if ( is_parent_sequence == 0 )
1877 indent_yaml( output, indent );
1879 is_parent_sequence = 0;
1881 // Determine if this is an unfolded block literal
1882 if ( strchr( value, '\n' ) )
1884 strbuf_printf( output, "%s: |\n", list->name[ i ] );
1885 output_yaml_block_literal( output, value, indent + strlen( list->name[ i ] ) + strlen( ": " ) );
1889 strbuf_printf( output, "%s: %s\n", list->name[ i ], value );
1893 // Output a child as a map item
1896 indent_yaml( output, indent );
1897 strbuf_printf( output, "%s:\n", list->name[ i ] );
1900 serialise_yaml( child, output, indent + 2, 0 );
1906 /** Serialize a properties list as a string of YAML Tiny.
1908 * The caller MUST free the returned string!
1909 * This operates on properties containing properties as a hierarchical data
1911 * \public \memberof mlt_properties_s
1912 * \param self a properties list
1913 * \return a string containing YAML Tiny that represents the properties list
1916 char *mlt_properties_serialise_yaml( mlt_properties self )
1918 const char *lc_numeric = mlt_properties_get_lcnumeric( self );
1919 strbuf b = strbuf_new();
1920 strbuf_printf( b, "---\n" );
1921 mlt_properties_set_lcnumeric( self, "C" );
1922 serialise_yaml( self, b, 0, 0 );
1923 mlt_properties_set_lcnumeric( self, lc_numeric );
1924 strbuf_printf( b, "...\n" );
1925 char *ret = b->string;
1930 /** Protect a properties list against concurrent access.
1932 * \public \memberof mlt_properties_s
1933 * \param self a properties list
1936 void mlt_properties_lock( mlt_properties self )
1939 pthread_mutex_lock( &( ( property_list* )( self->local ) )->mutex );
1942 /** End protecting a properties list against concurrent access.
1944 * \public \memberof mlt_properties_s
1945 * \param self a properties list
1948 void mlt_properties_unlock( mlt_properties self )
1951 pthread_mutex_unlock( &( ( property_list* )( self->local ) )->mutex );