]> git.sesse.net Git - mlt/blob - src/framework/mlt_property.c
d64592f2f090ebeb516c509db2a641cca4163aae
[mlt] / src / framework / mlt_property.c
1 /**
2  * \file mlt_property.c
3  * \brief Property class definition
4  *
5  * Copyright (C) 2003-2008 Ushodaya Enterprises Limited
6  * \author Charles Yates <charles.yates@pandora.be>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21  */
22
23 #include "mlt_property.h"
24
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28
29
30 /** Bit pattern used internally to indicated representations available.
31 */
32
33 typedef enum
34 {
35         mlt_prop_none = 0,    //!< not set
36         mlt_prop_int = 1,     //!< set as an integer
37         mlt_prop_string = 2,  //!< set as string or already converted to string
38         mlt_prop_position = 4,//!< set as a position
39         mlt_prop_double = 8,  //!< set as a floating point
40         mlt_prop_data = 16,   //!< set as opaque binary
41         mlt_prop_int64 = 32   //!< set as a 64-bit integer
42 }
43 mlt_property_type;
44
45 /** \brief Property class
46  *
47  * A property is like a variant or dynamic type. They are used for many things
48  * in MLT, but in particular they are the parameter mechanism for the plugins.
49  */
50
51 struct mlt_property_s
52 {
53         /// Stores a bit pattern of types available for this property
54         mlt_property_type types;
55
56         /// Atomic type handling
57         int prop_int;
58         mlt_position prop_position;
59         double prop_double;
60         int64_t prop_int64;
61
62         /// String handling
63         char *prop_string;
64
65         /// Generic type handling
66         void *data;
67         int length;
68         mlt_destructor destructor;
69         mlt_serialiser serialiser;
70 };
71
72 /** Construct a property and initialize it
73  * \public \memberof mlt_property_s
74  */
75
76 mlt_property mlt_property_init( )
77 {
78         mlt_property this = malloc( sizeof( struct mlt_property_s ) );
79         if ( this != NULL )
80         {
81                 this->types = 0;
82                 this->prop_int = 0;
83                 this->prop_position = 0;
84                 this->prop_double = 0;
85                 this->prop_int64 = 0;
86                 this->prop_string = NULL;
87                 this->data = NULL;
88                 this->length = 0;
89                 this->destructor = NULL;
90                 this->serialiser = NULL;
91         }
92         return this;
93 }
94
95 /** Clear (0/null) a property.
96  *
97  * Frees up any associated resources in the process.
98  * \private \memberof mlt_property_s
99  * \param this a property
100  */
101
102 static inline void mlt_property_clear( mlt_property this )
103 {
104         // Special case data handling
105         if ( this->types & mlt_prop_data && this->destructor != NULL )
106                 this->destructor( this->data );
107
108         // Special case string handling
109         if ( this->types & mlt_prop_string )
110                 free( this->prop_string );
111
112         // Wipe stuff
113         this->types = 0;
114         this->prop_int = 0;
115         this->prop_position = 0;
116         this->prop_double = 0;
117         this->prop_int64 = 0;
118         this->prop_string = NULL;
119         this->data = NULL;
120         this->length = 0;
121         this->destructor = NULL;
122         this->serialiser = NULL;
123 }
124
125 /** Set the property to an integer value.
126  *
127  * \public \memberof mlt_property_s
128  * \param this a property
129  * \param value an integer
130  * \return false
131  */
132
133 int mlt_property_set_int( mlt_property this, int value )
134 {
135         mlt_property_clear( this );
136         this->types = mlt_prop_int;
137         this->prop_int = value;
138         return 0;
139 }
140
141 /** Set the property to a floating point value.
142  *
143  * \public \memberof mlt_property_s
144  * \param this a property
145  * \param value a double precision floating point value
146  * \return false
147  */
148
149 int mlt_property_set_double( mlt_property this, double value )
150 {
151         mlt_property_clear( this );
152         this->types = mlt_prop_double;
153         this->prop_double = value;
154         return 0;
155 }
156
157 /** Set the property to a position value.
158  *
159  * Position is a relative time value in frame units.
160  * \public \memberof mlt_property_s
161  * \param this a property
162  * \param value a position value
163  * \return false
164  */
165
166 int mlt_property_set_position( mlt_property this, mlt_position value )
167 {
168         mlt_property_clear( this );
169         this->types = mlt_prop_position;
170         this->prop_position = value;
171         return 0;
172 }
173
174 /** Set the property to a string value.
175  *
176  * This makes a copy of the string you supply so you do not need to track
177  * a new reference to it.
178  * \public \memberof mlt_property_s
179  * \param this a property
180  * \param value the string to copy to the property
181  * \return true if it failed
182  */
183
184 int mlt_property_set_string( mlt_property this, const char *value )
185 {
186         if ( value != this->prop_string )
187         {
188                 mlt_property_clear( this );
189                 this->types = mlt_prop_string;
190                 if ( value != NULL )
191                         this->prop_string = strdup( value );
192         }
193         else
194         {
195                 this->types = mlt_prop_string;
196         }
197         return this->prop_string == NULL;
198 }
199
200 /** Set the property to a 64-bit integer value.
201  *
202  * \public \memberof mlt_property_s
203  * \param this a property
204  * \param value a 64-bit integer
205  * \return false
206  */
207
208 int mlt_property_set_int64( mlt_property this, int64_t value )
209 {
210         mlt_property_clear( this );
211         this->types = mlt_prop_int64;
212         this->prop_int64 = value;
213         return 0;
214 }
215
216 /** Set a property to an opaque binary value.
217  *
218  * This does not make a copy of the data. You can use a Properties object
219  * with its reference tracking and the destructor function to control
220  * the lifetime of the data. Otherwise, pass NULL for the destructor
221  * function and control the lifetime yourself.
222  * \public \memberof mlt_property_s
223  * \param this a property
224  * \param value an opaque pointer
225  * \param length the number of bytes pointed to by value (optional)
226  * \param destructor a function to use to destroy this binary data (optional, assuming you manage the resource)
227  * \param serialiser a function to use to convert this binary data to a string (optional)
228  * \return false
229  */
230
231 int mlt_property_set_data( mlt_property this, void *value, int length, mlt_destructor destructor, mlt_serialiser serialiser )
232 {
233         if ( this->data == value )
234                 this->destructor = NULL;
235         mlt_property_clear( this );
236         this->types = mlt_prop_data;
237         this->data = value;
238         this->length = length;
239         this->destructor = destructor;
240         this->serialiser = serialiser;
241         return 0;
242 }
243
244 /** Convert a base 10 or base 16 string to an integer.
245  *
246  * The string must begin with '0x' to be interpreted as hexadecimal.
247  * Otherwise, it is interpreted as base 10.
248  * \private \memberof mlt_property_s
249  * \param value a string to convert
250  * \return the resultant integer
251  */
252 static inline int mlt_property_atoi( const char *value )
253 {
254         if ( value == NULL )
255                 return 0;
256         else if ( value[0] == '0' && value[1] == 'x' )
257                 return strtol( value + 2, NULL, 16 );
258         else
259                 return strtol( value, NULL, 10 );
260 }
261
262 /** Get the property as an integer.
263  *
264  * \public \memberof mlt_property_s
265  * \param this a property
266  * \return an integer value
267  */
268
269 int mlt_property_get_int( mlt_property this )
270 {
271         if ( this->types & mlt_prop_int )
272                 return this->prop_int;
273         else if ( this->types & mlt_prop_double )
274                 return ( int )this->prop_double;
275         else if ( this->types & mlt_prop_position )
276                 return ( int )this->prop_position;
277         else if ( this->types & mlt_prop_int64 )
278                 return ( int )this->prop_int64;
279         else if ( this->types & mlt_prop_string )
280                 return mlt_property_atoi( this->prop_string );
281         return 0;
282 }
283
284 /** Get the property as a floating point.
285  *
286  * \public \memberof mlt_property_s
287  * \param this a property
288  * \return a floating point value
289  */
290
291 double mlt_property_get_double( mlt_property this )
292 {
293         if ( this->types & mlt_prop_double )
294                 return this->prop_double;
295         else if ( this->types & mlt_prop_int )
296                 return ( double )this->prop_int;
297         else if ( this->types & mlt_prop_position )
298                 return ( double )this->prop_position;
299         else if ( this->types & mlt_prop_int64 )
300                 return ( double )this->prop_int64;
301         else if ( this->types & mlt_prop_string )
302                 return atof( this->prop_string );
303         return 0;
304 }
305
306 /** Get the property as a position.
307  *
308  * A position is an offset time in terms of frame units.
309  * \public \memberof mlt_property_s
310  * \param this a property
311  * \return the position in frames
312  */
313
314 mlt_position mlt_property_get_position( mlt_property this )
315 {
316         if ( this->types & mlt_prop_position )
317                 return this->prop_position;
318         else if ( this->types & mlt_prop_int )
319                 return ( mlt_position )this->prop_int;
320         else if ( this->types & mlt_prop_double )
321                 return ( mlt_position )this->prop_double;
322         else if ( this->types & mlt_prop_int64 )
323                 return ( mlt_position )this->prop_int64;
324         else if ( this->types & mlt_prop_string )
325                 return ( mlt_position )atol( this->prop_string );
326         return 0;
327 }
328
329 /** Convert a string to a 64-bit integer.
330  *
331  * If the string begins with '0x' it is interpreted as a hexadecimal value.
332  * \private \memberof mlt_property_s
333  * \param value a string
334  * \return a 64-bit integer
335  */
336
337 static inline int64_t mlt_property_atoll( const char *value )
338 {
339         if ( value == NULL )
340                 return 0;
341         else if ( value[0] == '0' && value[1] == 'x' )
342                 return strtoll( value + 2, NULL, 16 );
343         else
344                 return strtoll( value, NULL, 10 );
345 }
346
347 /** Get the property as a signed integer.
348  *
349  * \public \memberof mlt_property_s
350  * \param this a property
351  * \return a 64-bit integer
352  */
353
354 int64_t mlt_property_get_int64( mlt_property this )
355 {
356         if ( this->types & mlt_prop_int64 )
357                 return this->prop_int64;
358         else if ( this->types & mlt_prop_int )
359                 return ( int64_t )this->prop_int;
360         else if ( this->types & mlt_prop_double )
361                 return ( int64_t )this->prop_double;
362         else if ( this->types & mlt_prop_position )
363                 return ( int64_t )this->prop_position;
364         else if ( this->types & mlt_prop_string )
365                 return mlt_property_atoll( this->prop_string );
366         return 0;
367 }
368
369 /** Get the property as a string.
370  *
371  * The caller is not responsible for deallocating the returned string!
372  * The string is deallocated when the Property is closed.
373  * This tries its hardest to convert the property to string including using
374  * a serialization function for binary data, if supplied.
375  * \public \memberof mlt_property_s
376  * \param this a property
377  * \return a string representation of the property or NULL if failed
378  */
379
380 char *mlt_property_get_string( mlt_property this )
381 {
382         // Construct a string if need be
383         if ( ! ( this->types & mlt_prop_string ) )
384         {
385                 if ( this->types & mlt_prop_int )
386                 {
387                         this->types |= mlt_prop_string;
388                         this->prop_string = malloc( 32 );
389                         sprintf( this->prop_string, "%d", this->prop_int );
390                 }
391                 else if ( this->types & mlt_prop_double )
392                 {
393                         this->types |= mlt_prop_string;
394                         this->prop_string = malloc( 32 );
395                         sprintf( this->prop_string, "%f", this->prop_double );
396                 }
397                 else if ( this->types & mlt_prop_position )
398                 {
399                         this->types |= mlt_prop_string;
400                         this->prop_string = malloc( 32 );
401                         sprintf( this->prop_string, "%d", (int)this->prop_position ); /* I don't know if this is wanted. -Zach */
402                 }
403                 else if ( this->types & mlt_prop_int64 )
404                 {
405                         this->types |= mlt_prop_string;
406                         this->prop_string = malloc( 32 );
407                         sprintf( this->prop_string, "%lld", this->prop_int64 );
408                 }
409                 else if ( this->types & mlt_prop_data && this->serialiser != NULL )
410                 {
411                         this->types |= mlt_prop_string;
412                         this->prop_string = this->serialiser( this->data, this->length );
413                 }
414         }
415
416         // Return the string (may be NULL)
417         return this->prop_string;
418 }
419
420 /** Get the binary data from a property.
421  *
422  * This only works if you previously put binary data into the property.
423  * This does not return a copy of the data; it returns a pointer to it.
424  * If you supplied a destructor function when setting the binary data,
425  * the destructor is used when the Property is closed to free the memory.
426  * Therefore, only free the returned pointer if you did not supply a
427  * destructor function.
428  * \public \memberof mlt_property_s
429  * \param this a property
430  * \param[out] length the size of the binary object in bytes
431  * \return an opaque data pointer or NULL if not available
432  */
433
434 void *mlt_property_get_data( mlt_property this, int *length )
435 {
436         // Assign length if not NULL
437         if ( length != NULL )
438                 *length = this->length;
439
440         // Return the data (note: there is no conversion here)
441         return this->data;
442 }
443
444 /** Destroy a property and free all related resources.
445  *
446  * \public \memberof mlt_property_s
447  * \param this a property
448  */
449
450 void mlt_property_close( mlt_property this )
451 {
452         mlt_property_clear( this );
453         free( this );
454 }
455
456 /** Copy a property.
457  *
458  * A Property holding binary data only copies the data if a serialiser
459  * function was supplied when you set the Property.
460  * \public \memberof mlt_property_s
461  * \author Zach <zachary.drew@gmail.com>
462  * \param this a property
463  * \param that another property
464  */
465 void mlt_property_pass( mlt_property this, mlt_property that )
466 {
467         mlt_property_clear( this );
468
469         this->types = that->types;
470
471         if ( this->types & mlt_prop_int64 )
472                 this->prop_int64 = that->prop_int64;
473         else if ( this->types & mlt_prop_int )
474                 this->prop_int = that->prop_int;
475         else if ( this->types & mlt_prop_double )
476                 this->prop_double = that->prop_double;
477         else if ( this->types & mlt_prop_position )
478                 this->prop_position = that->prop_position;
479         else if ( this->types & mlt_prop_string )
480         {
481                 if ( that->prop_string != NULL )
482                         this->prop_string = strdup( that->prop_string );
483         }
484         else if ( this->types & mlt_prop_data && this->serialiser != NULL )
485         {
486                 this->types = mlt_prop_string;
487                 this->prop_string = this->serialiser( this->data, this->length );
488         }
489 }