]> git.sesse.net Git - mlt/blob - src/framework/mlt_properties.c
895be28a0abb846a7019621bcce440c517f83fc2
[mlt] / src / framework / mlt_properties.c
1 /*
2  * mlt_properties.c -- base properties class
3  * Copyright (C) 2003-2004 Ushodaya Enterprises Limited
4  * Author: Charles Yates <charles.yates@pandora.be>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program 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
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 #include "config.h"
22 #include "mlt_properties.h"
23 #include "mlt_property.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <ctype.h>
29
30 /* ---------------- // Private Implementation // ---------------- */
31
32 /** Private implementation of the property list.
33 */
34
35 typedef struct
36 {
37         int hash[ 199 ];
38         char **name;
39         mlt_property *value;
40         int count;
41         int size;
42         mlt_properties mirror;
43 }
44 property_list;
45
46 /** Memory leak checks.
47 */
48
49 #ifdef _MLT_PROPERTY_CHECKS_
50 static int properties_created = 0;
51 static int properties_destroyed = 0;
52 #endif
53
54 /** Basic implementation.
55 */
56
57 int mlt_properties_init( mlt_properties this, void *child )
58 {
59         if ( this != NULL )
60         {
61 #ifdef _MLT_PROPERTY_CHECKS_
62                 // Increment number of properties created
63                 properties_created ++;
64 #endif
65
66                 // NULL all methods
67                 memset( this, 0, sizeof( struct mlt_properties_s ) );
68
69                 // Assign the child of the object
70                 this->child = child;
71
72                 // Allocate the local structure
73                 this->local = calloc( sizeof( property_list ), 1 );
74         }
75
76         // Check that initialisation was successful
77         return this != NULL && this->local == NULL;
78 }
79
80 /** Constructor for stand alone object.
81 */
82
83 mlt_properties mlt_properties_new( )
84 {
85         // Construct a standalone properties object
86         mlt_properties this = calloc( sizeof( struct mlt_properties_s ), 1 );
87
88         // Initialise this
89         mlt_properties_init( this, NULL );
90
91         // Return the pointer
92         return this;
93 }
94
95 /** Load properties from a file.
96 */
97
98 mlt_properties mlt_properties_load( char *filename )
99 {
100         // Construct a standalone properties object
101         mlt_properties this = mlt_properties_new( );
102
103         if ( this != NULL )
104         {
105                 // Open the file
106                 FILE *file = fopen( filename, "r" );
107
108                 // Load contents of file
109                 if ( file != NULL )
110                 {
111                         // Temp string
112                         char temp[ 1024 ];
113
114                         // Read each string from the file
115                         while( fgets( temp, 1024, file ) )
116                         {
117                                 // Chomp the string
118                                 temp[ strlen( temp ) - 1 ] = '\0';
119
120                                 // Parse and set the property
121                                 if ( strcmp( temp, "" ) && temp[ 0 ] != '#' )
122                                         mlt_properties_parse( this, temp );
123                         }
124
125                         // Close the file
126                         fclose( file );
127                 }
128         }
129
130         // Return the pointer
131         return this;
132 }
133
134 static inline int generate_hash( char *name )
135 {
136         int hash = 0;
137         int i = 1;
138         while ( *name )
139                 hash = ( hash + ( i ++ * ( *name ++ & 31 ) ) ) % 199;
140         return hash;
141 }
142
143 /** Special case - when a container (such as fezzik) is protecting another 
144         producer, we need to ensure that properties are passed through to the
145         real producer.
146 */
147
148 static inline void mlt_properties_do_mirror( mlt_properties this, char *name )
149 {
150         property_list *list = this->local;
151         if ( list->mirror != NULL ) 
152         {
153                 char *value = mlt_properties_get( this, name );
154                 if ( value != NULL )
155                         mlt_properties_set( list->mirror, name, value );
156         }
157 }
158
159 /** Allow the specification of a mirror.
160 */
161
162 void mlt_properties_mirror( mlt_properties this, mlt_properties that )
163 {
164         property_list *list = this->local;
165         list->mirror = that;
166 }
167
168 /** Inherit all serialisable properties from that into this.
169 */
170
171 int mlt_properties_inherit( mlt_properties this, mlt_properties that )
172 {
173         int count = mlt_properties_count( that );
174         int i = 0;
175         for ( i = 0; i < count; i ++ )
176         {
177                 char *value = mlt_properties_get_value( that, i );
178                 if ( value != NULL )
179                 {
180                         char *name = mlt_properties_get_name( that, i );
181                         mlt_properties_set( this, name, value );
182                 }
183         }
184         return 0;
185 }
186
187 /** Pass all properties from 'that' that match the prefix to 'this' (excluding the prefix).
188 */
189
190 int mlt_properties_pass( mlt_properties this, mlt_properties that, char *prefix )
191 {
192         int count = mlt_properties_count( that );
193         int length = strlen( prefix );
194         int i = 0;
195         for ( i = 0; i < count; i ++ )
196         {
197                 char *name = mlt_properties_get_name( that, i );
198                 if ( !strncmp( name, prefix, length ) )
199                 {
200                         char *value = mlt_properties_get_value( that, i );
201                         if ( value != NULL )
202                                 mlt_properties_set( this, name + length, value );
203                 }
204         }
205         return 0;
206 }
207
208 /** Locate a property by name
209 */
210
211 static inline mlt_property mlt_properties_find( mlt_properties this, char *name )
212 {
213         property_list *list = this->local;
214         mlt_property value = NULL;
215         int key = generate_hash( name );
216         int i = list->hash[ key ] - 1;
217
218         if ( i >= 0 )
219         {
220                 // Check if we're hashed
221                 if ( list->count > 0 &&
222                         name[ 0 ] == list->name[ i ][ 0 ] && 
223                         !strcmp( list->name[ i ], name ) )
224                         value = list->value[ i ];
225
226                 // Locate the item 
227                 for ( i = list->count - 1; value == NULL && i >= 0; i -- )
228                         if ( name[ 0 ] == list->name[ i ][ 0 ] && !strcmp( list->name[ i ], name ) )
229                                 value = list->value[ i ];
230         }
231
232         return value;
233 }
234
235 /** Add a new property.
236 */
237
238 static mlt_property mlt_properties_add( mlt_properties this, char *name )
239 {
240         property_list *list = this->local;
241         int key = generate_hash( name );
242
243         // Check that we have space and resize if necessary
244         if ( list->count == list->size )
245         {
246                 list->size += 50;
247                 list->name = realloc( list->name, list->size * sizeof( char * ) );
248                 list->value = realloc( list->value, list->size * sizeof( mlt_property ) );
249         }
250
251         // Assign name/value pair
252         list->name[ list->count ] = strdup( name );
253         list->value[ list->count ] = mlt_property_init( );
254
255         // Assign to hash table
256         if ( list->hash[ key ] == 0 )
257                 list->hash[ key ] = list->count + 1;
258
259         // Return and increment count accordingly
260         return list->value[ list->count ++ ];
261 }
262
263 /** Fetch a property by name - this includes add if not found.
264 */
265
266 static mlt_property mlt_properties_fetch( mlt_properties this, char *name )
267 {
268         // Try to find an existing property first
269         mlt_property property = mlt_properties_find( this, name );
270
271         // If it wasn't found, create one
272         if ( property == NULL )
273                 property = mlt_properties_add( this, name );
274
275         // Return the property
276         return property;
277 }
278
279 /** Set the property.
280 */
281
282 int mlt_properties_set( mlt_properties this, char *name, char *value )
283 {
284         int error = 1;
285
286         // Fetch the property to work with
287         mlt_property property = mlt_properties_fetch( this, name );
288
289         // Set it if not NULL
290         if ( property != NULL && ( value == NULL || value[ 0 ] != '@' ) )
291         {
292                 error = mlt_property_set_string( property, value );
293                 mlt_properties_do_mirror( this, name );
294         }
295         else if ( property != NULL && value[ 0 ] == '@' )
296         {
297                 int total = 0;
298                 int current = 0;
299                 char id[ 255 ];
300                 char op = '+';
301
302                 value ++;
303
304                 while ( *value != '\0' )
305                 {
306                         int length = strcspn( value, "+-*/" );
307
308                         // Get the identifier
309                         strncpy( id, value, length );
310                         id[ length ] = '\0';
311                         value += length;
312
313                         // Determine the value
314                         if ( isdigit( id[ 0 ] ) )
315                                 current = atof( id );
316                         else
317                                 current = mlt_properties_get_int( this, id );
318
319                         // Apply the operation
320                         switch( op )
321                         {
322                                 case '+':
323                                         total += current;
324                                         break;
325                                 case '-':
326                                         total -= current;
327                                         break;
328                                 case '*':
329                                         total *= current;
330                                         break;
331                                 case '/':
332                                         total /= current;
333                                         break;
334                         }
335
336                         // Get the next op
337                         op = *value != '\0' ? *value ++ : ' ';
338                 }
339
340                 error = mlt_property_set_int( property, total );
341                 mlt_properties_do_mirror( this, name );
342         }
343
344         return error;
345 }
346
347 /** Set or default the property.
348 */
349
350 int mlt_properties_set_or_default( mlt_properties this, char *name, char *value, char *def )
351 {
352         return mlt_properties_set( this, name, value == NULL ? def : value );
353 }
354
355 /** Get a string value by name.
356 */
357
358 char *mlt_properties_get( mlt_properties this, char *name )
359 {
360         mlt_property value = mlt_properties_find( this, name );
361         return value == NULL ? NULL : mlt_property_get_string( value );
362 }
363
364 /** Get a name by index.
365 */
366
367 char *mlt_properties_get_name( mlt_properties this, int index )
368 {
369         property_list *list = this->local;
370         if ( index >= 0 && index < list->count )
371                 return list->name[ index ];
372         return NULL;
373 }
374
375 /** Get a string value by index.
376 */
377
378 char *mlt_properties_get_value( mlt_properties this, int index )
379 {
380         property_list *list = this->local;
381         if ( index >= 0 && index < list->count )
382                 return mlt_property_get_string( list->value[ index ] );
383         return NULL;
384 }
385
386 /** Get a data value by index.
387 */
388
389 void *mlt_properties_get_data_at( mlt_properties this, int index, int *size )
390 {
391         property_list *list = this->local;
392         if ( index >= 0 && index < list->count )
393                 return mlt_property_get_data( list->value[ index ], size );
394         return NULL;
395 }
396
397 /** Return the number of items in the list.
398 */
399
400 int mlt_properties_count( mlt_properties this )
401 {
402         property_list *list = this->local;
403         return list->count;
404 }
405
406 /** Set a value by parsing a name=value string
407 */
408
409 int mlt_properties_parse( mlt_properties this, char *namevalue )
410 {
411         char *name = strdup( namevalue );
412         char *value = NULL;
413         int error = 0;
414         char *ptr = strchr( name, '=' );
415
416         if ( ptr )
417         {
418                 *( ptr ++ ) = '\0';
419
420                 if ( *ptr != '\"' )
421                 {
422                         value = strdup( ptr );
423                 }
424                 else
425                 {
426                         ptr ++;
427                         value = strdup( ptr );
428                         if ( value != NULL && value[ strlen( value ) - 1 ] == '\"' )
429                                 value[ strlen( value ) - 1 ] = '\0';
430                 }
431         }
432         else
433         {
434                 value = strdup( "" );
435         }
436
437         error = mlt_properties_set( this, name, value );
438
439         free( name );
440         free( value );
441
442         return error;
443 }
444
445 /** Get a value associated to the name.
446 */
447
448 int mlt_properties_get_int( mlt_properties this, char *name )
449 {
450         mlt_property value = mlt_properties_find( this, name );
451         return value == NULL ? 0 : mlt_property_get_int( value );
452 }
453
454 /** Set a value associated to the name.
455 */
456
457 int mlt_properties_set_int( mlt_properties this, char *name, int value )
458 {
459         int error = 1;
460
461         // Fetch the property to work with
462         mlt_property property = mlt_properties_fetch( this, name );
463
464         // Set it if not NULL
465         if ( property != NULL )
466         {
467                 error = mlt_property_set_int( property, value );
468                 mlt_properties_do_mirror( this, name );
469         }
470
471         return error;
472 }
473
474 /** Get a value associated to the name.
475 */
476
477 double mlt_properties_get_double( mlt_properties this, char *name )
478 {
479         mlt_property value = mlt_properties_find( this, name );
480         return value == NULL ? 0 : mlt_property_get_double( value );
481 }
482
483 /** Set a value associated to the name.
484 */
485
486 int mlt_properties_set_double( mlt_properties this, char *name, double value )
487 {
488         int error = 1;
489
490         // Fetch the property to work with
491         mlt_property property = mlt_properties_fetch( this, name );
492
493         // Set it if not NULL
494         if ( property != NULL )
495         {
496                 error = mlt_property_set_double( property, value );
497                 mlt_properties_do_mirror( this, name );
498         }
499
500         return error;
501 }
502
503 /** Get a value associated to the name.
504 */
505
506 mlt_position mlt_properties_get_position( mlt_properties this, char *name )
507 {
508         mlt_property value = mlt_properties_find( this, name );
509         return value == NULL ? 0 : mlt_property_get_position( value );
510 }
511
512 /** Set a value associated to the name.
513 */
514
515 int mlt_properties_set_position( mlt_properties this, char *name, mlt_position value )
516 {
517         int error = 1;
518
519         // Fetch the property to work with
520         mlt_property property = mlt_properties_fetch( this, name );
521
522         // Set it if not NULL
523         if ( property != NULL )
524         {
525                 error = mlt_property_set_position( property, value );
526                 mlt_properties_do_mirror( this, name );
527         }
528
529         return error;
530 }
531
532 /** Get a value associated to the name.
533 */
534
535 void *mlt_properties_get_data( mlt_properties this, char *name, int *length )
536 {
537         mlt_property value = mlt_properties_find( this, name );
538         return value == NULL ? NULL : mlt_property_get_data( value, length );
539 }
540
541 /** Set a value associated to the name.
542 */
543
544 int mlt_properties_set_data( mlt_properties this, char *name, void *value, int length, mlt_destructor destroy, mlt_serialiser serialise )
545 {
546         int error = 1;
547
548         // Fetch the property to work with
549         mlt_property property = mlt_properties_fetch( this, name );
550
551         // Set it if not NULL
552         if ( property != NULL )
553                 error = mlt_property_set_data( property, value, length, destroy, serialise );
554
555         return error;
556 }
557
558 /** Rename a property.
559 */
560
561 int mlt_properties_rename( mlt_properties this, char *source, char *dest )
562 {
563         mlt_property value = mlt_properties_find( this, dest );
564
565         if ( value == NULL )
566         {
567                 property_list *list = this->local;
568                 int i = 0;
569
570                 // Locate the item 
571                 for ( i = 0; i < list->count; i ++ )
572                 {
573                         if ( !strcmp( list->name[ i ], source ) )
574                         {
575                                 free( list->name[ i ] );
576                                 list->name[ i ] = strdup( dest );
577                                 list->hash[ generate_hash( dest ) ] = i + 1;
578                                 break;
579                         }
580                 }
581         }
582
583         return value != NULL;
584 }
585
586 /** Dump the properties.
587 */
588
589 void mlt_properties_dump( mlt_properties this, FILE *output )
590 {
591         property_list *list = this->local;
592         int i = 0;
593         for ( i = 0; i < list->count; i ++ )
594                 if ( mlt_properties_get( this, list->name[ i ] ) != NULL )
595                         fprintf( output, "%s=%s\n", list->name[ i ], mlt_properties_get( this, list->name[ i ] ) );
596 }
597
598 /** Close the list.
599 */
600
601 void mlt_properties_close( mlt_properties this )
602 {
603         if ( this != NULL )
604         {
605                 property_list *list = this->local;
606                 int index = 0;
607
608                 // Clean up names and values
609                 for ( index = list->count - 1; index >= 0; index -- )
610                 {
611                         free( list->name[ index ] );
612                         mlt_property_close( list->value[ index ] );
613                 }
614
615                 // Clear up the list
616                 free( list->name );
617                 free( list->value );
618                 free( list );
619
620                 // Free this now if this has no child
621                 if ( this->child == NULL )
622                         free( this );
623
624 #ifdef _MLT_PROPERTY_CHECKS_
625                 // Increment destroyed count
626                 properties_destroyed ++;
627
628                 // Show current stats - these should match when the app is closed
629                 fprintf( stderr, "Created %d, destroyed %d\n", properties_created, properties_destroyed );
630 #endif
631         }
632 }
633