Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/openal-0.0.8/src/al_ext.c @ 17

Last change on this file since 17 was 17, checked in by landauf, 16 years ago

added openal

File size: 20.5 KB
Line 
1/* -*- mode: C; tab-width:8; c-basic-offset:8 -*-
2 * vi:set ts=8:
3 *
4 * al_ext.c
5 *
6 * Defines the mojo for built-in or dlopened extensions.
7 */
8#include "al_siteconfig.h"
9
10#include <AL/al.h>
11#include <AL/alc.h>
12#include <AL/alext.h>
13#include <stdlib.h>
14#include <string.h>
15#include <stdio.h>
16
17#include "al_main.h"
18#include "al_types.h"
19#include "al_ext.h"
20#include "al_error.h"
21#include "al_debug.h"
22
23#include "al_mutexlib.h"
24
25#ifndef NODLOPEN
26#include <dlfcn.h>
27#endif
28
29/*
30 * Maximum length of an extension function name.
31 */
32#define _AL_EXT_NAMELEN 240
33
34/*
35 * Maximum number of plugins supported
36 */
37#define MAX_EXT_LIBS 64
38
39/* locking macros */
40#define _alUnlockExtension() FL_alUnlockExtension(__FILE__, __LINE__)
41#define _alLockExtension()   FL_alLockExtension(__FILE__, __LINE__)
42
43/*
44 * FL_alLockExtension( const char *fn, int ln )
45 *
46 * Lock mutex guarding extension data structures, passing fn and ln to
47 * _alLockPrintf.
48 */
49static void FL_alLockExtension( const char *fn, int ln );
50
51/*
52 * FL_alUnlockExtension( const char *fn, int ln )
53 *
54 * Unlock mutex guarding extension data structures, passing fn and ln to
55 * _alLockPrintf.
56 */
57static void FL_alUnlockExtension( const char *fn, int ln );
58
59/* data structure storing extension library fini functions */
60static struct {
61        void (*pool[MAX_EXT_LIBS])(void);
62        int index;
63} FiniFunc;
64
65/* data structure storing extension functions.  Simple binary tree. */
66typedef struct _enode_t {
67        ALubyte name[ _AL_EXT_NAMELEN + 1 ];
68        AL_funcPtr addr;
69
70        struct _enode_t *left;
71        struct _enode_t *right;
72} enode_t;
73
74/*
75 * etree is the base for our function registry.
76 */
77static enode_t *etree    = NULL;
78
79/*
80 * ext_mutex is the mutex guarding extension data structures.
81 */
82static MutexID ext_mutex = NULL;
83
84/*
85 * Adds a new node to treenode, with name name and address addr.  Returns
86 * treenode.
87 */
88static enode_t *add_node( enode_t *treenode, const ALubyte *name, AL_funcPtr addr );
89
90/*
91 * Returns the node that exists in treenode with a matching name, or NULL if
92 * no such node exists.
93 */
94static enode_t *get_node( enode_t *treenode, const ALchar *name );
95
96/*
97 * _alDestroyExtension( void *extp )
98 *
99 * Finalizes a enode_t, but not it's children.
100 */
101static void _alDestroyExtension( void *extp );
102
103/*
104 * tree_free( enode_t *treehead, void (*ff)(void *) )
105 *
106 * Finalize an entire enode tree.
107 */
108static void tree_free( enode_t *treehead, void (*ff)(void *) );
109
110/*
111 * Allocate and return a new extension node.
112 */
113static enode_t *new_ext( const ALubyte *name, AL_funcPtr addr );
114
115#ifndef NODLOPEN
116/* following functions unneeded in we don't have dlopen */
117
118/*
119 * _alExtPushFiniFunc( void (*func)(void) )
120 *
121 * Pushes a func on the fini stack, so that fini functions can be called on
122 * exit or unload.
123 */
124static void _alExtPushFiniFunc( void (*func)(void) );
125
126#endif /* NODLOPEN */
127
128/*
129 * On the level of the specification, "Extension" is a
130 * group of functions and/or tokens that express a particular
131 * extended functionality of the API.
132 *
133 * In terms of this implementation 'Extension' refers
134 * to particular function that is registered in the
135 * dictionary for fast GetProcAddress(). A simple dlsym()
136 * is not possible because of the Linux implementation's
137 * dynamic plugin system.
138 *
139 * Also in terms of the implementation, 'Extension Group'
140 * refers to an extension in the specification sense--a name
141 * that surrounds a group of functions and/or tokens. It
142 * is possible to use a simple linked list for this, and
143 * IsExtensionPresent() simply traverses this list.
144 */
145
146#define _AL_EXT_GROUPLEN 256
147
148typedef struct _egroup_node_t {
149        ALubyte name[_AL_EXT_GROUPLEN+1];
150        struct _egroup_node_t* next;
151} egroup_node_t;
152
153/* linked list of exciting extension group names */
154static egroup_node_t* egroup_list = NULL;
155
156/*
157 * Returns TRUE is gname is a supported extension, FALSE otherwise.
158 */
159ALboolean alIsExtensionPresent( const ALchar* gname ) {
160        egroup_node_t* group = egroup_list;
161
162        while( group ) {
163
164                if( strncmp( (const char*) group->name,
165                             (const char*) gname,
166                             _AL_EXT_GROUPLEN ) == 0 ) {
167                        return AL_TRUE;
168                }
169
170                group = group->next;
171        }
172
173        return AL_FALSE;
174}
175
176/*
177 * Populate buffer, up to size-1, with a string representation of the
178 * extension strings.  Returns AL_TRUE if size was greater or equal to 1,
179 * AL_FALSE otherwise.
180 */
181ALboolean _alGetExtensionStrings( ALchar* buffer, size_t size ) {
182        egroup_node_t *group = egroup_list;
183
184        if( size < 1 ) {
185                return AL_FALSE;
186        }
187
188        buffer[0] = '\0';
189
190        while( group ) {
191                size_t length = strlen( (char *) group->name ) + 1;
192
193                if( length < size ) {
194                        strncat( (char *) buffer, (char *) group->name, size );
195                        strncat( (char *) buffer, " ", size - length + 1 );
196                } else {
197                        break;
198                }
199
200                size -= length;
201                group = group->next;
202        }
203
204        return AL_TRUE;
205}
206
207/*
208 * Add an extension group (see above) to the current list of extensions,
209 * returning AL_TRUE.  AL_FALSE is returned on error.
210 */
211ALboolean _alRegisterExtensionGroup( const ALubyte* gname ) {
212        egroup_node_t* group;
213
214        if( gname == NULL ) {
215                return AL_FALSE;
216        }
217
218        group = (egroup_node_t*) malloc( sizeof( *group ) );
219
220        if( group == NULL ) {
221                return AL_FALSE;
222        }
223
224        strncpy( (char*) group->name, (const char*) gname, _AL_EXT_GROUPLEN );
225        group->next = egroup_list;
226        egroup_list = group;
227
228        return AL_TRUE;
229}
230
231/*
232 * _alDestroyExtensionGroups( void )
233 *
234 * Finalize the extension group data structures.
235 */
236void _alDestroyExtensionGroups( void ) {
237        egroup_node_t *group = egroup_list;
238
239        while( group ) {
240                egroup_node_t *temp = group->next;
241                free( group );
242                group = temp;
243        }
244
245        egroup_list = NULL;
246
247        return;
248}
249
250/**
251 * Extension support.
252 */
253
254#define DEFINE_AL_PROC(p) { #p, (AL_funcPtr)p }
255
256typedef struct
257{
258        const ALchar *name;
259        AL_funcPtr value;
260} funcNameAddressPair;
261
262funcNameAddressPair alProcs[] = {
263        /* this has to be sorted! */
264        DEFINE_AL_PROC(alBuffer3f),
265        DEFINE_AL_PROC(alBuffer3i),
266        DEFINE_AL_PROC(alBufferData),
267        DEFINE_AL_PROC(alBufferf),
268        DEFINE_AL_PROC(alBufferfv),
269        DEFINE_AL_PROC(alBufferi),
270        DEFINE_AL_PROC(alBufferiv),
271        DEFINE_AL_PROC(alDeleteBuffers),
272        DEFINE_AL_PROC(alDeleteSources),
273        DEFINE_AL_PROC(alDisable),
274        DEFINE_AL_PROC(alDistanceModel),
275        DEFINE_AL_PROC(alDopplerFactor),
276        DEFINE_AL_PROC(alDopplerVelocity),
277        DEFINE_AL_PROC(alEnable),
278        DEFINE_AL_PROC(alGenBuffers),
279        DEFINE_AL_PROC(alGenSources),
280        DEFINE_AL_PROC(alGetBoolean),
281        DEFINE_AL_PROC(alGetBooleanv),
282        DEFINE_AL_PROC(alGetBuffer3f),
283        DEFINE_AL_PROC(alGetBuffer3i),
284        DEFINE_AL_PROC(alGetBufferf),
285        DEFINE_AL_PROC(alGetBufferfv),
286        DEFINE_AL_PROC(alGetBufferi),
287        DEFINE_AL_PROC(alGetBufferiv),
288        DEFINE_AL_PROC(alGetDouble),
289        DEFINE_AL_PROC(alGetDoublev),
290        DEFINE_AL_PROC(alGetEnumValue),
291        DEFINE_AL_PROC(alGetError),
292        DEFINE_AL_PROC(alGetFloat),
293        DEFINE_AL_PROC(alGetFloatv),
294        DEFINE_AL_PROC(alGetInteger),
295        DEFINE_AL_PROC(alGetIntegerv),
296        DEFINE_AL_PROC(alGetListener3f),
297        DEFINE_AL_PROC(alGetListener3i),
298        DEFINE_AL_PROC(alGetListenerf),
299        DEFINE_AL_PROC(alGetListenerfv),
300        DEFINE_AL_PROC(alGetListeneri),
301        DEFINE_AL_PROC(alGetListeneriv),
302        DEFINE_AL_PROC(alGetProcAddress),
303        DEFINE_AL_PROC(alGetSource3f),
304        /* DEFINE_AL_PROC(alGetSource3i), TODO: NOT YET IMPLEMENTED!!! */
305        DEFINE_AL_PROC(alGetSourcef),
306        DEFINE_AL_PROC(alGetSourcefv),
307        DEFINE_AL_PROC(alGetSourcei),
308        DEFINE_AL_PROC(alGetSourceiv),
309        DEFINE_AL_PROC(alGetString),
310        DEFINE_AL_PROC(alIsBuffer),
311        DEFINE_AL_PROC(alIsEnabled),
312        DEFINE_AL_PROC(alIsExtensionPresent),
313        DEFINE_AL_PROC(alIsSource),
314        DEFINE_AL_PROC(alListener3f),
315        DEFINE_AL_PROC(alListener3i),
316        DEFINE_AL_PROC(alListenerf),
317        DEFINE_AL_PROC(alListenerfv),
318        DEFINE_AL_PROC(alListeneri),
319        DEFINE_AL_PROC(alListeneriv),
320        DEFINE_AL_PROC(alSource3f),
321        /* DEFINE_AL_PROC(alSource3i), TODO: NOT YET IMPLEMENTED!!! */
322        DEFINE_AL_PROC(alSourcePause),
323        DEFINE_AL_PROC(alSourcePausev),
324        DEFINE_AL_PROC(alSourcePlay),
325        DEFINE_AL_PROC(alSourcePlayv),
326        DEFINE_AL_PROC(alSourceQueueBuffers),
327        DEFINE_AL_PROC(alSourceRewind),
328        DEFINE_AL_PROC(alSourceRewindv),
329        DEFINE_AL_PROC(alSourceStop),
330        DEFINE_AL_PROC(alSourceStopv),
331        DEFINE_AL_PROC(alSourceUnqueueBuffers),
332        DEFINE_AL_PROC(alSourcef),
333        DEFINE_AL_PROC(alSourcefv),
334        DEFINE_AL_PROC(alSourcei),
335        /* DEFINE_AL_PROC(alSourceiv), TODO: NOT YET IMPLEMENTED!!! */
336        DEFINE_AL_PROC(alSpeedOfSound)
337};
338
339#undef DEFINE_AL_PROC
340
341static int
342compareFuncNameAddressPairs(const void *s1, const void *s2)
343{
344        const funcNameAddressPair *p1 = (const funcNameAddressPair*)s1;
345        const funcNameAddressPair *p2 = (const funcNameAddressPair*)s2;
346        return strcmp((const char*)(p1->name), (const char*)(p2->name));
347}
348
349static ALboolean
350getStandardProcAddress(AL_funcPtr *value, const ALchar *funcName)
351{
352        funcNameAddressPair key;
353        funcNameAddressPair *p;
354        key.name = funcName;
355        p = bsearch(&key, alProcs,
356                    sizeof(alProcs) / sizeof(alProcs[0]),
357                    sizeof(alProcs[0]),
358                    compareFuncNameAddressPairs);
359        if (p == NULL) {
360                return AL_FALSE;
361        }
362        *value = p->value;
363        return AL_TRUE;
364}
365
366/* TODO: exporting this is a HACK */
367ALboolean
368_alGetExtensionProcAddress( AL_funcPtr *procAddress, const ALchar *funcName )
369{
370        enode_t *retpair;
371        retpair = get_node( etree, funcName );
372        if(retpair == NULL) {
373                return AL_FALSE;
374        }
375        *procAddress = retpair->addr;
376        return AL_TRUE;
377}
378
379/*
380 * alGetProcAddress( const ALubyte *fname )
381 *
382 * Obtain the address of a function (usually an extension) with the name
383 * fname. All addresses are context-independent.
384 */
385void *
386alGetProcAddress( const ALchar *funcName )
387{
388        AL_funcPtr value = NULL;
389        if (getStandardProcAddress(&value, funcName) == AL_TRUE) {
390                return (void *)value; /* NOTE: The cast is not valid ISO C! */
391        }
392        if (_alGetExtensionProcAddress(&value, funcName) == AL_TRUE) {
393                return (void *)value; /* NOTE: The cast is not valid ISO C! */
394        }
395        _alDCSetError( AL_INVALID_VALUE );
396        return (void *)value; /* NOTE: The cast is not valid ISO C! */
397}
398
399
400/*
401 * _alRegisterExtension is called to register an extension in our tree.
402 * extensions are not via GetProcAddress until they have been registered.
403 *
404 * Returns AL_TRUE if the name/addr pair was added, AL_FALSE otherwise.
405 */
406ALboolean _alRegisterExtension( const ALubyte *name, AL_funcPtr addr ) {
407        enode_t *temp;
408
409        _alLockExtension();
410
411        temp = add_node( etree, name, addr );
412        if(temp == NULL) {
413                _alUnlockExtension();
414                _alDebug(ALD_EXT, __FILE__, __LINE__,
415                        "could not add extension %s", name);
416                return AL_FALSE;
417        }
418
419        _alUnlockExtension();
420        etree = temp;
421
422        _alDebug(ALD_EXT, __FILE__, __LINE__,
423                 "registered %s at %p", name, (void*)addr);
424
425        return AL_TRUE;
426}
427
428/*
429 * _alDestroyExtension( void *extp )
430 *
431 * Finalizes a enode_t, but not it's children.
432 */
433static void _alDestroyExtension(void *extp) {
434        free( extp );
435
436        return;
437}
438
439/*
440 * _alInitExtensions( void )
441 *
442 * Initializes extension bookkeeping data structures.
443 *
444 * Not much to do here, since the structures are built via the register calls.
445 * So just init the mutex.  Return AL_TRUE unless the mutex could not be
446 * initialized.
447 */
448ALboolean _alInitExtensions( void ) {
449        if(ext_mutex == NULL) {
450                ext_mutex = _alCreateMutex();
451                if(ext_mutex == NULL) {
452                        return AL_FALSE;
453                }
454        }
455
456        return AL_TRUE;
457}
458
459/*
460 * _alDestroyExtensions( void )
461 *
462 * Destroy extension book keeping structures.
463 */
464void _alDestroyExtensions( void ) {
465        int i;
466
467        tree_free( etree, _alDestroyExtension );
468        _alDestroyMutex( ext_mutex );
469
470        etree     = NULL;
471        ext_mutex = NULL;
472
473        for(i = FiniFunc.index - 1; i >= 0; i--) {
474                FiniFunc.pool[i](); /* call fini funcs */
475                FiniFunc.index--;
476        }
477
478        return;
479}
480
481/*
482 * Adds a function with name "name" and address "addr" to the tree with root
483 * at treehead.
484 *
485 * assumes locked extensions
486 */
487static enode_t *add_node( enode_t *treehead, const ALubyte *name, AL_funcPtr addr ) {
488        int i;
489        enode_t *retval;
490
491        if((addr == NULL) || (name == NULL)) {
492                return NULL;
493        }
494
495        if(treehead == NULL) {
496                retval = new_ext( name, addr );
497                if(retval == NULL) {
498                        return NULL;
499                }
500
501                return retval;
502        }
503
504        i = ustrncmp( name, treehead->name, _AL_EXT_NAMELEN );
505
506        if(i < 0) {
507                treehead->left = add_node( treehead->left, name, addr );
508        }
509        if(i == 0) {
510                return treehead;
511        }
512        if(i > 0) {
513                treehead->right = add_node( treehead->right, name, addr );
514        }
515
516        return treehead;
517}
518
519/*
520 * Returns a new extension node, using name and addr as initializers, or NULL
521 * if resources were not available.
522 */
523static enode_t *new_ext( const ALubyte *name, AL_funcPtr addr ) {
524        enode_t *retval = malloc( sizeof *retval );
525        if(retval == NULL) {
526                return NULL;
527        }
528
529        ustrncpy( retval->name, name, _AL_EXT_NAMELEN );
530        retval->addr  = addr;
531        retval->left  = NULL;
532        retval->right = NULL;
533
534        return retval;
535}
536
537/*
538 * tree_free( enode_t *treehead, void (*ff)(void *) )
539 *
540 * Destroy the tree with root at treehead, calling ff on each data item.
541 */
542static void tree_free( enode_t *treehead, void (*ff)(void *) ) {
543        enode_t *temp;
544
545        if(treehead == NULL) {
546                return;
547        }
548
549        if(treehead->left) {
550                tree_free( treehead->left, ff );
551        }
552
553        temp = treehead->right;
554        free( treehead );
555
556        tree_free( temp, ff );
557
558        return;
559}
560
561/*
562 * Retrieve enode_t pointer for extension with name "name" from
563 * tree with root "treehead", or NULL if not found.
564 */
565static enode_t *get_node( enode_t *treehead, const ALchar *name ) {
566        int i;
567
568        if((name == NULL) || (treehead == NULL)) {
569                return NULL;
570        }
571
572        i = ustrncmp(name, treehead->name, _AL_EXT_NAMELEN);
573        if(i < 0) {
574                return get_node(treehead->left, name);
575        }
576        if(i > 0) {
577                return get_node(treehead->right, name);
578        }
579
580        return treehead;
581}
582
583#ifdef NODLOPEN
584
585ALboolean _alLoadDL(UNUSED(const char *fname)) {
586        return AL_FALSE;
587}
588
589#else
590
591/*
592 * _alLoadDL( const char *fname )
593 *
594 * Load the plugin named by fname, returning AL_TRUE on sucess, AL_FALSE on
595 * error.
596 *
597 *  FIXME: some sort of locking is in order.
598 *
599 *  FIXME: stick the fini_func function somewhere so we
600 *         can actually call it.
601 */
602ALboolean _alLoadDL( const char *fname ) {
603        void *handle;
604        AL_extension *ext_table;
605        static void (*init_func)( void );
606        static void (*fini_func)( void );
607        int i;
608
609        handle = dlopen( fname, RTLD_GLOBAL | RTLD_NOW );
610        if(handle == NULL) {
611                _alDebug(ALD_EXT, __FILE__, __LINE__,
612                        "Could not load %s:\n\t%s", fname, dlerror());
613                return AL_FALSE;
614        }
615
616        ext_table = dlsym(handle, LAL_EXT_TABLE_STR);
617        if(ext_table == NULL) {
618                _alDebug(ALD_EXT, __FILE__, __LINE__,
619                        "%s has no extension table.", fname);
620                return AL_FALSE;
621        }
622
623        init_func = (void (*)(void)) dlsym(handle, LAL_EXT_INIT_STR);
624        fini_func = (void (*)(void)) dlsym(handle, LAL_EXT_FINI_STR);
625
626        for( i = 0; (ext_table[i].name != NULL) &&
627                    (ext_table[i].addr != NULL); i++) {
628                _alRegisterExtension( ext_table[i].name, ext_table[i].addr );
629        }
630
631        if(init_func != NULL) {
632                /* initialize library */
633                init_func();
634        }
635
636        if(fini_func != NULL) {
637                _alExtPushFiniFunc( fini_func );
638        }
639
640        return AL_TRUE;
641}
642#endif
643
644/*
645 * lal_addTimeFilter( const char *name, time_filter *addr )
646 *
647 * Adds or replaces a time filter in the filter pipeline.  Returns AL_TRUE on
648 * success, AL_FALSE on error.
649 *
650 *  Not super-well tested.
651 *
652 *  FIXME: set error?  Probably not.
653 */
654ALboolean lal_addTimeFilter( const char *name, time_filter *addr ) {
655        AL_context *cc;
656        time_filter_set *tfs;
657        int i;
658        int scmp;
659
660        /* check args */
661        if((name == NULL) || (addr == NULL)) {
662                return AL_FALSE;
663        }
664
665        _alcDCLockContext();
666
667        cc = _alcDCGetContext();
668        if(cc == NULL) {
669                _alcDCUnlockContext();
670                return AL_FALSE;
671        }
672
673        tfs = cc->time_filters;
674
675        for(i = 0; (i < _ALC_MAX_FILTERS) && (tfs->filter != NULL); i++) {
676                scmp = strncmp(tfs[i].name, name, _ALF_MAX_NAME);
677                if(scmp == 0) {
678                        /* overwrite existing filter */
679                        tfs[i].filter = addr;
680
681                        _alcDCUnlockContext();
682                        return AL_TRUE;
683                }
684        }
685
686        if(i == _ALC_MAX_FILTERS) {
687                /* no room for new filter */
688                _alcDCUnlockContext();
689
690                return AL_FALSE;
691        }
692
693        /* add new filter */
694        strncpy(tfs[i].name, name, _ALF_MAX_NAME);
695        tfs[i].filter = addr;
696
697        _alcDCUnlockContext();
698
699        return AL_TRUE;
700}
701
702/*
703 * FL_alLockExtension( const char *fn, int ln )
704 *
705 * Lock mutex guarding extension data structures, passing fn and ln to
706 * _alLockPrintf.
707 */
708static void FL_alLockExtension(UNUSED(const char *fn), UNUSED(int ln)) {
709        _alLockPrintf("_alLockExtension", fn, ln);
710
711        if(ext_mutex == NULL) {
712                /*
713                 * Sigh.  Extensions are loaded from config, so they
714                 * need to have locks even before _alMain is called,
715                 * so InitExtension may not be called at this point.
716                 */
717                ext_mutex = _alCreateMutex();
718        }
719
720        _alLockMutex( ext_mutex );
721
722        return;
723}
724
725/*
726 * FL_alUnlockExtension( const char *fn, int ln )
727 *
728 * Unlock mutex guarding extension data structures, passing fn and ln to
729 * _alLockPrintf.
730 */
731static void FL_alUnlockExtension(UNUSED(const char *fn), UNUSED(int ln)) {
732        _alLockPrintf("_alUnlockExtension", fn, ln);
733
734        _alUnlockMutex( ext_mutex );
735
736        return;
737}
738
739
740#ifndef NODLOPEN
741/* avoid errors on platforms that don't support dlopen */
742
743/*
744 * _alExtPushFiniFunc( void (*func)(void) )
745 *
746 * Saves fini func to call on dlclose time.
747 */
748static void _alExtPushFiniFunc( void (*func)(void) ) {
749        if(FiniFunc.index >= MAX_EXT_LIBS) {
750                return;
751        }
752
753        FiniFunc.pool[FiniFunc.index] = func;
754        FiniFunc.index++;
755
756        return;
757}
758#endif /* NODLOPEN */
759
760#define DEFINE_AL_ENUM(e) { #e, e }
761
762typedef struct
763{
764        const ALchar *name;
765        ALenum value;
766} enumNameValuePair;
767
768enumNameValuePair alEnums[] = {
769        /* this has to be sorted! */
770        DEFINE_AL_ENUM(AL_BITS),
771        DEFINE_AL_ENUM(AL_BUFFER),
772        DEFINE_AL_ENUM(AL_BUFFERS_PROCESSED),
773        DEFINE_AL_ENUM(AL_BUFFERS_QUEUED),
774        DEFINE_AL_ENUM(AL_BYTE_OFFSET),
775        DEFINE_AL_ENUM(AL_CHANNELS),
776        DEFINE_AL_ENUM(AL_CONE_INNER_ANGLE),
777        DEFINE_AL_ENUM(AL_CONE_OUTER_ANGLE),
778        DEFINE_AL_ENUM(AL_CONE_OUTER_GAIN),
779        DEFINE_AL_ENUM(AL_DIRECTION),
780        DEFINE_AL_ENUM(AL_DISTANCE_MODEL),
781        DEFINE_AL_ENUM(AL_DOPPLER_FACTOR),
782        DEFINE_AL_ENUM(AL_DOPPLER_VELOCITY),
783        DEFINE_AL_ENUM(AL_EXPONENT_DISTANCE),
784        DEFINE_AL_ENUM(AL_EXPONENT_DISTANCE_CLAMPED),
785        DEFINE_AL_ENUM(AL_EXTENSIONS),
786        DEFINE_AL_ENUM(AL_FALSE),
787        DEFINE_AL_ENUM(AL_FORMAT_MONO16),
788        DEFINE_AL_ENUM(AL_FORMAT_MONO8),
789        DEFINE_AL_ENUM(AL_FORMAT_STEREO16),
790        DEFINE_AL_ENUM(AL_FORMAT_STEREO8),
791        DEFINE_AL_ENUM(AL_FREQUENCY),
792        DEFINE_AL_ENUM(AL_GAIN),
793        DEFINE_AL_ENUM(AL_INITIAL),
794        DEFINE_AL_ENUM(AL_INVALID_ENUM),
795        DEFINE_AL_ENUM(AL_INVALID_NAME),
796        DEFINE_AL_ENUM(AL_INVALID_OPERATION),
797        DEFINE_AL_ENUM(AL_INVALID_VALUE),
798        DEFINE_AL_ENUM(AL_INVERSE_DISTANCE),
799        DEFINE_AL_ENUM(AL_INVERSE_DISTANCE_CLAMPED),
800        DEFINE_AL_ENUM(AL_LINEAR_DISTANCE),
801        DEFINE_AL_ENUM(AL_LINEAR_DISTANCE_CLAMPED),
802        DEFINE_AL_ENUM(AL_LOOPING),
803        DEFINE_AL_ENUM(AL_MAX_DISTANCE),
804        DEFINE_AL_ENUM(AL_MAX_GAIN),
805        DEFINE_AL_ENUM(AL_MIN_GAIN),
806        DEFINE_AL_ENUM(AL_NONE),
807        DEFINE_AL_ENUM(AL_NO_ERROR),
808        DEFINE_AL_ENUM(AL_ORIENTATION),
809        DEFINE_AL_ENUM(AL_OUT_OF_MEMORY),
810        DEFINE_AL_ENUM(AL_PAUSED),
811        DEFINE_AL_ENUM(AL_PENDING),
812        DEFINE_AL_ENUM(AL_PITCH),
813        DEFINE_AL_ENUM(AL_PLAYING),
814        DEFINE_AL_ENUM(AL_POSITION),
815        DEFINE_AL_ENUM(AL_PROCESSED),
816        DEFINE_AL_ENUM(AL_REFERENCE_DISTANCE),
817        DEFINE_AL_ENUM(AL_RENDERER),
818        DEFINE_AL_ENUM(AL_ROLLOFF_FACTOR),
819        DEFINE_AL_ENUM(AL_SAMPLE_OFFSET),
820        DEFINE_AL_ENUM(AL_SEC_OFFSET),
821        DEFINE_AL_ENUM(AL_SIZE),
822        DEFINE_AL_ENUM(AL_SOURCE_RELATIVE),
823        DEFINE_AL_ENUM(AL_SOURCE_STATE),
824        DEFINE_AL_ENUM(AL_SOURCE_TYPE),
825        DEFINE_AL_ENUM(AL_SPEED_OF_SOUND),
826        DEFINE_AL_ENUM(AL_STATIC),
827        DEFINE_AL_ENUM(AL_STOPPED),
828        DEFINE_AL_ENUM(AL_STREAMING),
829        DEFINE_AL_ENUM(AL_TRUE),
830        DEFINE_AL_ENUM(AL_UNDETERMINED),
831        DEFINE_AL_ENUM(AL_UNUSED),
832        DEFINE_AL_ENUM(AL_VELOCITY),
833        DEFINE_AL_ENUM(AL_VENDOR),
834        DEFINE_AL_ENUM(AL_VERSION)
835};
836
837#undef DEFINE_AL_ENUM
838
839static int
840compareEnumNameValuePairs(const void *s1, const void *s2)
841{
842        const enumNameValuePair *p1 = (const enumNameValuePair*)s1;
843        const enumNameValuePair *p2 = (const enumNameValuePair*)s2;
844        return strcmp((const char*)(p1->name), (const char*)(p2->name));
845}
846
847static ALboolean
848getStandardEnumValue(ALenum *value, const ALchar *enumName)
849{
850        enumNameValuePair key;
851        enumNameValuePair *p;
852        key.name = enumName;
853        p = bsearch(&key, alEnums,
854                    sizeof(alEnums) / sizeof(alEnums[0]),
855                    sizeof(alEnums[0]),
856                    compareEnumNameValuePairs);
857        if (p == NULL) {
858                return AL_FALSE;
859        }
860        *value = p->value;
861        return AL_TRUE;
862}
863
864static ALboolean
865getExtensionEnumValue( ALenum *value, const ALchar *enumName )
866{
867        /* ToDo: Hook in our extension loader somehow */
868        const char *name = (const char*)enumName;
869        if (strcmp(name, "AL_BYTE_LOKI") == 0) {
870                *value = AL_BYTE_LOKI;
871                return AL_TRUE;
872        } else if (strcmp(name, "AL_FORMAT_QUAD16_LOKI") == 0) {
873                *value = AL_FORMAT_QUAD16_LOKI;
874                return AL_TRUE;
875        } else if (strcmp(name, "AL_FORMAT_QUAD8_LOKI") == 0) {
876                *value = AL_FORMAT_QUAD8_LOKI;
877                return AL_TRUE;
878        } else {
879                return AL_FALSE;
880        }
881}
882
883/*
884 * alGetEnumValue( const ALubyte *enumName )
885 *
886 * Returns the integer value of an enumeration (usually an extension)
887 * with the name ename.
888 */
889ALenum
890alGetEnumValue( const ALchar *enumName )
891{
892        ALenum value = 0;
893        if (getStandardEnumValue(&value, enumName) == AL_TRUE) {
894                return value;
895        }
896        if (getExtensionEnumValue(&value, enumName) == AL_TRUE) {
897                return value;
898        }
899        _alDCSetError( AL_INVALID_VALUE );
900        return value;
901}
Note: See TracBrowser for help on using the repository browser.