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