2 * mlt_properties.c -- base properties class
3 * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4 * Author: Charles Yates <charles.yates@pandora.be>
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "mlt_properties.h"
22 #include "mlt_property.h"
29 #include <sys/types.h>
32 /* ---------------- // Private Implementation // ---------------- */
34 /** Private implementation of the property list.
44 mlt_properties mirror;
49 /** Memory leak checks.
52 //#define _MLT_PROPERTY_CHECKS_ 2
54 #ifdef _MLT_PROPERTY_CHECKS_
55 static int properties_created = 0;
56 static int properties_destroyed = 0;
59 /** Basic implementation.
62 int mlt_properties_init( mlt_properties this, void *child )
66 #ifdef _MLT_PROPERTY_CHECKS_
67 // Increment number of properties created
68 properties_created ++;
72 memset( this, 0, sizeof( struct mlt_properties_s ) );
74 // Assign the child of the object
77 // Allocate the local structure
78 this->local = calloc( sizeof( property_list ), 1 );
80 // Increment the ref count
81 ( ( property_list * )this->local )->ref_count = 1;
84 // Check that initialisation was successful
85 return this != NULL && this->local == NULL;
88 /** Constructor for stand alone object.
91 mlt_properties mlt_properties_new( )
93 // Construct a standalone properties object
94 mlt_properties this = calloc( sizeof( struct mlt_properties_s ), 1 );
97 mlt_properties_init( this, NULL );
103 /** Load properties from a file.
106 mlt_properties mlt_properties_load( const char *filename )
108 // Construct a standalone properties object
109 mlt_properties this = mlt_properties_new( );
114 FILE *file = fopen( filename, "r" );
116 // Load contents of file
121 char last[ 1024 ] = "";
123 // Read each string from the file
124 while( fgets( temp, 1024, file ) )
127 temp[ strlen( temp ) - 1 ] = '\0';
129 // Check if the line starts with a .
130 if ( temp[ 0 ] == '.' )
133 sprintf( temp2, "%s%s", last, temp );
134 strcpy( temp, temp2 );
136 else if ( strchr( temp, '=' ) )
138 strcpy( last, temp );
139 *( strchr( last, '=' ) ) = '\0';
142 // Parse and set the property
143 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
144 mlt_properties_parse( this, temp );
152 // Return the pointer
156 static inline int generate_hash( const char *name )
161 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
165 /** Special case - when a container (such as fezzik) is protecting another
166 producer, we need to ensure that properties are passed through to the
170 static inline void mlt_properties_do_mirror( mlt_properties this, const char *name )
172 property_list *list = this->local;
173 if ( list->mirror != NULL )
175 char *value = mlt_properties_get( this, name );
177 mlt_properties_set( list->mirror, name, value );
181 /** Maintain ref count to allow multiple uses of an mlt object.
184 int mlt_properties_inc_ref( mlt_properties this )
188 property_list *list = this->local;
189 return ++ list->ref_count;
194 /** Maintain ref count to allow multiple uses of an mlt object.
197 int mlt_properties_dec_ref( mlt_properties this )
201 property_list *list = this->local;
202 return -- list->ref_count;
207 /** Return the ref count of this object.
210 int mlt_properties_ref_count( mlt_properties this )
214 property_list *list = this->local;
215 return list->ref_count;
220 /** Mirror properties set on 'this' to 'that'.
223 void mlt_properties_mirror( mlt_properties this, mlt_properties that )
225 property_list *list = this->local;
229 /** Inherit all serialisable properties from that into this.
232 int mlt_properties_inherit( mlt_properties this, mlt_properties that )
234 int count = mlt_properties_count( that );
236 for ( i = 0; i < count; i ++ )
238 char *value = mlt_properties_get_value( that, i );
241 char *name = mlt_properties_get_name( that, i );
242 mlt_properties_set( this, name, value );
248 /** Pass all properties from 'that' that match the prefix to 'this' (excluding the prefix).
251 int mlt_properties_pass( mlt_properties this, mlt_properties that, const char *prefix )
253 int count = mlt_properties_count( that );
254 int length = strlen( prefix );
256 for ( i = 0; i < count; i ++ )
258 char *name = mlt_properties_get_name( that, i );
259 if ( !strncmp( name, prefix, length ) )
261 char *value = mlt_properties_get_value( that, i );
263 mlt_properties_set( this, name + length, value );
269 /** Locate a property by name
272 static inline mlt_property mlt_properties_find( mlt_properties this, const char *name )
274 property_list *list = this->local;
275 mlt_property value = NULL;
276 int key = generate_hash( name );
277 int i = list->hash[ key ] - 1;
281 // Check if we're hashed
282 if ( list->count > 0 &&
283 name[ 0 ] == list->name[ i ][ 0 ] &&
284 !strcmp( list->name[ i ], name ) )
285 value = list->value[ i ];
288 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
289 if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
290 value = list->value[ i ];
296 /** Add a new property.
299 static mlt_property mlt_properties_add( mlt_properties this, const char *name )
301 property_list *list = this->local;
302 int key = generate_hash( name );
304 // Check that we have space and resize if necessary
305 if ( list->count == list->size )
308 list->name = realloc( list->name, list->size * sizeof( const char * ) );
309 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
312 // Assign name/value pair
313 list->name[ list->count ] = strdup( name );
314 list->value[ list->count ] = mlt_property_init( );
316 // Assign to hash table
317 if ( list->hash[ key ] == 0 )
318 list->hash[ key ] = list->count + 1;
320 // Return and increment count accordingly
321 return list->value[ list->count ++ ];
324 /** Fetch a property by name - this includes add if not found.
327 static mlt_property mlt_properties_fetch( mlt_properties this, const char *name )
329 // Try to find an existing property first
330 mlt_property property = mlt_properties_find( this, name );
332 // If it wasn't found, create one
333 if ( property == NULL )
334 property = mlt_properties_add( this, name );
336 // Return the property
340 /** Pass property 'name' from 'that' to 'this'
341 * Who to blame: Zach <zachary.drew@gmail.com>
344 void mlt_properties_pass_property( mlt_properties this, mlt_properties that, const char *name )
346 // Make sure the source property isn't null.
347 mlt_property that_prop = mlt_properties_find( that, name );
348 if( that_prop == NULL )
351 mlt_property_pass( mlt_properties_fetch( this, name ), that_prop );
354 /** Pass all properties from 'that' to 'this' as found in comma seperated 'list'.
355 * Who to blame: Zach <zachary.drew@gmail.com>
358 int mlt_properties_pass_list( mlt_properties this, mlt_properties that, const char *list )
360 char *props = strdup( list );
362 char *delim = " ,\t\n"; // Any combination of spaces, commas, tabs, and newlines
367 count = strcspn( ptr, delim );
369 if( ptr[count] == '\0' )
372 ptr[count] = '\0'; // Make it a real string
374 mlt_properties_pass_property( this, that, ptr );
377 ptr += strspn( ptr, delim );
386 /** Set the property.
389 int mlt_properties_set( mlt_properties this, const char *name, const char *value )
393 // Fetch the property to work with
394 mlt_property property = mlt_properties_fetch( this, name );
396 // Set it if not NULL
397 if ( property == NULL )
399 fprintf( stderr, "Whoops - %s not found (should never occur)\n", name );
401 else if ( value == NULL )
403 error = mlt_property_set_string( property, value );
404 mlt_properties_do_mirror( this, name );
406 else if ( *value != '@' )
408 error = mlt_property_set_string( property, value );
409 mlt_properties_do_mirror( this, name );
411 else if ( value[ 0 ] == '@' )
420 while ( *value != '\0' )
422 int length = strcspn( value, "+-*/" );
424 // Get the identifier
425 strncpy( id, value, length );
429 // Determine the value
430 if ( isdigit( id[ 0 ] ) )
431 current = atof( id );
433 current = mlt_properties_get_int( this, id );
435 // Apply the operation
453 op = *value != '\0' ? *value ++ : ' ';
456 error = mlt_property_set_int( property, total );
457 mlt_properties_do_mirror( this, name );
460 mlt_events_fire( this, "property-changed", name, NULL );
465 /** Set or default the property.
468 int mlt_properties_set_or_default( mlt_properties this, const char *name, const char *value, const char *def )
470 return mlt_properties_set( this, name, value == NULL ? def : value );
473 /** Get a string value by name.
476 char *mlt_properties_get( mlt_properties this, const char *name )
478 mlt_property value = mlt_properties_find( this, name );
479 return value == NULL ? NULL : mlt_property_get_string( value );
482 /** Get a name by index.
485 char *mlt_properties_get_name( mlt_properties this, int index )
487 property_list *list = this->local;
488 if ( index >= 0 && index < list->count )
489 return list->name[ index ];
493 /** Get a string value by index.
496 char *mlt_properties_get_value( mlt_properties this, int index )
498 property_list *list = this->local;
499 if ( index >= 0 && index < list->count )
500 return mlt_property_get_string( list->value[ index ] );
504 /** Get a data value by index.
507 void *mlt_properties_get_data_at( mlt_properties this, int index, int *size )
509 property_list *list = this->local;
510 if ( index >= 0 && index < list->count )
511 return mlt_property_get_data( list->value[ index ], size );
515 /** Return the number of items in the list.
518 int mlt_properties_count( mlt_properties this )
520 property_list *list = this->local;
524 /** Set a value by parsing a name=value string
527 int mlt_properties_parse( mlt_properties this, const char *namevalue )
529 char *name = strdup( namevalue );
532 char *ptr = strchr( name, '=' );
540 value = strdup( ptr );
545 value = strdup( ptr );
546 if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
547 value[ strlen( value ) - 1 ] = '\0';
552 value = strdup( "" );
555 error = mlt_properties_set( this, name, value );
563 /** Get a value associated to the name.
566 int mlt_properties_get_int( mlt_properties this, const char *name )
568 mlt_property value = mlt_properties_find( this, name );
569 return value == NULL ? 0 : mlt_property_get_int( value );
572 /** Set a value associated to the name.
575 int mlt_properties_set_int( mlt_properties this, const char *name, int value )
579 // Fetch the property to work with
580 mlt_property property = mlt_properties_fetch( this, name );
582 // Set it if not NULL
583 if ( property != NULL )
585 error = mlt_property_set_int( property, value );
586 mlt_properties_do_mirror( this, name );
589 mlt_events_fire( this, "property-changed", name, NULL );
594 /** Get a value associated to the name.
597 int64_t mlt_properties_get_int64( mlt_properties this, const char *name )
599 mlt_property value = mlt_properties_find( this, name );
600 return value == NULL ? 0 : mlt_property_get_int64( value );
603 /** Set a value associated to the name.
606 int mlt_properties_set_int64( mlt_properties this, const char *name, int64_t value )
610 // Fetch the property to work with
611 mlt_property property = mlt_properties_fetch( this, name );
613 // Set it if not NULL
614 if ( property != NULL )
616 error = mlt_property_set_int64( property, value );
617 mlt_properties_do_mirror( this, name );
620 mlt_events_fire( this, "property-changed", name, NULL );
625 /** Get a value associated to the name.
628 double mlt_properties_get_double( mlt_properties this, const char *name )
630 mlt_property value = mlt_properties_find( this, name );
631 return value == NULL ? 0 : mlt_property_get_double( value );
634 /** Set a value associated to the name.
637 int mlt_properties_set_double( mlt_properties this, const char *name, double value )
641 // Fetch the property to work with
642 mlt_property property = mlt_properties_fetch( this, name );
644 // Set it if not NULL
645 if ( property != NULL )
647 error = mlt_property_set_double( property, value );
648 mlt_properties_do_mirror( this, name );
651 mlt_events_fire( this, "property-changed", name, NULL );
656 /** Get a value associated to the name.
659 mlt_position mlt_properties_get_position( mlt_properties this, const char *name )
661 mlt_property value = mlt_properties_find( this, name );
662 return value == NULL ? 0 : mlt_property_get_position( value );
665 /** Set a value associated to the name.
668 int mlt_properties_set_position( mlt_properties this, const char *name, mlt_position value )
672 // Fetch the property to work with
673 mlt_property property = mlt_properties_fetch( this, name );
675 // Set it if not NULL
676 if ( property != NULL )
678 error = mlt_property_set_position( property, value );
679 mlt_properties_do_mirror( this, name );
682 mlt_events_fire( this, "property-changed", name, NULL );
687 /** Get a value associated to the name.
690 void *mlt_properties_get_data( mlt_properties this, const char *name, int *length )
692 mlt_property value = mlt_properties_find( this, name );
693 return value == NULL ? NULL : mlt_property_get_data( value, length );
696 /** Set a value associated to the name.
699 int mlt_properties_set_data( mlt_properties this, const char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
703 // Fetch the property to work with
704 mlt_property property = mlt_properties_fetch( this, name );
706 // Set it if not NULL
707 if ( property != NULL )
708 error = mlt_property_set_data( property, value, length, destroy, serialise );
710 mlt_events_fire( this, "property-changed", name, NULL );
715 /** Rename a property.
718 int mlt_properties_rename( mlt_properties this, const char *source, const char *dest )
720 mlt_property value = mlt_properties_find( this, dest );
724 property_list *list = this->local;
728 for ( i = 0; i < list->count; i ++ )
730 if ( !strcmp( list->name[ i ], source ) )
732 free( list->name[ i ] );
733 list->name[ i ] = strdup( dest );
734 list->hash[ generate_hash( dest ) ] = i + 1;
740 return value != NULL;
743 /** Dump the properties.
746 void mlt_properties_dump( mlt_properties this, FILE *output )
748 property_list *list = this->local;
750 for ( i = 0; i < list->count; i ++ )
751 if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
752 fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
755 void mlt_properties_debug( mlt_properties this, const char *title, FILE *output )
757 if ( output == NULL ) output = stderr;
758 fprintf( output, "%s: ", title );
761 property_list *list = this->local;
763 fprintf( output, "[ ref=%d", list->ref_count );
764 for ( i = 0; i < list->count; i ++ )
765 if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
766 fprintf( output, ", %s=%s", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
768 fprintf( output, ", %s=%p", list->name[ i ], mlt_properties_get_data( this, list->name[ i ], NULL ) );
769 fprintf( output, " ]" );
771 fprintf( output, "\n" );
774 int mlt_properties_save( mlt_properties this, const char *filename )
777 FILE *f = fopen( filename, "w" );
780 mlt_properties_dump( this, f );
787 /* This is a very basic cross platform fnmatch replacement - it will fail in
788 ** many cases, but for the basic *.XXX and YYY*.XXX, it will work ok.
791 static int mlt_fnmatch( const char *wild, const char *file )
796 while( f < strlen( file ) && w < strlen( wild ) )
798 if ( wild[ w ] == '*' )
801 if ( w == strlen( wild ) )
803 while ( f != strlen( file ) && tolower( file[ f ] ) != tolower( wild[ w ] ) )
806 else if ( wild[ w ] == '?' || tolower( file[ f ] ) == tolower( wild[ w ] ) )
811 else if ( wild[ 0 ] == '*' )
821 return strlen( file ) == f && strlen( wild ) == w;
824 static int mlt_compare( const void *this, const void *that )
826 return strcmp( mlt_property_get_string( *( mlt_property * )this ), mlt_property_get_string( *( mlt_property * )that ) );
829 /* Obtains an optionally sorted list of the files found in a directory with a specific wild card.
830 * Entries in the list have a numeric name (running from 0 to count - 1). Only values change
831 * position if sort is enabled. Designed to be posix compatible (linux, os/x, mingw etc).
834 int mlt_properties_dir_list( mlt_properties this, const char *dirname, const char *pattern, int sort )
836 DIR *dir = opendir( dirname );
841 struct dirent *de = readdir( dir );
842 char fullname[ 1024 ];
845 sprintf( key, "%d", mlt_properties_count( this ) );
846 snprintf( fullname, 1024, "%s/%s", dirname, de->d_name );
847 if ( de->d_name[ 0 ] != '.' && mlt_fnmatch( pattern, de->d_name ) )
848 mlt_properties_set( this, key, fullname );
855 if ( sort && mlt_properties_count( this ) )
857 property_list *list = this->local;
858 qsort( list->value, mlt_properties_count( this ), sizeof( mlt_property ), mlt_compare );
861 return mlt_properties_count( this );
867 void mlt_properties_close( mlt_properties this )
869 if ( this != NULL && mlt_properties_dec_ref( this ) <= 0 )
871 if ( this->close != NULL )
873 this->close( this->close_object );
877 property_list *list = this->local;
880 #if _MLT_PROPERTY_CHECKS_ == 1
882 mlt_properties_debug( this, "Closing", stderr );
885 #ifdef _MLT_PROPERTY_CHECKS_
886 // Increment destroyed count
887 properties_destroyed ++;
889 // Show current stats - these should match when the app is closed
890 fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
893 // Clean up names and values
894 for ( index = list->count - 1; index >= 0; index -- )
896 free( list->name[ index ] );
897 mlt_property_close( list->value[ index ] );
905 // Free this now if this has no child
906 if ( this->child == NULL )