home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 106 / EnigmaAmiga106CD.iso / software / sviluppo / ahisrc / device / database.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-09-11  |  16.3 KB  |  713 lines

  1. /* $Id: database.c,v 4.14 1999/09/11 22:56:51 lcs Exp $ */
  2.  
  3. /*
  4.      AHI - Hardware independent audio subsystem
  5.      Copyright (C) 1996-1999 Martin Blom <martin@blom.org>
  6.      
  7.      This library is free software; you can redistribute it and/or
  8.      modify it under the terms of the GNU Library General Public
  9.      License as published by the Free Software Foundation; either
  10.      version 2 of the License, or (at your option) any later version.
  11.      
  12.      This library is distributed in the hope that it will be useful,
  13.      but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15.      Library General Public License for more details.
  16.      
  17.      You should have received a copy of the GNU Library General Public
  18.      License along with this library; if not, write to the
  19.      Free Software Foundation, Inc., 59 Temple Place - Suite 330, Cambridge,
  20.      MA 02139, USA.
  21. */
  22.  
  23. #include <config.h>
  24. #include <CompilerSpecific.h>
  25.  
  26. #include <exec/memory.h>
  27. #include <exec/semaphores.h>
  28. #include <dos/dostags.h>
  29. #include <dos/dos.h>
  30. #include <libraries/iffparse.h>
  31. #include <proto/exec.h>
  32. #include <proto/dos.h>
  33. #include <proto/iffparse.h>
  34. #include <proto/utility.h>
  35. #include <clib/ahi_protos.h>
  36. #include <pragmas/ahi_pragmas.h>
  37. #include <proto/ahi_sub.h>
  38. #include <strings.h>
  39.  
  40. #include "ahi_def.h"
  41. #include "database.h"
  42. #include "debug.h"
  43.  
  44.  
  45. static ULONG AddModeFile ( UBYTE *filename );
  46.  
  47. /******************************************************************************
  48. ** Audio Database *************************************************************
  49. ******************************************************************************/
  50.  
  51. struct AHI_AudioMode
  52. {
  53.   struct MinNode          ahidbn_MinNode;
  54.   struct TagItem          ahidbn_Tags[0];
  55.  
  56.   /* Taglist, mode name and driver name follows.
  57.      Size variable. Use FreeVec() to free node. */
  58. };
  59.  
  60. /*
  61. ** Lock the database for read access. Return NULL if database not present.
  62. */
  63.  
  64. struct AHI_AudioDatabase *
  65. LockDatabase(void)
  66. {
  67.   struct AHI_AudioDatabase *audiodb;
  68.  
  69.   Forbid();
  70.   
  71.   audiodb = (struct AHI_AudioDatabase *) FindSemaphore(ADB_NAME);
  72.  
  73.   if(audiodb != NULL)
  74.   {
  75.     ObtainSemaphoreShared((struct SignalSemaphore *) audiodb);
  76.   }
  77.  
  78.   Permit();
  79.  
  80.   return audiodb;
  81. }
  82.  
  83. /*
  84. ** Lock the database for write access. Create it if not present.
  85. */
  86.  
  87. struct AHI_AudioDatabase *
  88. LockDatabaseWrite(void)
  89. {
  90.   struct AHI_AudioDatabase *audiodb;
  91.  
  92.   Forbid();
  93.  
  94.   audiodb = (struct AHI_AudioDatabase *) FindSemaphore(ADB_NAME);
  95.  
  96.   if(audiodb != NULL)
  97.   {
  98.     ObtainSemaphore((struct SignalSemaphore *) audiodb);
  99.   }
  100.   else
  101.   {
  102.     audiodb = (struct AHI_AudioDatabase *)
  103.         AllocVec(sizeof(struct AHI_AudioDatabase), MEMF_PUBLIC|MEMF_CLEAR);
  104.  
  105.     if(audiodb != NULL)
  106.     {
  107.  
  108.       NewList( (struct List *) &audiodb->ahidb_AudioModes);
  109.  
  110.       audiodb->ahidb_Semaphore.ss_Link.ln_Name = audiodb->ahidb_Name;
  111.       audiodb->ahidb_Semaphore.ss_Link.ln_Pri  = 20;
  112.       strcpy(audiodb->ahidb_Semaphore.ss_Link.ln_Name, ADB_NAME);
  113.  
  114.       AddSemaphore((struct SignalSemaphore *) audiodb);
  115.       ObtainSemaphore((struct SignalSemaphore *) audiodb);
  116.     }
  117.   }
  118.   Permit();
  119.  
  120.   return audiodb;
  121. }
  122.  
  123. void
  124. UnlockDatabase ( struct AHI_AudioDatabase *audiodb )
  125. {
  126.   if(audiodb)
  127.   {
  128.     ReleaseSemaphore((struct SignalSemaphore *) audiodb);
  129.   }
  130. }
  131.  
  132. struct TagItem *
  133. GetDBTagList ( struct AHI_AudioDatabase *audiodb,
  134.                ULONG id )
  135. {
  136.   struct AHI_AudioMode *node;
  137.   struct TagItem       *rc = NULL;
  138.  
  139.   if((audiodb != NULL) && (id != AHI_INVALID_ID))
  140.   {
  141.     for(node=(struct AHI_AudioMode *)audiodb->ahidb_AudioModes.mlh_Head;
  142.         node->ahidbn_MinNode.mln_Succ;
  143.         node=(struct AHI_AudioMode *)node->ahidbn_MinNode.mln_Succ)
  144.     {
  145.       if(id == GetTagData(AHIDB_AudioID,AHI_INVALID_ID,node->ahidbn_Tags))
  146.       {
  147.         rc = node->ahidbn_Tags;
  148.         break;
  149.       }
  150.     }
  151.   }
  152.  
  153.   return rc;
  154. }
  155.  
  156.  
  157. /******************************************************************************
  158. ** AHI_NextAudioID ************************************************************
  159. ******************************************************************************/
  160.  
  161. /****** ahi.device/AHI_NextAudioID ******************************************
  162. *
  163. *   NAME
  164. *       AHI_NextAudioID -- iterate current audio mode identifiers
  165. *
  166. *   SYNOPSIS
  167. *       next_ID = AHI_NextAudioID( last_ID );
  168. *       D0                         D0
  169. *
  170. *       ULONG AHI_NextAudioID( ULONG );
  171. *
  172. *   FUNCTION
  173. *       This function is used to iterate through all current AudioIDs in
  174. *       the audio database.
  175. *
  176. *   INPUTS
  177. *       last_ID - previous AudioID or AHI_INVALID_ID if beginning iteration.
  178. *
  179. *   RESULT
  180. *       next_ID - subsequent AudioID or AHI_INVALID_ID if no more IDs.
  181. *
  182. *   EXAMPLE
  183. *
  184. *   NOTES
  185. *
  186. *   BUGS
  187. *
  188. *   SEE ALSO
  189. *      AHI_GetAudioAttrsA(), AHI_BestAudioIDA()
  190. *
  191. ****************************************************************************
  192. *
  193. */
  194.  
  195. ULONG ASMCALL
  196. NextAudioID( REG(d0, ULONG id),
  197.              REG(a6, struct AHIBase *AHIBase) )
  198. {
  199.   struct AHI_AudioDatabase *audiodb;
  200.   struct AHI_AudioMode *node;
  201.   ULONG  nextid=AHI_INVALID_ID;
  202.  
  203.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  204.   {
  205.     Debug_NextAudioID(id);
  206.   }
  207.  
  208.   audiodb = LockDatabase();
  209.  
  210.   if(audiodb != NULL)
  211.   {
  212.     node = (struct AHI_AudioMode *) audiodb->ahidb_AudioModes.mlh_Head;
  213.  
  214.     if(id != AHI_INVALID_ID)
  215.     {
  216.       while(node != NULL)
  217.       {
  218.         ULONG thisid;
  219.         
  220.         thisid = GetTagData(AHIDB_AudioID,AHI_INVALID_ID,node->ahidbn_Tags);
  221.         node = (struct AHI_AudioMode *) node->ahidbn_MinNode.mln_Succ;
  222.  
  223.         if(thisid == id)
  224.         {
  225.           break;
  226.         }
  227.       }
  228.     }
  229.  
  230.     if(node && node->ahidbn_MinNode.mln_Succ)
  231.     {
  232.       nextid = GetTagData(AHIDB_AudioID, AHI_INVALID_ID, node->ahidbn_Tags);
  233.     }
  234.  
  235.     UnlockDatabase(audiodb);
  236.   }
  237.  
  238.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  239.   {
  240.     KPrintF("=>0x%08lx\n",nextid);
  241.   }
  242.  
  243.   return nextid;
  244. }
  245.  
  246.  
  247. /******************************************************************************
  248. ** AHI_AddAudioMode ***********************************************************
  249. ******************************************************************************/
  250.  
  251. /****i* ahi.device/AHI_AddAudioMode *****************************************
  252. *
  253. *   NAME
  254. *       AHI_AddAudioMode -- add an audio mode to the database (V4)
  255. *
  256. *   SYNOPSIS
  257. *       success = AHI_AddAudioMode( DBtags );
  258. *       D0                          A0
  259. *
  260. *       ULONG AHI_AddAudioMode( struct TagItem *, UBYTE *, UBYTE *);
  261. *
  262. *   FUNCTION
  263. *       Adds the audio mode described by a taglist to the audio mode
  264. *       database. If the database does not exists, it will be created.
  265. *
  266. *   INPUTS
  267. *       DBtags - Tags describing the properties of this mode.
  268. *
  269. *   RESULT
  270. *       success - FALSE if the mode could not be added.
  271. *
  272. *   EXAMPLE
  273. *
  274. *   NOTES
  275. *
  276. *   BUGS
  277. *
  278. *   SEE ALSO
  279. *
  280. ****************************************************************************
  281. *
  282. */
  283.  
  284. ULONG ASMCALL
  285. AddAudioMode( REG(a0, struct TagItem *DBtags),
  286.               REG(a6, struct AHIBase *AHIBase) )
  287. {
  288.   struct AHI_AudioDatabase *audiodb;
  289.   struct AHI_AudioMode *node;
  290.   ULONG nodesize = sizeof(struct AHI_AudioMode), tagitems = 0;
  291.   ULONG datalength = 0, namelength = 0, driverlength = 0;
  292.   struct TagItem *tstate = DBtags, *tp, *tag;
  293.   ULONG rc = FALSE;
  294.  
  295.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  296.   {
  297.     Debug_AddAudioMode(DBtags);
  298.   }
  299.  
  300. // Remove old mode if present in database
  301.   AHI_RemoveAudioMode( GetTagData(AHIDB_AudioID, AHI_INVALID_ID, DBtags));
  302.  
  303. // Now add the new mode
  304.  
  305.   audiodb = LockDatabaseWrite();
  306.  
  307.   if(audiodb != NULL)
  308.   {
  309.     BOOL fast = FALSE;
  310.  
  311. // Find total size
  312.  
  313.     while( (tag = NextTagItem(&tstate)) != NULL )
  314.     {
  315.  
  316.       if(tag->ti_Data) switch(tag->ti_Tag)
  317.       {
  318.         case AHIDB_Data:
  319.           datalength    = ((ULONG *)tag->ti_Data)[0];
  320.           nodesize     += datalength;
  321.           break;
  322.  
  323.         case AHIDB_Name:
  324.           namelength    = strlen((UBYTE *)tag->ti_Data)+1;
  325.           nodesize     += namelength;
  326.           break;
  327.  
  328.         case AHIDB_Driver:
  329.           driverlength  = strlen((UBYTE *)tag->ti_Data)+1;
  330.           nodesize     += driverlength;
  331.           break;
  332.  
  333.         case AHIDB_MultTable:
  334.           fast = tag->ti_Data;
  335.           break;
  336.       }
  337.  
  338.       nodesize += sizeof(struct TagItem);
  339.       tagitems++;
  340.     }
  341.  
  342. #ifdef VERSIONGEN
  343.     if( fast )
  344.     {
  345.       // Silently filter away all fast modes!
  346.       rc = TRUE;
  347.       goto unlock;
  348.     }
  349. #endif
  350.  
  351.     nodesize += sizeof(struct TagItem);  // The last TAG_END
  352.     tagitems++;
  353.  
  354.     node = AllocVec(nodesize, MEMF_PUBLIC|MEMF_CLEAR);
  355.  
  356.     if(node != NULL)
  357.     {
  358.       tp      = node->ahidbn_Tags;
  359.       tstate  = DBtags;
  360.       while( (tag = NextTagItem(&tstate)) != NULL)
  361.       {
  362.         if(tag->ti_Data) switch(tag->ti_Tag)
  363.         {
  364.           case AHIDB_Data:
  365.             tp->ti_Data = ((ULONG) &node->ahidbn_Tags[tagitems]);
  366.             CopyMem((APTR)tag->ti_Data, (APTR)tp->ti_Data, datalength);
  367.             break;
  368.           case AHIDB_Name:
  369.             tp->ti_Data = ((ULONG) &node->ahidbn_Tags[tagitems]) + datalength;
  370.             strcpy((UBYTE *)tp->ti_Data, (UBYTE *)tag->ti_Data);
  371.             break;
  372.           case AHIDB_Driver:
  373.             tp->ti_Data= ((ULONG) &node->ahidbn_Tags[tagitems]) + datalength + namelength;
  374.             strcpy((UBYTE *)tp->ti_Data, (UBYTE *)tag->ti_Data);
  375.             break;
  376.           default:
  377.             tp->ti_Data = tag->ti_Data;
  378.             break;
  379.         }
  380.         tp->ti_Tag = tag->ti_Tag;
  381.         tp++;
  382.       }
  383.       tp->ti_Tag = TAG_DONE;
  384.  
  385.       AddHead((struct List *) &audiodb->ahidb_AudioModes, (struct Node *) node);
  386.       rc = TRUE;
  387.     }
  388.  
  389. unlock:
  390.     UnlockDatabase(audiodb);
  391.   }
  392.  
  393.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  394.   {
  395.     KPrintF("=>%ld\n",rc);
  396.   }
  397.  
  398.   return rc;
  399. }
  400.  
  401.  
  402. /******************************************************************************
  403. ** AHI_RemoveAudioMode ********************************************************
  404. ******************************************************************************/
  405.  
  406. /****i* ahi.device/AHI_RemoveAudioMode **************************************
  407. *
  408. *   NAME
  409. *       AHI_RemoveAudioMode -- remove a audio mode to the database (V4)
  410. *
  411. *   SYNOPSIS
  412. *       success = AHI_RemoveAudioMode( ID );
  413. *       D0                             D0
  414. *
  415. *       ULONG AHI_RemoveAudioMode( ULONG );
  416. *
  417. *   FUNCTION
  418. *       Removes the audio mode from the audio mode database.
  419. *
  420. *   INPUTS
  421. *       ID - The audio ID of the mode to be removed, or AHI_INVALID_ID.
  422. *
  423. *   RESULT
  424. *       success - FALSE if the mode could not be removed.
  425. *
  426. *   EXAMPLE
  427. *
  428. *   NOTES
  429. *
  430. *   BUGS
  431. *
  432. *   SEE ALSO
  433. *
  434. ****************************************************************************
  435. *
  436. */
  437.  
  438. ULONG ASMCALL
  439. RemoveAudioMode( REG(d0, ULONG id),
  440.                  REG(a6, struct AHIBase *AHIBase) )
  441. {
  442.   struct AHI_AudioMode *node;
  443.   struct AHI_AudioDatabase *audiodb;
  444.   ULONG rc=FALSE;
  445.  
  446.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  447.   {
  448.     Debug_RemoveAudioMode(id);
  449.   }
  450.  
  451.  
  452.   /* Why ?? */
  453.  
  454.   audiodb = LockDatabaseWrite();
  455.  
  456.   if(audiodb != NULL)
  457.   {
  458.     UnlockDatabase(audiodb);
  459.   }
  460.  
  461.   audiodb = LockDatabaseWrite();
  462.  
  463.   if(audiodb != NULL)
  464.   {
  465.     if(id != AHI_INVALID_ID)
  466.     {
  467.       for(node=(struct AHI_AudioMode *)audiodb->ahidb_AudioModes.mlh_Head;
  468.           node->ahidbn_MinNode.mln_Succ;
  469.           node=(struct AHI_AudioMode *)node->ahidbn_MinNode.mln_Succ)
  470.       {
  471.         if(id == GetTagData(AHIDB_AudioID, AHI_INVALID_ID, node->ahidbn_Tags))
  472.         {
  473.           Remove((struct Node *) node);
  474.           FreeVec(node);
  475.           rc = TRUE;
  476.           break;
  477.         }
  478.       }
  479.  
  480.       // Remove the entire database if it's empty
  481.  
  482.       Forbid();
  483.  
  484.       if(audiodb->ahidb_AudioModes.mlh_Head->mln_Succ == NULL)
  485.       {
  486.         UnlockDatabase(audiodb);
  487.  
  488.         audiodb = (struct AHI_AudioDatabase *) FindSemaphore(ADB_NAME);
  489.  
  490.         if(audiodb != NULL)
  491.         {
  492.           RemSemaphore((struct SignalSemaphore *) audiodb);
  493.           FreeVec(audiodb);
  494.         }
  495.  
  496.         audiodb = NULL;
  497.  
  498.       }
  499.  
  500.       Permit();
  501.  
  502.     }
  503.     UnlockDatabase(audiodb);
  504.   }
  505.  
  506.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  507.   {
  508.     KPrintF("=>%ld\n",rc);
  509.   }
  510.  
  511.   return rc;
  512. }
  513.  
  514.  
  515. /******************************************************************************
  516. ** AHI_LoadModeFile ***********************************************************
  517. ******************************************************************************/
  518.  
  519. /****i* ahi.device/AHI_LoadModeFile *****************************************
  520. *
  521. *   NAME
  522. *       AHI_LoadModeFile -- Add all modes in a mode file to the database (V4)
  523. *
  524. *   SYNOPSIS
  525. *       success = AHI_LoadModeFile( name );
  526. *       D0                          A0
  527. *
  528. *       ULONG AHI_LoadModeFile( STRPTR );
  529. *
  530. *   FUNCTION
  531. *       This function takes the name of a file or a directory and either
  532. *       adds all modes in the file or the modes of all files in the
  533. *       directory to the audio mode database. Directories inside the
  534. *       given directory will not be recursed. The file format is IFF-AHIM.
  535. *
  536. *   INPUTS
  537. *       name - A pointer to the name of a file or directory.
  538. *
  539. *   RESULT
  540. *       success - FALSE on error. Check dos.library/IOErr() for more
  541. *           information.
  542. *
  543. *   EXAMPLE
  544. *
  545. *   NOTES
  546. *
  547. *   BUGS
  548. *
  549. *   SEE ALSO
  550. *
  551. ****************************************************************************
  552. *
  553. */
  554.  
  555. ULONG ASMCALL
  556. LoadModeFile( REG(a0, UBYTE *name),
  557.               REG(a6, struct AHIBase *AHIBase) )
  558. {
  559.   ULONG rc=FALSE;
  560.   struct FileInfoBlock  *fib;
  561.   BPTR  lock,thisdir;
  562.  
  563.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  564.   {
  565.     Debug_LoadModeFile(name);
  566.   }
  567.  
  568.   SetIoErr(NULL);
  569.  
  570.   fib = AllocDosObject(DOS_FIB, TAG_DONE);
  571.  
  572.   if(fib != NULL)
  573.   {
  574.     lock = Lock(name, ACCESS_READ);
  575.  
  576.     if(lock != NULL)
  577.     {
  578.       if(Examine(lock,fib))
  579.       {
  580.         if(fib->fib_DirEntryType>0) // Directory?
  581.         {
  582.           thisdir = CurrentDir(lock);
  583.  
  584.           while(ExNext(lock, fib))
  585.           {
  586.             if(fib->fib_DirEntryType>0)
  587.             {
  588.               continue;     // AHI_LoadModeFile(fib->fib_FileName); for recursion
  589.             }
  590.             else
  591.             {
  592.               rc = AddModeFile(fib->fib_FileName);
  593.  
  594.               if(!rc)
  595.               {
  596.                 break;
  597.               }
  598.             }
  599.           }
  600.           if(IoErr() == ERROR_NO_MORE_ENTRIES)
  601.           {
  602.             SetIoErr(NULL);
  603.           }
  604.  
  605.           CurrentDir(thisdir);
  606.         }
  607.         else  // Plain file
  608.         {
  609.           rc = AddModeFile(name);
  610.         }
  611.       }
  612.  
  613.       UnLock(lock);
  614.     }
  615.  
  616.     FreeDosObject(DOS_FIB,fib);
  617.   }
  618.  
  619.   if(AHIBase->ahib_DebugLevel >= AHI_DEBUG_HIGH)
  620.   {
  621.     KPrintF("=>%ld\n",rc);
  622.   }
  623.  
  624.   return rc;
  625. }
  626.  
  627. /* AddModeFile **********************************************************/
  628.  
  629. static ULONG
  630. AddModeFile ( UBYTE *filename )
  631. {
  632.   struct IFFHandle *iff;
  633.   struct StoredProperty *name,*data;
  634.   struct CollectionItem *ci;
  635.   struct TagItem *tag,*tstate;
  636.   struct TagItem extratags[]=
  637.   {
  638.     { AHIDB_Driver, NULL },
  639.     { AHIDB_Data, NULL },
  640.     { TAG_MORE,   NULL }
  641.   };
  642.   ULONG rc=FALSE;
  643.  
  644.   iff = AllocIFF();
  645.  
  646.   if(iff != NULL)
  647.   {
  648.  
  649.     iff->iff_Stream = Open(filename, MODE_OLDFILE);
  650.  
  651.     if(iff->iff_Stream != NULL)
  652.     {
  653.       InitIFFasDOS(iff);
  654.  
  655.       if(!OpenIFF(iff, IFFF_READ))
  656.       {
  657.  
  658.         if(!(PropChunk(iff,       ID_AHIM, ID_AUDN)
  659.           || PropChunk(iff,       ID_AHIM, ID_AUDD)
  660.           || CollectionChunk(iff, ID_AHIM, ID_AUDM)
  661.           || StopOnExit(iff,      ID_AHIM, ID_FORM)))
  662.         {
  663.           if(ParseIFF(iff, IFFPARSE_SCAN) == IFFERR_EOC)
  664.           {
  665.             name = FindProp(iff,       ID_AHIM, ID_AUDN);
  666.             data = FindProp(iff,       ID_AHIM, ID_AUDD);
  667.             ci   = FindCollection(iff, ID_AHIM, ID_AUDM);
  668.  
  669.             if(name != NULL)
  670.             {
  671.               extratags[0].ti_Data = (ULONG) name->sp_Data;
  672.             }
  673.  
  674.             if(data != NULL)
  675.             {
  676.               extratags[1].ti_Data = (ULONG) data->sp_Data;
  677.             }
  678.  
  679.             rc = TRUE;
  680.  
  681.             while(ci != NULL)
  682.             {
  683.               // Relocate loaded taglist
  684.  
  685.               tstate = (struct TagItem *) ci->ci_Data;
  686.               while((tag = NextTagItem(&tstate)) != NULL )
  687.               {
  688.                 if(tag->ti_Tag & (AHI_TagBaseR ^ AHI_TagBase))
  689.                 {
  690.                   tag->ti_Data += (ULONG) ci->ci_Data;
  691.                 }
  692.               }
  693.  
  694.               // Link taglists
  695.  
  696.               extratags[2].ti_Data = (ULONG) ci->ci_Data;
  697.  
  698.               rc = AHI_AddAudioMode(extratags);
  699.  
  700.               ci = ci->ci_Next;
  701.             }
  702.           }
  703.         }
  704.         CloseIFF(iff);
  705.       }
  706.       Close(iff->iff_Stream);
  707.     }
  708.     FreeIFF(iff);
  709.   }
  710.  
  711.   return rc;
  712. }
  713.