db.c

Go to the documentation of this file.
00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 /*
00010     The contents of this file are subject to the Mozilla Public License 
00011     Version 1.1 (the "License"); you may not use this file except in 
00012     compliance with the License. You may obtain a copy of the License at 
00013     http://www.mozilla.org/MPL/
00014                                                         
00015     Software distributed under the License is distributed on an "AS IS" 
00016     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. 
00017     See the License for the specific language governing rights and 
00018     limitations under the License.
00019     
00020     The Original Code is property of Neuros Audio LLC.
00021     
00022     The Initial Developer of the Original Code is DeepB. 
00023     Portions created by others are public domain. 
00024     All Rights Reserved.
00025     
00026     Contributor(s): DeepB, others.
00027     
00028     Alternatively, the contents of this file may be used under the terms 
00029     of the GPL license (the GPL License), in which case the provisions of 
00030     GPL License are applicable instead of those above.  
00031     If you wish to allow use of your version of this file only under the 
00032     terms of the GPL License and not to allow others to use your version of 
00033     this file under the MPL, indicate your decision by deleting the 
00034     provisions above and replace them with the notice and other provisions 
00035     required by the GPL License. If you do not delete the provisions above, 
00036     a recipient may use your version of this file under either the MPL or 
00037     the GPL License."
00038 */
00039 
00043 #include "../SYSTEM/sys_hardware.h"
00044 #include "db.h"
00045 #include "db_assert.h"
00046 
00050 static BOOL _removeChildIdx(DB_DATA *,DB_FIELDIDX,DB_MDBOFFSET);
00051 static DB_HDL _query(DB_ID, DB_ENTRY, DB_DATA *, DB_HDL);
00052 #define DB_MAXDBNODES       8           /* Maximum children nodes per DB. */
00053 
00054 static st_DBDINODE * _copyTree(st_DBDINODE *, const st_DBIDNODE *);
00055 static const DB_DATA * _formDataTree(st_DBDINODE *, const DB_DATA *);
00056 static BOOL _insert2child(st_DBDINODE *);
00057 #define RETURN_ERROR    {FAT_fclose(file);return FALSE;}
00058 #define RETURN_ERROR_DB {FAT_fclose(file);return DB_INVALID_ID;}
00059 static void _sortSAI (unsigned long *, USHORT);
00060 static BOOL _genFile        ( ULONG, const char *);
00061 static BOOL _createDB       ( ULONG, const char *, BOOL);
00062 static BOOL _replacePAI(DB_ID,DB_MDBOFFSET,DB_MDBOFFSET);
00063 #define DB_MAXPAIBUFLEN     64  
00064 static DB_PAIOFFSET _checkPAI(DB_ID,DB_PAIOFFSET,DB_MDBOFFSET);
00065 static DB_PAIOFFSET _createPAIentry(DB_ID,DB_MDBOFFSET);
00066 #define SPECIAL_CHAR_FIX
00067 
00068 #define TABLE_SIZE  130
00069 const unsigned char _char_sorting_table[TABLE_SIZE] =
00070         {
00071           /*0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,*/
00072             0x00, 0x06, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
00073           /*0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,*/
00074             0x0E, 0x01, 0x02, 0x24, 0x25, 0x03, 0x0F, 0x10, 
00075             
00076           /*0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,*/
00077             0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
00078           /*0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,*/
00079             0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 
00080             
00081           /*0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,*/
00082             0x04, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x22,
00083           /*0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,*/
00084             0x2C, 0x2D, 0x2E, 0x40, 0x2F, 0x23, 0x30, 0x31, 
00085             
00086           /*0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,*/
00087             0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B,
00088           /*0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,*/
00089             0x4C, 0x4D, 0x32, 0x33, 0x41, 0x42, 0x33, 0x34, 
00090         
00091           /*0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,*/
00092             0x35, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A,
00093           /*0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,*/
00094             0x5C, 0x5E, 0x60, 0x62, 0x64, 0x66, 0x68, 0x6A, 
00095         
00096           /*0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,*/
00097             0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A,
00098           /*0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,*/
00099             0x7C, 0x7E, 0x80, 0x36, 0x37, 0x38, 0x39, 0x3A, 
00100         
00101           /*0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,*/
00102             0x3B, 0x4E, 0x50, 0x52, 0x54, 0x56, 0x58, 0x5A, 
00103           /*0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,*/
00104             0x5C, 0x5E, 0x60, 0x61, 0x64, 0x66, 0x68, 0x6A, 
00105         
00106           /*0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,*/
00107             0x6C, 0x6E, 0x70, 0x72, 0x74, 0x76, 0x78, 0x7A, 
00108           /*0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,*/
00109             0x7C, 0x7E, 0x80, 0x3C, 0x3D, 0x3E, 0x3F, 0x21,
00110             
00111           /*0x80, 0x81*/
00112             0x05, 0x07
00113         };
00114 
00115 #ifdef SPECIAL_CHAR_FIX
00116 #define _2lower(x) (((_char_sorting_table[((x)>>8)&0xff])<<8) |(_char_sorting_table[(x)&0xff]) )
00117 #else
00118 #define _2lower(x) _char_sorting_table[(x)]
00119 #endif
00120 
00124 
00128 #ifdef BACKUP_DATABASE
00129 const char    strDBBUPDIR[]   = "BAK_DB";
00130 #endif
00131 const char    strDBDIR[]      = "WOID_DB";
00132 const char    strAUDIODIR[]   = "audio";
00133 const char    strAUDIO[]      = "audio.mdb";
00134 const char    strPCAUDIO[]    = "pcaudio.mdb";
00135 const char    strFAILEDHISI[] = "failedhisi.mdb";
00136 const char    strIDEDHISI[]   = "idedhisi.mdb";
00137 const char    strUNIDEDHISI[] = "unidedhisi.mdb";
00138 st_DBREGIST   DB_registration[DB_MAX_ID];   /* DB ID registration record. */
00139 st_DBIDTREE   DB_idtree;                    /* DB ID registration tree. */
00140 st_DBQUERYCTL DB_qctl[DB_OPENMAX];
00141 st_DBINFO     DB_qinfo[DB_OPENMAX];
00142 
00143 st_DBNAV      DBnav;
00144 
00145 //DB_CTL        DB_ctl;
00146 extern void AUDIO_MDB_INIT_TABLE    ( void );
00147 extern void PCAUDIO_MDB_INIT_TABLE  ( void );
00148 extern void UNIDHISI_MDB_INIT_TABLE ( void );
00149 extern void IDEDHISI_MDB_INIT_TABLE ( void );
00150 extern void FAILHISI_MDB_INIT_TABLE ( void );
00151 
00155 #pragma CODE_SECTION (DB_unmount, ".dbinit_code")
00167 BOOL DB_unmount(DB_ID id)
00168 {   
00169     return TRUE;    
00170 }
00171 
00172 
00173 #pragma CODE_SECTION (DB_setSyncMark, ".dbinit_code")
00181 void DB_setSyncMark( const char * drive )
00182 {
00183     st_DBHEADER         header;
00184     File *              file;
00185     
00186     FAT_cd(drive);  
00187     if( TRUE == FAT_cd(strDBDIR) )
00188     {
00189         if( TRUE == FAT_cd(strAUDIODIR) )
00190         {
00191             if(file = FAT_fopen(strAUDIO, r_b))
00192             {
00193                 FAT_fseek(file, 0, SEEK_HEAD);
00194                 if( FAT_fread(file, (unsigned short *)&header, sizeof(st_DBHEADER)) 
00195                     == sizeof(st_DBHEADER) ) 
00196                 {
00197                     header.status |= 0x0002;    
00198                 }
00199                 FAT_fseek(file, 0, SEEK_HEAD);
00200                 FAT_fwrite(file, (unsigned short *)&header, sizeof(st_DBHEADER)); 
00201                 FAT_fclose(file);
00202             }
00203         }
00204     }
00205 }
00206 
00207 #pragma CODE_SECTION (DB_checkSyncMark, ".dbinit_code")
00216 BOOL DB_checkSyncMark( const char * drive )
00217 {
00218     st_DBHEADER         header;
00219     BOOL                ret = TRUE;
00220     File *              file;
00221     
00222     FAT_cd(drive);
00223     if( TRUE == FAT_cd(strDBDIR) )
00224     {
00225         if( TRUE == FAT_cd(strAUDIODIR) )
00226         {
00227             if(file = FAT_fopen(strAUDIO, rb))
00228             {
00229                 if( FAT_fread(file, (unsigned short *)&header, sizeof(st_DBHEADER)) 
00230                     == sizeof(st_DBHEADER) ) 
00231                 {
00232                     if( !(header.status & 0x0002) ) ret = FALSE;
00233                 }
00234                 FAT_fclose(file);
00235             }
00236         }
00237     }
00238             
00239     return ret;
00240 }
00241 
00242 #pragma CODE_SECTION(DB_removeRecord, ".db_code")
00255 BOOL DB_removeRecord(DB_ID childId, DB_ENTRY childEntry, DB_ENTRY paiEntry)
00256 {
00257     unsigned short  entryNum;
00258     DB_MDBOFFSET    root;
00259     DB_MDBOFFSET    child;
00260     DB_PAIOFFSET    pai;
00261     DB_FIELDIDX     fldidx;
00262     DB_RECLEN       len;
00263     File *          idxfile;
00264     File *          dbfile;
00265     unsigned short  record[DB_MAXRECLEN];   
00266     
00267     if(DB__cdDBdir(DB__name(DB__rootID(childId), MDB)) == FALSE)   return FALSE;    
00268     
00269     fldidx = DB__fieldIndex(childId);
00270 
00271     /* Fetch child MDB offset. */
00272     idxfile = FAT_fopen(DB__name(childId, SAI), rb);
00273     FAT_fseek(idxfile, (long)(childEntry + DB_SAIFIRSTENTRY) << 2, SEEK_HEAD);
00274     FAT_fread(idxfile, (unsigned short *)&child, 2);
00275     FAT_fread(idxfile, (unsigned short *)&pai, 2);
00276     FAT_fclose(idxfile);
00277 
00278     /* Update root record, remove child index. */
00279     idxfile = FAT_fopen(DB__name(childId, PAI), rb);
00280     FAT_fseek(idxfile, pai+((paiEntry-1)<<1), SEEK_HEAD);
00281     FAT_fread(idxfile, (unsigned short *)&root, 2);
00282     FAT_fclose(idxfile);    
00283 
00284     dbfile = FAT_fopen(DB__name(DB__rootID(childId), MDB), r_b);
00285     FAT_fseek(dbfile, root, SEEK_HEAD);
00286     DB__getRecord(dbfile, record);
00287     
00288     _removeChildIdx(record, fldidx, child);
00289 
00290     len = DB__recordLen(record);
00291 
00292     FAT_fseek(dbfile, root, SEEK_HEAD);
00293     FAT_fwrite(dbfile, (unsigned short *)record, len);
00294     FAT_fclose(dbfile);
00295 
00296 
00297     /* Search child PAI to remove specified parent entry. */
00298     DB__removePAIentry(childId, root, pai, &entryNum);
00299 
00300     if(entryNum == 0)
00301     {
00302         /* No PAIs left for this entry, delete it. */
00303         DB__deleteChildRecord(childId, childEntry);
00304     }
00305 
00306     return TRUE;
00307 }
00308 
00309 #pragma CODE_SECTION(_removeChildIdx, ".db_code")
00322 static BOOL _removeChildIdx(DB_DATA *       pRecord, 
00323                             DB_FIELDIDX     fldidx, 
00324                             DB_MDBOFFSET    childMdb)
00325 {
00326     unsigned long       mdb;
00327     unsigned short *    pD;
00328     unsigned short *    pT;
00329     
00330     pD = (unsigned short *)DB__locateField(pRecord, fldidx);
00331     
00332     while(1)
00333     {
00334         if(*pD == DB_ESCCHAR) pD++;
00335         else if( (*pD==DB_RECDLMT) ||(*pD==DB_FLDDLMT) )  break;
00336         
00337         mdb = (unsigned long)(*pD)<<16;     
00338         pT = pD++;
00339         
00340         if(*pD == DB_ESCCHAR) pD++;     
00341         else if( (*pD==DB_RECDLMT) ||(*pD==DB_FLDDLMT) )  break;
00342         
00343         mdb |= (unsigned long)(*pD);
00344 
00345         if( mdb == childMdb)
00346         {
00347             *pT  = 0;
00348             *pD  = 0;
00349         }
00350         
00351         pD++;
00352     }
00353         
00354     return TRUE;    
00355 }
00356 
00357 //#pragma CODE_SECTION(DB_queryFirst, ".db_code")
00358 #pragma CODE_SECTION(DB_queryFirst, ".sram0_resident")
00377 DB_HDL DB_queryFirst(   DB_ID           id, 
00378                         DB_FIELDIDX     fldIdx, 
00379                         DB_ENTRY        fldEntry, 
00380                         DB_ENTRY        dbEntry,
00381                         DB_DATA *       pData)
00382 {
00383     DB_HDL          hdl;
00384     DB_ID           tmpid;
00385     USHORT          entryNum;
00386     unsigned short  ii;
00387     st_DBQUERYCTL * pCtl;
00388     st_DBIDNODE *   node;
00389     st_DBINFO *     pInfo;
00390             
00391     /* Locate first available query control OBJ. */
00392     for( ii = 0; ii < DB_OPENMAX; ii++ ) 
00393     {       
00394         if( DB_qctl[ii].free == TRUE )  break;
00395     }
00396     if ( ii == DB_OPENMAX ) return DB_INVALID_HDL;  
00397 
00398     /* Valid handle found. */   
00399     hdl         = ii;
00400     pCtl        = &DB_qctl[hdl];
00401     pCtl->free  = FALSE;
00402     pInfo       = &DB_qinfo[hdl];
00403     
00404     if( DB__info(id, pInfo) == FALSE )
00405     {
00406         pCtl->free = TRUE;
00407         return DB_INVALID_HDL;
00408     }
00409     
00410     // start querying.
00411     node = &DB_idtree.node[id];
00412     
00413     /* Check to see if id points to a virtual DB. */
00414     //if( DB_registration[id].fname == NULL ) 
00415     if(pInfo->bVirtual == TRUE)
00416     {
00417         /* Virtual DB, access through its parent. */
00418         node = node->parent;        
00419         return( _query(node->id, dbEntry, pData, hdl) );        
00420     }
00421 
00422     /* Check to see if primary key is used to access the database. */
00423     //if( fldIdx == 0 )
00424     if( (fldIdx == 0)||(fldIdx == 0xffff) )
00425     {
00426         /* Primary key detected, query DB directly. */
00427         return( _query(id, dbEntry, pData, hdl) );
00428     }
00429 
00430     /* Following code to access DB using specified key. */
00431     /* Check to see if this is a valid key. */
00432     //if( DB__info(id, &info) == FALSE ) return DB_INVALID_HDL;
00433     //if( fldIdx >= info.numOfKeys ) return DB_INVALID_HDL;
00434     if( fldIdx >= pInfo->numOfKeys )
00435     {
00436         pCtl->free = TRUE;
00437         return DB_INVALID_HDL;
00438     }
00439 
00440     /* Fetch the access field DB ID. */
00441     node = node->child; 
00442     for(ii = 0; ii < fldIdx; ii++ ) node = node->next;
00443 
00444     tmpid = node->id;
00445 
00446     /* Locate the key. */
00447     hdl = _query(tmpid, fldEntry, pData, hdl);
00448     if(hdl == DB_INVALID_HDL) return hdl;
00449 
00450 
00451     //pCtl = &DB_qctl[hdl];
00452     /* Close current MDB file. */
00453     FAT_fclose(pCtl->dbfile);
00454 
00455     /* Close current SAI file. */
00456     FAT_fclose(pCtl->idxfile);
00457 
00458 
00459     /* Open MDB file. */
00460     pCtl->dbfile = FAT_fopen(DB__name(id, MDB), rb);
00461 
00462     /* Open PAI file. */
00463     pCtl->idxfile = FAT_fopen(DB__name(tmpid, PAI), rb);
00464     
00465     if( pCtl->pai == 0) 
00466     {
00467         /* Empty PAI entry. */
00468         pCtl->free = TRUE;
00469 
00470         FAT_fclose(pCtl->idxfile);
00471         FAT_fclose(pCtl->dbfile);
00472         return DB_INVALID_HDL;
00473     }
00474 
00475     /* PAI entry always takes 32 bits. */
00476     pCtl->step = 1;
00477     
00478     /* Locate the entry number. */
00479     FAT_fseek(pCtl->idxfile, pCtl->pai - 4, SEEK_HEAD);
00480     FAT_fread(pCtl->idxfile, &entryNum, 1);
00481     
00482     pInfo->numOfPAIent = entryNum+1;
00483     if(dbEntry > entryNum)
00484     {
00485         /* Empty PAI entry. */
00486         pCtl->free = TRUE;
00487         FAT_fclose(pCtl->idxfile);
00488         FAT_fclose(pCtl->dbfile);
00489         return DB_INVALID_HDL;
00490     }
00491     
00492     pCtl->idx = pCtl->pai;
00493 
00494 #if 1
00495     /* !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00496     ** I chose the confusing way to ease my UI application. :(
00497     ** Any query via PAI MUST add ONE entry offset, thus the UI
00498     ** can use the same code to query no matter it is via SAI or PAI,
00499     ** since "dbEntry == 0" always points to the default empty entry
00500     ** if we directly query the DB through SAI ( fldIdx == 0 ).
00501     ** !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
00502     */
00503     pCtl->idx -= 2; 
00504 #endif
00505 
00506     /* Locate the record index. */
00507     FAT_fseek(pCtl->idxfile, pCtl->idx + (dbEntry << 1), SEEK_HEAD);
00508     FAT_fread(pCtl->idxfile, (unsigned short *)&pCtl->pai, 2);
00509         
00510     /* Locate the record. */
00511     FAT_fseek(pCtl->dbfile, pCtl->pai, SEEK_HEAD);
00512 
00513     /* Fetch record. */
00514     if( DB__getRecord(pCtl->dbfile, pData) == FALSE ) 
00515     {       
00516         /* No record available. */
00517         pCtl->free = TRUE;
00518         FAT_fclose(pCtl->idxfile);
00519         FAT_fclose(pCtl->dbfile);
00520         return DB_INVALID_HDL;
00521     }
00522 
00523     return hdl;
00524 }
00525 
00526 #pragma CODE_SECTION(DB_queryNext, ".db_code")
00539 BOOL DB_queryNext(DB_HDL hdl, DB_ENTRY entry, DB_DATA * pData)
00540 {
00541     DB_MDBOFFSET    mdb = 0L;
00542     USHORT *        pD = pData;
00543     st_DBQUERYCTL * pCtl = &DB_qctl[hdl];
00544     
00545     FAT_fseek(pCtl->idxfile, pCtl->idx + (entry<<pCtl->step),SEEK_HEAD);
00546     FAT_fread(pCtl->idxfile, (unsigned short *)&mdb, 2);
00547                     
00548     /* Reached top / bottom ? */
00549     if( mdb == 0 ) return FALSE;        
00550     
00551     /* Locate the record. */
00552     FAT_fseek(pCtl->dbfile, mdb, SEEK_HEAD);
00553     
00554     if(pD)
00555     {
00556         *(USHORT*)pD++ = mdb>>16;
00557         *(USHORT*)pD++ = mdb&0xffff;
00558     }
00559     
00560     return( DB__getRecord(pCtl->dbfile, pD) );  
00561 }
00562 
00563 
00564 #pragma CODE_SECTION(DB_queryClose, ".db_code")
00574 BOOL DB_queryClose(DB_HDL hdl)
00575 {
00576     st_DBQUERYCTL * pCtl;
00577     
00578     if(hdl == DB_INVALID_HDL )  return FALSE;
00579     pCtl = &DB_qctl[hdl];
00580     if(pCtl->free == TRUE)      return TRUE;
00581     
00582     FAT_fclose(pCtl->dbfile);       
00583     FAT_fclose(pCtl->idxfile);      
00584 
00585     pCtl->free = TRUE;
00586 
00587     return TRUE;    
00588 }
00589 
00590 
00591 #pragma CODE_SECTION(_query, ".db_code")
00592 // Function queries the specified database by the primary key. It is the
00593 // caller's responsibility to maintain the id integrity.
00594 //
00595 // @param id
00596 //          DB ID.
00597 // @param dbEntry
00598 //          DB data entry.
00599 // @param pData
00600 //          DB record data buffer.
00601 // @param hdl
00602 //          DB query handle.
00603 // @return
00604 //      Valid DB handle if successful, otherwise DB_INVALID_HDL.
00605 //
00606 static DB_HDL _query(DB_ID id, DB_ENTRY dbEntry, DB_DATA * pData, DB_HDL hdl)
00607 {
00608     DB_MDBOFFSET    mdb;
00609     USHORT *        pD = (USHORT*)pData;
00610     unsigned short  entryNum;
00611     unsigned short  ii;
00612     unsigned long   signature;
00613     st_DBQUERYCTL * pCtl;
00614     st_DBINFO *     pInfo;
00615 
00616     pCtl        = &DB_qctl[hdl];
00617     pInfo       = &DB_qinfo[hdl];
00618         
00619     /* Default to SAI entry which takes 64 bits. */
00620     pCtl->step = 2;
00621 
00622     
00623     /* Change to corresponding root DB directory. */
00624     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE) 
00625     {   
00626         pCtl->free = TRUE;      
00627         return DB_INVALID_HDL;
00628     }
00629 
00630     
00631     /* Open SAI file. */
00632     pCtl->idxfile = FAT_fopen(DB__name(id, SAI), rb);
00633 
00634     /* Check SAI file signature for safe. */
00635     FAT_fread(pCtl->idxfile, (unsigned short *)&signature, 2);
00636 
00637     if( signature != DB_SAI_SIGNATURE ) 
00638     {
00639         /* Invalid field access. */
00640         pCtl->free = TRUE;
00641         FAT_fclose(pCtl->idxfile);
00642         return DB_INVALID_HDL;
00643     }
00644     
00645 
00646     /* Check if dbEntry is valid. */
00647     FAT_fseek(pCtl->idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
00648     FAT_fread(pCtl->idxfile, &entryNum, 1);
00649     pInfo->numOfSAIent = entryNum;
00650     if((long)entryNum <= (long)dbEntry)
00651     {
00652         /* Invalid entry. */
00653         pCtl->free = TRUE;
00654         FAT_fclose(pCtl->idxfile);
00655         return DB_INVALID_HDL;
00656     }
00657 
00658 
00659     /* Add signature entry offset and remember current position. */
00660     pCtl->idx = (long)DB_SAIFIRSTENTRY<<2;
00661 
00662     /* Read back the entry pointer. */
00663     FAT_fseek(pCtl->idxfile, (long)(dbEntry + DB_SAIFIRSTENTRY)<<2, SEEK_HEAD);
00664     FAT_fread(pCtl->idxfile, (unsigned short *)&mdb, 2);
00665 
00666     /* Read back the pai pointer. */
00667     FAT_fread(pCtl->idxfile, (unsigned short *)&pCtl->pai, 2);
00668     
00669     if( mdb == 0) 
00670     {       
00671         /* Empty DB. */
00672         pCtl->free = TRUE;
00673         FAT_fclose(pCtl->idxfile);
00674         return DB_INVALID_HDL;
00675     }
00676 
00677     /* Open MDB file. */
00678     pCtl->dbfile = FAT_fopen(DB__name(id, MDB), rb);
00679         
00680     /* Locate the record. */
00681     FAT_fseek(pCtl->dbfile, mdb, SEEK_HEAD);
00682     
00683     if(pD)
00684     {
00685         *(USHORT*)pD++ = mdb>>16;
00686         *(USHORT*)pD++ = mdb&0xffff;
00687     }
00688     
00689     /* Fetch record. */
00690     if( DB__getRecord(pCtl->dbfile, pD) == FALSE ) 
00691     {       
00692         /* No record available. */
00693         pCtl->free = TRUE;
00694         FAT_fclose(pCtl->idxfile);
00695         FAT_fclose(pCtl->dbfile);
00696         return DB_INVALID_HDL;
00697     }
00698 
00699     return hdl;
00700 }
00701 
00702 
00703 #pragma CODE_SECTION (DB_mount, ".dbinit_code")
00714 DB_ID DB_mount(const DB_FNAME name)
00715 {
00716     // CD to corresponding sub-directory.
00717     if(DB__cdDBdir(name) == FALSE ) return DB_INVALID_ID;
00718 
00719     return( DB__register(name, NULL, NULL) );
00720 }
00721 
00722 #pragma CODE_SECTION(DB_insertRecord, ".db_code")
00733 BOOL DB_insertRecord(DB_ID id, const DB_DATA * pData)
00734 {
00735     st_DBINFO       info;
00736     st_DBDINODE *   node;                   /* DB insertion node. */
00737     st_DBDINODE     ditree[DB_MAXDBNODES];  /* DB insertion tree  */
00738     DB_ENTRY        entry;
00739     DB_PAIOFFSET    pai;
00740     DB_MDBOFFSET    mdb;
00741     File *          dbfile;
00742 
00743     /* Check DB attributes for safe. */
00744     if( DB__info(id, &info) == FALSE ) return FALSE;
00745     if( !(info.attribute & DB_ROOT) ) 
00746     {
00747         /* Insertion can only be applied to root DB. */
00748         return FALSE;       
00749     }
00750 
00751 
00752     /* Initialize root node. */
00753     ditree[0].parent =
00754     ditree[0].prev = NULL;
00755     
00756     /* Copy DB node tree over. */
00757     _copyTree(ditree, &DB_idtree.node[id]);
00758 
00759 
00760     /* Form DB insertion data tree. */
00761     _formDataTree(ditree, pData);
00762 
00763 
00764     /* First to check if record already exists. */
00765     if( DB__recordPosition(id, &entry, *(unsigned short **)pData, FALSE) == TRUE ) 
00766     {       
00767         /* Record already exists, error. */
00768         return FALSE;
00769     }
00770 
00771 
00772     /* Always append to the end of MDB file. Let's check MDB file size. */
00773     dbfile = FAT_fopen(DB__name(id, MDB), rb);
00774     mdb = dbfile->size;
00775     FAT_fclose(dbfile);
00776 
00777 
00778     /* Insert record to root SAI. */
00779     pai = 0L;
00780 
00781     /* Add entry to SAI file. */
00782     DB__addSAIentry(id, entry, mdb, pai);
00783 
00784     
00785     /* Set up parent MDB offset. */
00786     ditree[0].mdb = mdb;
00787 
00788 
00789     /* Update all related children database. */
00790     if( info.numOfKeys > 1) 
00791     {
00792         /* Children available, let's do it. */  
00793         node = ditree[0].child;
00794         
00795         while(node->next)
00796         {
00797             _insert2child(node->next);
00798             node = node->next;
00799         }
00800     }
00801 
00802 
00803     /* Finally, write root DB data. */
00804 
00805     dbfile = FAT_fopen(DB__name(id, MDB), ab);
00806     FAT_fwrite(dbfile, (unsigned short *)ditree[0].data, ditree[0].len);
00807     FAT_fclose(dbfile);
00808     
00809     return TRUE;    
00810 }
00811 
00812 #pragma CODE_SECTION(_copyTree, ".db_code") 
00823 static st_DBDINODE * _copyTree(st_DBDINODE * pDstTree, const st_DBIDNODE * pSrcTree)
00824 {
00825     st_DBDINODE * next = pDstTree + 1;
00826 
00827     pDstTree->id = pSrcTree->id;
00828 
00829     /* Check if children present. */
00830     if ( pSrcTree->child ) 
00831     {
00832         pDstTree->child = next;
00833         next->parent = pDstTree;
00834         next->prev = NULL;
00835         next = _copyTree(next, pSrcTree->child );
00836     }
00837     else pDstTree->child = NULL;
00838 
00839 
00840 //DeepB
00841 //Enable recursive parsing of tree nodes
00842 #ifndef USE_DATABASE_HACKS  /* Following code will eat up memory very quickly. */
00843 
00844     /* Check if next node present. */
00845     if ( pSrcTree->next ) 
00846     {
00847         pDstTree->next = next;
00848         next->prev = pDstTree;
00849         next->parent = pDstTree->parent;
00850         next = _copyTree(next, pSrcTree->next );
00851     }
00852     else pDstTree->next = NULL;
00853 
00854 #else   /* Alternative to save memory. */
00855 
00856     /* Check if next node present. */
00857     while ( pSrcTree->next ) 
00858     {
00859         pDstTree->next = next;
00860         next->prev = pDstTree;
00861         next->parent = pDstTree->parent;
00862 
00863         pDstTree = next;
00864 
00865         next++;
00866         pSrcTree = pSrcTree->next;
00867 
00868         /* Do NOT process sub-children, KNOWN PROBLEM.
00869         if ( pSrcTree->child ) 
00870         {
00871             pDstTree->id = pSrcTree->id;
00872             pDstTree->child = next;
00873 
00874             next->parent = pDstTree;
00875             next->prev = NULL;
00876             next = _copyTree(next, pSrcTree->child );
00877         }
00878         else
00879         */
00880         {
00881             pDstTree->id = pSrcTree->id;
00882             pDstTree->child = NULL;         
00883         }
00884     }
00885 
00886     pDstTree->next = NULL;
00887 #endif
00888 
00889     return(next);
00890 }
00891 
00892 #pragma CODE_SECTION(_formDataTree, ".db_code")
00904 static const DB_DATA * _formDataTree(st_DBDINODE * pTree, const DB_DATA * pData)
00905 {
00906     unsigned short ** p;
00907 
00908     p = (unsigned short **)pData;
00909     
00910     pTree->data = *p;   
00911     pTree->len = DB__recordLen(*p);
00912 
00913     p++;
00914 
00915     /* First check children. */
00916     if ( pTree->child ) 
00917     {
00918         p = (unsigned short **)_formDataTree(pTree->child->next, p);
00919     }
00920     
00921     /* Check siblings. */
00922     while( pTree->next )
00923     {
00924         pTree = pTree->next;
00925         pTree->data = *p;
00926         pTree->len = DB__recordLen(*p);
00927 
00928         p++;
00929 
00930         if(pTree->child)
00931         {
00932             p = (unsigned short **)_formDataTree(pTree->child->next, p);
00933         }
00934     }   
00935 
00936     return ((const DB_DATA *)p);    
00937 }
00938 #pragma CODE_SECTION(DB__compare, ".db_code")
00950 short DB__compare(const DB_DATA * pRecord1, const DB_DATA * pRecord2)
00951 {
00952     const unsigned short *  p1;
00953     const unsigned short *  p2;
00954     unsigned short          value1;
00955     unsigned short          value2;
00956 #ifdef SPECIAL_CHAR_FIX
00957     unsigned short byte1H, byte1L, byte2H, byte2L;
00958 #endif
00959 
00960     p1 = (const unsigned short *) pRecord1;
00961     p2 = (const unsigned short *) pRecord2;
00962 
00963     while( 1 ) 
00964     {
00965         if(*p1 == DB_ESCCHAR) p1++;     
00966         if(*p2 == DB_ESCCHAR) p2++;
00967 
00968         if( (*p1 == DB_RECDLMT) || (*p1 == DB_FLDDLMT) )
00969         {       
00970             if( (*p2 == DB_RECDLMT) || (*p2 == DB_FLDDLMT) ) return 0;
00971             else                                             return -1;
00972         }
00973 
00974         if( (*p2 == DB_RECDLMT) || (*p2 == DB_FLDDLMT) )
00975         {       
00976             if( (*p1 == DB_RECDLMT) || (*p1 == DB_FLDDLMT) ) return 0;
00977             else                                             return 1;
00978         }
00979 
00980 #ifdef SPECIAL_CHAR_FIX
00981         byte1L = *p1 & 0xFF;
00982         if ( byte1L < TABLE_SIZE ) byte1L = _2lower(byte1L);        
00983         byte1H = (*p1 >> 8) & 0xFF;
00984         
00985         if ( byte1H < TABLE_SIZE ) byte1H = _2lower(byte1H);
00986         value1 = (byte1H<<8) | byte1L;
00987         
00988         byte2L = *p2 & 0xFF;
00989         if ( byte2L < TABLE_SIZE ) byte2L = _2lower(byte2L);
00990         byte2H = (*p2 >> 8) & 0xFF;
00991 
00992         if ( byte2H < TABLE_SIZE ) byte2H = _2lower(byte2H);
00993         value2 = (byte2H<<8) | byte2L;
00994 #else
00995         value1 = _2lower(*p1);          
00996         value2 = _2lower(*p2);
00997 #endif
00998         
00999         if(value1 > value2)      return 1;
01000         else if(value1 < value2) return -1;
01001         else 
01002         {
01003             /* Points to next data. */
01004             p1++;
01005             p2++;
01006         }
01007     }
01008 }
01009 
01010 #pragma CODE_SECTION(DB__insert2leaf, ".db_code")
01033 DB_MDBOFFSET DB__insert2leaf(   DB_ID               id, 
01034                                 DB_ID               parentId,
01035                                 DB_MDBOFFSET        parentMdb,                           
01036                                 const DB_DATA *     pParentRecord,
01037                                 const DB_DATA *     pRecord,                             
01038                                 DB_RECLEN           len,
01039                                 BOOL                bAlwaysInsert)
01040 {
01041     DB_MDBOFFSET    leafMdb;
01042     DB_MDBOFFSET    leafPai;
01043     DB_PAIOFFSET    newPaiStart;
01044     DB_PAIOFFSET    newPai;
01045     DB_ENTRY        entry;
01046     DB_PAIOFFSET    rdStart;
01047     unsigned short  moduleLen;
01048     
01049     union 
01050     {       
01051         unsigned short      field[DB_MAXFIELDLEN];
01052         
01053         struct 
01054         {
01055             unsigned short  pai[DB_MINPAILEN];
01056             unsigned short  clear[DB_MINPAILEN];
01057         } pai;  
01058     } buf;
01059 
01060     DB_PAIOFFSET    paiOffset;
01061     st_DBPAICTL     control;
01062     unsigned short  ii;
01063     File *          idxfile;
01064     File *          dbfile;
01065     
01066     /* First round, check if record already exists. */
01067     if( DB__recordPosition(id, &entry, pRecord, FALSE) == FALSE)
01068     {
01069         /* Record does not exits, append to MDB file. */
01070         dbfile = FAT_fopen(DB__name(id, MDB), ab);
01071         
01072         leafMdb = dbfile->size;
01073         FAT_fwrite(dbfile, (unsigned short *)pRecord, len);
01074         FAT_fclose(dbfile);
01075 
01076         /* Create a new entry to PAI file. */
01077         leafPai = _createPAIentry(id, parentMdb);
01078 
01079         /* Add entry to SAI file. */
01080         DB__addSAIentry(id, entry, leafMdb, leafPai);
01081 
01082         return leafMdb;
01083     }
01084 
01085 
01086     /* Record exists, all we need to do here is to update the
01087     ** PAI entry if it exists, or create new PAI if it does not 
01088     ** exist.
01089     */
01090 
01091     /* Fetch PAI entry index. */
01092     idxfile = FAT_fopen(DB__name(id, SAI), r_b);
01093     
01094     FAT_fseek(idxfile, ((unsigned long)entry << 2), SEEK_HEAD);
01095     FAT_fread(idxfile, (unsigned short *)&leafMdb, 2);
01096     FAT_fread(idxfile, (unsigned short *)&leafPai, 2);
01097 
01098     if( leafPai == 0L ) 
01099     {
01100         /* PAI does not exist, add a new entry to PAI file. */
01101         leafPai = _createPAIentry(id, parentMdb);
01102             
01103         /* Update PAI entry in SAI file. */
01104         FAT_fseek(idxfile, -2, SEEK_MID);
01105         FAT_fwrite(idxfile, (unsigned short *)&leafPai, 2);
01106         FAT_fclose(idxfile);
01107 
01108         return leafMdb;
01109     }
01110     FAT_fclose(idxfile);
01111     
01112     
01113     /* Record exists and SAI contains a valid PAI entry. We'll check
01114     ** to insert into the existed PAI module. 
01115     */
01116     if( bAlwaysInsert == FALSE ) 
01117     {
01118         /* Check to see if PAI already exists. */
01119         if( _checkPAI(id, leafPai, parentMdb) )
01120         {                   
01121             /* Everything matches, do NOT update. */
01122             return leafMdb;
01123         }
01124     }
01125 
01126     
01127     /* Now to check PAI entry number to see if a new module needs to 
01128     ** be created.
01129     */
01130 
01131     /* Read back control data of the current module. */
01132     idxfile = FAT_fopen(DB__name(id, PAI), r_b);
01133     
01134     /* Points to control data. */
01135     FAT_fseek(idxfile, leafPai - sizeof(st_DBPAICTL), SEEK_HEAD);
01136     FAT_fread(idxfile, (unsigned short *)&control, sizeof(st_DBPAICTL));
01137 
01138     paiOffset = 
01139     newPai = leafPai;           
01140 
01141             
01142     if(control.entryNum == ( (control.dlen - sizeof(st_DBPAICTL) - 2)>>1 ) )
01143     {
01144         /* Entry full, free this entry and move it to the end of file.
01145         **
01146         ** NOTE:
01147         **      There might be a TRAP here, ideally we need to search
01148         **      throught the PAI to see if there is any available entry
01149         **      with a size bigger than the current one. Here we just
01150         **      choose not to search and directly create a new moudle
01151         **      at the end of the PAI file. 
01152         */
01153 
01154         /* Set up PAI clear buffer. */
01155         for(ii = 0; ii < DB_MINPAILEN; ii++) buf.pai.clear[ii] = 0;
01156         
01157         newPaiStart = idxfile->size;
01158 
01159         /* Check if current module is at the file end. If it is, we'll expand
01160         ** current module instead of allocating a new one.
01161         */  
01162         if(newPaiStart == leafPai - sizeof(st_DBPAICTL) + control.dlen)
01163         {
01164             /* At the end of the file. */           
01165             control.dlen += DB_MINPAILEN;
01166 
01167             /* Update module length before moving it. */
01168             FAT_fseek(idxfile, -(long)sizeof(st_DBPAICTL), SEEK_MID);
01169             FAT_fwrite(idxfile, (unsigned short *)&control.dlen, 1); 
01170 
01171                     
01172             /* Clear all the newly-added entries. */
01173             FAT_fseek(idxfile, newPaiStart, SEEK_HEAD);
01174             FAT_fwrite(idxfile, buf.pai.clear, DB_MINPAILEN);
01175         }
01176 
01177         else
01178         {
01179             /* We'll have to allocate a new module. To prevent PAI
01180             ** file gets too much fragmented, set up a flag here to
01181             ** do defragmentation( NOT SUPPORTED. ). 
01182             */
01183             paiOffset = 
01184             newPai    = newPaiStart + sizeof(st_DBPAICTL);;
01185 
01186             FAT_fseek(idxfile, leafPai - sizeof(st_DBPAICTL), SEEK_HEAD);
01187 
01188             /* Read back first block. */
01189             FAT_fread(idxfile, buf.pai.pai, DB_MINPAILEN);
01190             FAT_fseek(idxfile, (long)(-DB_MINPAILEN), SEEK_MID);
01191 
01192             /* Mark this module to be free. */
01193             buf.pai.clear[0] = control.dlen;
01194             buf.pai.clear[1] = PAI_FREE;
01195 
01196 
01197             FAT_fwrite(idxfile, buf.pai.clear, DB_MINPAILEN);
01198 
01199 
01200             /* Restore clear buffer. */
01201             buf.pai.clear[0] = 0;
01202             buf.pai.clear[1] = 0;
01203 
01204 
01205             /* Sets up new entry length. */
01206             buf.pai.pai[0] = control.dlen + DB_MINPAILEN;
01207 
01208             /* Reserve control.dlen. */
01209             moduleLen = buf.pai.pai[0];
01210 
01211 
01212             /* To use the same code as that of direct insertion. We'll 
01213             ** NOT update the entry number here. 
01214             */
01215             //buf.pai.pai[2] = control.entryNum + 1;
01216 
01217             FAT_fseek(idxfile, newPaiStart, SEEK_HEAD);
01218             FAT_fwrite(idxfile, buf.pai.pai, DB_MINPAILEN);
01219 
01220             newPaiStart += DB_MINPAILEN;
01221 
01222             rdStart = leafPai - sizeof(st_DBPAICTL) + DB_MINPAILEN;
01223 
01224             control.dlen -= DB_MINPAILEN;               
01225                     
01226             while(control.dlen)
01227             {
01228                 FAT_fseek(idxfile, rdStart, SEEK_HEAD);
01229                 FAT_fread(idxfile, buf.pai.pai, DB_MINPAILEN);
01230 
01231                 FAT_fseek(idxfile, (long)(-DB_MINPAILEN), SEEK_MID);
01232                 FAT_fwrite(idxfile, buf.pai.clear, DB_MINPAILEN);
01233 
01234                 FAT_fseek(idxfile, newPaiStart, SEEK_HEAD);
01235                 FAT_fwrite(idxfile, buf.pai.pai, DB_MINPAILEN);
01236 
01237                 rdStart      += DB_MINPAILEN;
01238                 newPaiStart  += DB_MINPAILEN;
01239 
01240                 control.dlen -= DB_MINPAILEN;
01241             }
01242 
01243             FAT_fseek(idxfile, newPaiStart, SEEK_HEAD);
01244             FAT_fwrite(idxfile, buf.pai.clear, DB_MINPAILEN);
01245             FAT_fclose(idxfile);
01246 
01247             /* Update the SAI file. */
01248             idxfile = FAT_fopen(DB__name(id, SAI), r_b);
01249             FAT_fseek(idxfile, ((unsigned long)entry<<2) + 2, SEEK_HEAD);
01250             FAT_fwrite(idxfile, (unsigned short *)&newPai, 2);
01251             FAT_fclose(idxfile);
01252 
01253             /* Restore control.dlen. */
01254             control.dlen = (unsigned short)moduleLen;
01255 
01256 
01257             /* Reopen the PAI file. */
01258             idxfile = FAT_fopen(DB__name(id, PAI), r_b);
01259         }
01260     }
01261 
01262     /* Let's insert the record PAI here. */
01263 
01264     /* Update entryNum first. */
01265     FAT_fseek(idxfile, newPai - sizeof(st_DBPAICTL) + 2, SEEK_HEAD);
01266 
01267     control.entryNum++;
01268 
01269     FAT_fwrite(idxfile, (unsigned short *)&control.entryNum, 1); 
01270     
01271     // If add2child, always append.
01272     if( bAlwaysInsert == FALSE ) 
01273     {
01274         // This has to be an insertion to root DB.
01275         dbfile = FAT_fopen(DB__name(parentId, MDB), rb);
01276         
01277         /* Check to insert. */
01278         FAT_fseek(idxfile, newPai, SEEK_HEAD);
01279 
01280         while(1)
01281         {
01282             FAT_fread(idxfile, (unsigned short *)&rdStart, 2);
01283     
01284             if(rdStart == 0L) break;
01285     
01286             FAT_fseek(dbfile, rdStart, SEEK_HEAD);
01287             FAT_fread(dbfile, buf.field, DB_MAXFIELDLEN);
01288     
01289             if(DB__compare(buf.field, pParentRecord) < 0)
01290             {
01291                 newPai += 2;
01292             }
01293             else break;
01294         }
01295     
01296         FAT_fclose(dbfile);
01297     }
01298     else  newPai += (control.entryNum-1)*2; // Append.
01299     
01300     FAT_finsert(idxfile, newPai, 
01301                 (unsigned short *)&parentMdb, 2, 
01302                 paiOffset + control.dlen - sizeof(st_DBPAICTL) );
01303                 
01304     FAT_fclose(idxfile);
01305     
01306     return(leafMdb);
01307 }
01308 
01309 #pragma CODE_SECTION(DB__addChildIdx, ".db_code")
01322 BOOL DB__addChildIdx(DB_DATA *      pRecord, 
01323                      DB_FIELDIDX    fldidx, 
01324                      DB_MDBOFFSET   childMdb)
01325 {
01326     unsigned short      ii;
01327     DB_RECLEN           len;
01328     BOOL                bFOUND;
01329     unsigned short *    pD;
01330     unsigned short *    pT;
01331     unsigned short *    pS;
01332     unsigned long       mdb;
01333     unsigned short      buf[4];
01334     
01335     pD = DB__locateField(pRecord, fldidx);
01336     len = DB__recordLen(pRecord);
01337     
01338     bFOUND = FALSE;
01339     while(1)
01340     {
01341         if(*pD == DB_ESCCHAR) pD++;
01342         else if( (*pD==DB_RECDLMT) ||(*pD==DB_FLDDLMT) )  break;
01343         
01344         mdb = (unsigned long)(*pD++)<<16;       
01345         
01346         if(*pD == DB_ESCCHAR) pD++;     
01347         else if( (*pD==DB_RECDLMT) ||(*pD==DB_FLDDLMT) )  break;
01348         
01349         mdb |= (unsigned long)(*pD);
01350 
01351         if( mdb == childMdb) return TRUE;
01352         
01353         else if( (mdb == 0L)&&(bFOUND == FALSE) )
01354         {
01355             pT = pD-1;
01356             bFOUND = TRUE;
01357         }
01358             
01359         pD++;
01360     }
01361     
01362     
01363     pS = buf;
01364     ii = (unsigned long)childMdb>>16;
01365     if( (ii == DB_FLDDLMT)||(ii == DB_RECDLMT)||(ii == DB_BAGDLMT)||(ii == DB_ESCCHAR) ) 
01366     {
01367         *pS++ = DB_ESCCHAR;
01368     }
01369     *pS++ = ii;
01370     ii = childMdb&0x0ffff;
01371     if( (ii == DB_FLDDLMT)||(ii == DB_RECDLMT)||(ii == DB_BAGDLMT)||(ii == DB_ESCCHAR) ) 
01372     {
01373         *pS++ = DB_ESCCHAR;
01374     }
01375     *pS++ = ii;
01376     ii = pS-buf;
01377     
01378     if( (bFOUND == TRUE)&&(ii == 2) )
01379     {
01380         *pT++ = (unsigned long)childMdb>>16;
01381         *pT   = childMdb&0x0ffff;
01382         return TRUE;
01383     }
01384     
01385     // Insert to end of field anyway.
01386     memmove( pD+ii, pD, len-(pD -(unsigned short *)pRecord)+1);
01387     pS = buf;
01388     while(ii--) *pD++ = *pS++;
01389 
01390     return TRUE;    
01391 }
01392 
01393 #pragma CODE_SECTION(_insert2child, ".db_code")
01402 static BOOL _insert2child(st_DBDINODE * node)
01403 {
01404     DB_MDBOFFSET    childMdb;
01405     DB_ENTRY        entry;
01406     DB_FIELDIDX     fldidx;
01407     st_DBDINODE *   tmpNode;
01408     File *          file;
01409 
01410     if(node->child)
01411     {       
01412         /* Parent MDB offset value shall be set here. */
01413 
01414         /* First to check if record already exists. */
01415         if( DB__recordPosition(node->id, &entry, node->data, FALSE) == TRUE ) 
01416         {       
01417             /* Record already exists. */
01418             file = FAT_fopen(DB__name(node->id, SAI), rb);
01419             FAT_fseek(file, (long)entry<<2, SEEK_HEAD);
01420             FAT_fread(file, (unsigned short *)&node->mdb, 2);
01421             FAT_fclose(file);
01422         }
01423         else
01424         {
01425             /* Record does not exist. */
01426             file = FAT_fopen(DB__name(node->id, MDB), rb);
01427             
01428             /* New record always gets appended to the end of file. */
01429             node->mdb = file->size;
01430             FAT_fclose(file);
01431         }
01432 
01433         tmpNode = node->child;
01434         
01435         while(tmpNode->next)
01436         {       
01437             _insert2child(tmpNode->next);
01438             tmpNode = tmpNode->next;
01439         }
01440 
01441         // All its children have been processed, now to process child DB itself. 
01442         childMdb = DB__insert2leaf( node->id, 
01443                                     node->parent->id,
01444                                     node->parent->mdb,
01445                                     node->parent->data,
01446                                     node->data,
01447                                     node->len,
01448                                     FALSE);
01449 
01450         fldidx = DB__fieldIndex(node->id);
01451 
01452         /* Update parent field value. */
01453         DB__addChildIdx(node->parent->data, fldidx, childMdb);
01454     }
01455     else
01456     {
01457         /* DB does not have any children, insert it. */
01458         childMdb = DB__insert2leaf( node->id, 
01459                                     node->parent->id,
01460                                     node->parent->mdb,
01461                                     node->parent->data,
01462                                     node->data,
01463                                     node->len,
01464                                     FALSE);
01465 
01466         fldidx = DB__fieldIndex(node->id);
01467         
01468 
01469         /* Update parent field value. */
01470         DB__addChildIdx(node->parent->data, fldidx, childMdb);
01471 
01472         /* Check to reset parent record data length. */
01473         node->parent->len = DB__recordLen(node->parent->data);
01474     }
01475     
01476     return TRUE;    
01477 }
01478 
01479 
01480 #pragma CODE_SECTION(DB_init, ".dbinit_code")
01487 BOOL DB_init(void)
01488 {
01489     unsigned short      ii;
01490     
01491     /* Clear database regisration table. */
01492     for ( ii = 0; ii < DB_MAX_ID; ii++ ) DB_registration[ii].fname = NULL;
01493     
01494     /* Reset database ID tree. */
01495     DB_idtree.counter = 0;  
01496 
01497     /* Reset all available query controls. */
01498     for( ii = 0; ii < DB_OPENMAX; ii++ ) DB_qctl[ii].free = TRUE;
01499 
01500     /* Initialize DB tree globale controls. */  
01501     //DB_ctl.actvHdl = DB_INVALID_HDL;
01502     
01503     return TRUE;
01504 }
01505 
01506 
01507 #pragma CODE_SECTION(DB_info, ".db_code")
01508 #if 1
01517 st_DBINFO * DB_info(DB_HDL hdl)
01518 {
01519     return(&DB_qinfo[hdl]);
01520 }
01521 
01522 #else
01533 BOOL DB_info(DB_ID id, st_DBINFO * pInfo)
01534 {
01535     File *          file;
01536     
01537     pInfo->id = id;
01538     
01539     /* Check to see if id points to a virtual DB. */
01540     if( DB_registration[id].fname == NULL ) 
01541     {
01542         pInfo->bVirtual = TRUE;
01543         
01544         /* Virtual DB, access through its parent. */
01545         id = DB_idtree.node[id].parent->id;
01546     }
01547     else pInfo->bVirtual = FALSE;
01548     
01549     
01550     if( DB__info(id, pInfo) == TRUE )
01551     {
01552         /* Read back SAI entry number. */
01553         if( (file = FAT_fopen(DB__name(id, SAI), rb) ) == NULL ) return FALSE;
01554 
01555         FAT_fseek(file, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);   
01556         FAT_fread(file, &pInfo->numOfSAIent, 1);
01557         FAT_fclose(file);
01558         return TRUE;
01559     }
01560     else return FALSE;
01561 }
01562 #endif
01563 
01564 
01565 #pragma CODE_SECTION(DB__info, ".db_code")
01577 BOOL DB__info(DB_ID id, st_DBINFO * pInfo)
01578 {
01579     File *              file;
01580     st_DBHEADER         header;
01581     unsigned long       signature;      
01582 
01583     #if 1
01584     pInfo->id = id;
01585     
01586     /* Check to see if id points to a virtual DB. */
01587     if( DB_registration[id].fname == NULL ) 
01588     {
01589         pInfo->bVirtual = TRUE;
01590         
01591         /* Virtual DB, access through its parent. */
01592         id = DB_idtree.node[id].parent->id;
01593     }
01594     else pInfo->bVirtual = FALSE;
01595     #endif
01596     
01597     // Change to corresponding root DB directory. all files contained
01598     // in this directory.
01599     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE)   return FALSE;
01600     
01601     if( (file = FAT_fopen(DB__name(id, MDB), rb) ) == NULL ) return FALSE;
01602     
01603     if( FAT_fread(file, (unsigned short *)&header, sizeof(st_DBHEADER)) 
01604             != sizeof(st_DBHEADER) ) RETURN_ERROR;
01605 
01606     FAT_fseek(file, header.len - 2, SEEK_HEAD);
01607     FAT_fread(file, (unsigned short *)&signature, 2);
01608 
01609     /* Check signature here for safe. */
01610     if( signature != DB_HEADER_SIGNATURE ) RETURN_ERROR;
01611 
01612     /* Copy information over. */
01613     pInfo->attribute = header.attribute;
01614     pInfo->numOfFields = header.numOfFields;
01615     pInfo->numOfKeys = header.numOfKeys;
01616     pInfo->status = header.status;
01617     pInfo->ptrXIM = ((long)header.ptrXIMhi<<16)|header.ptrXIMlo;
01618     
01619     FAT_fclose(file);   
01620 
01621     return TRUE;    
01622 }
01623 
01624 #pragma CODE_SECTION(DB_childID, ".db_code")
01635 DB_ID DB_childID(DB_ID rootID, DB_FIELDIDX fldIdx)
01636 {
01637     st_DBIDNODE * node;
01638 
01639     node = &DB_idtree.node[rootID];
01640     
01641     node = node->child;
01642     while(fldIdx--)
01643     {
01644         node = node->next;
01645     }
01646     
01647     return node->id;    
01648 }
01649 
01650 #pragma CODE_SECTION(DB_parentID, ".db_code")
01659 DB_ID DB_parentID(DB_ID id)
01660 {
01661     st_DBIDNODE * node;
01662 
01663     node = &DB_idtree.node[id];
01664     
01665     /* Traverse to parent. */
01666     if(node->parent) node = node->parent;
01667     
01668     return node->id;    
01669 }
01670 
01671 #pragma CODE_SECTION(DB__rootID, ".db_code")
01680 DB_ID DB__rootID(DB_ID id)
01681 {   
01682     st_DBIDNODE * node;
01683 
01684     node = &DB_idtree.node[id];
01685     
01686     /* Traverse to root. */
01687     while(node->parent) node = node->parent;
01688     
01689     return node->id;    
01690 }
01691 
01692 #pragma CODE_SECTION(DB_getSaiByMdb, ".db_code")
01703 DB_ENTRY DB_getSaiByMdb(ULONG mdb, DB_ID id)
01704 {
01705     File *          idxfile;
01706     unsigned long   signature;
01707     DB_ENTRY        entry;
01708     unsigned short  entryNum;
01709     ULONG           mdbEnt[2];
01710     
01711     /* Change to corresponding root DB directory. */
01712     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE) 
01713     {   
01714         return DB_INVALID_ENTRY;
01715     }
01716 
01717     
01718     /* Open SAI file. */
01719     idxfile = FAT_fopen(DB__name(id, SAI), rb);
01720 
01721     /* Check SAI file signature for safe. */
01722     FAT_fread(idxfile, (unsigned short *)&signature, 2);
01723 
01724     if( signature != DB_SAI_SIGNATURE ) 
01725     {
01726         /* Invalid field access. */
01727         FAT_fclose(idxfile);
01728         return DB_INVALID_ENTRY;
01729     }
01730     
01731 
01732     /* Check if dbEntry is valid. */
01733     FAT_fseek(idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
01734     FAT_fread(idxfile, &entryNum, 1);
01735 
01736     FAT_fseek(idxfile, (unsigned long)(DB_SAIFIRSTENTRY)<<2, SEEK_HEAD);
01737     entry = 0;
01738     while(entryNum--)
01739     {
01740         FAT_fread(idxfile, (unsigned short *)&mdbEnt, 4);
01741         if(mdbEnt[0] == mdb) 
01742         {
01743             FAT_fclose(idxfile);
01744             return entry;
01745         }
01746         entry++;
01747     }
01748     
01749     FAT_fclose(idxfile);
01750     return DB_INVALID_ENTRY;    
01751 }
01752 
01753 #pragma CODE_SECTION(DB_getMdbByRecord, ".db_code")
01763 DB_MDBOFFSET DB_getMdbByRecord(DB_ID id, const unsigned short * pData)
01764 {
01765     unsigned short  field[DB_MAXFIELDLEN];
01766     DB_ENTRY        entry;          /* SAI entry number. */
01767     DB_MDBOFFSET    offset;         /* File offset in MDB file. */
01768     File *          idxfile;
01769     File *          dbfile;
01770 
01771     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE)   return 0;
01772     
01773     /* Open MDB and SAI files. */
01774     idxfile = FAT_fopen(DB__name(id, SAI), rb);
01775     dbfile  = FAT_fopen(DB__name(id, MDB), rb);
01776     
01777     
01778     /* Points to the first valid entry. */
01779     entry = DB_SAIFIRSTENTRY;
01780 
01781 
01782     /* SAI entry takes 64bits, 4 words per entry. */
01783     FAT_fseek(idxfile, (long)entry << 2, SEEK_HEAD);
01784     FAT_fread(idxfile, (unsigned short *)&offset, 2);
01785 
01786     while(offset)
01787     {
01788         unsigned short len;
01789         
01790         FAT_fseek(dbfile, offset, SEEK_HEAD);
01791         FAT_fread(dbfile, field, DB_MAXFIELDLEN);
01792 
01793         /* Only compare the primary field. */
01794         if(len = DB__getField(field, 0, field))
01795         {
01796             unsigned short * pS = (unsigned short *)field;
01797             unsigned short * pD = (unsigned short *)pData;
01798             do
01799             {
01800                 if(*pS++ != *pD++) break;
01801         
01802             } while(--len);
01803             
01804             if( 0 == len )
01805             {
01806                 /* Record found!. */
01807                 FAT_fclose(idxfile);
01808                 FAT_fclose(dbfile);
01809     
01810                 return offset;
01811             }
01812         }
01813 
01814         entry++;
01815 
01816         /* Skip PAI entry. */
01817         FAT_fseek(idxfile, 2, SEEK_MID);            
01818         FAT_fread(idxfile, (unsigned short *)&offset, 2);
01819     }
01820 
01821 
01822     /* Record does not exist. */
01823     FAT_fclose(idxfile);
01824     FAT_fclose(dbfile);
01825 
01826     // Not found.
01827     return 0L;  
01828 }
01829 #pragma CODE_SECTION(DB_getField, ".db_code")
01845 
01846 DB_FIELDLEN DB_getField(    const DB_DATA * pRecord, 
01847                             DB_FIELDIDX     fldIdx, 
01848                             DB_DATA *       pData,
01849                             st_DBINFO *     pInfo)
01850 {
01851     st_DBIDNODE *       node;
01852     DB_ID               tmpid;
01853     DB_MDBOFFSET        childMdb;
01854     File *              file;
01855     unsigned short      ii;
01856     unsigned short      record[DB_MAXRECLEN];
01857     
01858     if(NULL == pData) return 0;
01859     
01860     ii = DB__getField(pRecord, fldIdx, pData);
01861     
01862     if( (0==fldIdx)||(0==ii)||(fldIdx >= pInfo->numOfKeys) ) return ii;
01863     
01865     // Currently only the first child MDB in field is fetched, this is 
01866     // definitely a hole in algorithm, since there might be more than
01867     // one there. I simply don't worry about it now because this
01868     // feature is not used anyway.
01870     childMdb = ((unsigned long)(*(unsigned short *)pData)<<16)|(*((unsigned short *)pData+1));
01871     
01872     // Virtual DB, no data available.
01873     //if(pInfo->bVirtual == TRUE) return 0; 
01874     
01875     /* Get field DB id. */
01876     //node = DB_idtree.node[pInfo->id].child; 
01877     node = DB_idtree.node[DB_rootID(pInfo->id)].child; 
01878     for(ii = 0; ii < fldIdx; ii++ ) node = node->next;
01879     
01880     tmpid = node->id;
01881 
01882     DB__cdDBdir(DB__name(DB__rootID(tmpid), MDB));
01883     
01884     /* Open child DB MDB file. */
01885     file = FAT_fopen(DB__name(tmpid, MDB), rb);
01886 
01887     /* Seek to offset. */
01888     FAT_fseek(file, childMdb, SEEK_HEAD);
01889     
01890     DB__getRecord(file, record);
01891     FAT_fclose(file);
01892 
01893     return( DB__getField(record, 0, pData) );
01894 }
01895 
01896 
01897 #pragma CODE_SECTION(DB__getField, ".db_code")
01911 DB_FIELDLEN DB__getField(   const DB_DATA * pRecord, 
01912                             DB_FIELDIDX     fldIdx, 
01913                             DB_DATA *       pData)
01914 {
01915     const unsigned short *  pSrc;
01916     unsigned short *        pDst;
01917     
01918     pSrc = (const unsigned short *)DB__locateField(pRecord, fldIdx); 
01919     
01920     if( NULL == pSrc )
01921     {       
01922         /* Unable to locate the specified field. */
01923         return 0;
01924     }
01925 
01926     
01927     if( (*pSrc == DB_RECDLMT)||(*pSrc == DB_FLDDLMT) )
01928     {       
01929         /* Empty record. */
01930         return 0;
01931     }
01932 
01933 
01934     pDst = (unsigned short *)pData;
01935     /* Start to fetch field. */
01936     while(1) 
01937     {
01938         if( *pSrc == DB_ESCCHAR) 
01939         {
01940             pSrc++;
01941             *pDst++ = *pSrc++;
01942         }
01943         else{
01944             *pDst++ = *pSrc++;
01945         }
01946 
01947         if( (*pSrc == DB_RECDLMT)||(*pSrc == DB_FLDDLMT) ) break;
01948     }
01949     
01950     return (pDst - (unsigned short *)pData);
01951 }
01952 
01953 #pragma CODE_SECTION(DB_dspData, ".db_code")
01966 DB_DSPDATALEN DB_dspData(DB_ID id, DB_DSPDATA pData, DB_DSPDATAIDX idx )
01967 {
01968     File *          file;
01969     unsigned long   pName;
01970     unsigned short  len;
01971 
01972     /* Change to corresponding root DB directory. */
01973     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE) return 0;   
01974 
01975     /* Check to see if id points to a virtual DB. */
01976     if( DB_registration[id].fname == NULL ) 
01977     {
01978         /* Virtual DB, access through its parent. */
01979         id = DB_idtree.node[id].parent->id;
01980     }
01981 
01982     if( (file = FAT_fopen(DB__name(id, MDB), rb) ) == NULL ) return 0;
01983 
01984 
01985     FAT_fseek(file, DB_PNAME_OFFSET + ((long)idx << 2), SEEK_HEAD);
01986     FAT_fread(file, (unsigned short *)&pName, 2);
01987     
01988     FAT_fseek(file, pName, SEEK_HEAD);
01989     FAT_fread(file, pData, 1);
01990     
01991     len = *pData;
01992     FAT_fread(file, pData, len);
01993     
01994     FAT_fclose(file);
01995     
01996     return len; 
01997 }
01998 //#pragma CODE_SECTION(DB_deleteRecord, ".db_code")
01999 #pragma CODE_SECTION(DB_deleteRecord, ".sram0_resident")
02011 BOOL DB_deleteRecord(DB_ID id, DB_ENTRY entry)
02012 {
02013     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE)   return FALSE;
02014     return DB__deleteChildRecord(id, entry);
02015 }
02016 
02017 #pragma CODE_SECTION(DB_deleteRecordByMdb, ".db_code")
02029 BOOL DB_deleteRecordByMdb(DB_ID id, DB_MDBOFFSET mdb)
02030 {
02031     DB_MDBOFFSET offset;
02032     USHORT      entryNum;
02033     DB_ENTRY    entry = 1;
02034     File *      idxfile;
02035     BOOL        ret = FALSE;
02036 
02037     if(DB__cdDBdir(DB__name(DB__rootID(id), MDB)) == FALSE)   return FALSE;
02038     
02039     // Fetch entry number from SAI file.
02040     idxfile = FAT_fopen(DB__name(id, SAI), rb);
02041     FAT_fseek(idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
02042     FAT_fread(idxfile, &entryNum, 1);
02043 
02044     FAT_fseek(idxfile, (unsigned long)(1+DB_SAIFIRSTENTRY)<<2, SEEK_HEAD);
02045     while(entryNum--)
02046     {
02047         if(2!=FAT_fread(idxfile, (unsigned short *)&offset, 2)) break;
02048         if(mdb == offset)
02049         {
02050             ret = TRUE;
02051             break;
02052         }
02053         // Skip the PAI entry.
02054         if(2!=FAT_fread(idxfile, (unsigned short *)&offset, 2)) break;
02055         
02056         entry++;
02057     }
02058     FAT_fclose(idxfile);
02059     
02060     if(TRUE == ret) return DB__deleteChildRecord(id, entry);
02061     
02062     return FALSE;
02063 }
02064 
02065 #pragma CODE_SECTION(DB__deleteChildRecord, ".db_code")
02079 BOOL DB__deleteChildRecord(DB_ID id, DB_ENTRY entry)
02080 {
02081     DB_ID           childID;
02082     st_DBIDNODE *   node;
02083     DB_MDBOFFSET    offset;
02084     DB_PAIOFFSET    pai;
02085     unsigned short  entryNum;
02086     unsigned short  entryLeft;
02087     File *          idxfile;
02088     File *          dbfile;
02089     DB_SAIOFFSET    sai;
02090     DB_FIELDIDX     fldidx;
02091     USHORT          fldlen;
02092     USHORT          usTmp, usLen;
02093     USHORT          buf[DB_MAXRECLEN];
02094     unsigned long   fld[32];// Assuming that one field could hold up to
02095                             // 32 valid offset values.
02096 
02097     // Get MDB offset from SAI file.
02098     idxfile = FAT_fopen(DB__name(id, SAI), r_b);
02099     FAT_fseek(idxfile, (unsigned long)(entry+DB_SAIFIRSTENTRY)<<2, SEEK_HEAD);
02100     FAT_fread(idxfile, (unsigned short *)&offset, 2);
02101 
02102     // Remove SAI entry.
02103     FAT_fseek(idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
02104     FAT_fread(idxfile, &entryNum, 1);
02105 
02106     DB_assert(entryNum, DB__DELETECHILDRECORD);
02107     
02108     /* Decrement entry number. */
02109     FAT_fseek(idxfile, -1, SEEK_MID);
02110     entryNum--;
02111     FAT_fwrite(idxfile, &entryNum, 1);  
02112     
02113     /* Process the rest of the entries. */
02114     usTmp = (unsigned long)(entryNum - entry)<<2;
02115     FAT_fseek(idxfile, (unsigned long)(entry + DB_SAIFIRSTENTRY) << 2, SEEK_HEAD);  
02116     while(usTmp)
02117     {       
02118         /* Skip the current entry which should be deleted. */
02119         FAT_fseek(idxfile, 4, SEEK_MID);
02120 
02121         if(usTmp > DB_MAXRECLEN )   usLen = DB_MAXRECLEN;
02122         else                        usLen = (unsigned short)usTmp;
02123 
02124         FAT_fread(idxfile, (unsigned short *)buf, usLen);
02125         FAT_fseek(idxfile, (long)((long)(-4) - usLen ), SEEK_MID);
02126         FAT_fwrite(idxfile, (unsigned short *)buf, usLen);
02127         usTmp -= usLen;     
02128     }
02129 
02130     buf[0] = buf[1] = buf[2] = buf[3] = 0;
02131 
02132     /* Zero out last entry. */
02133     FAT_fwrite(idxfile, (unsigned short *)buf, 4);
02134     FAT_fclose(idxfile);
02135 
02136     /* Mark entry as deleted. */
02137     dbfile = FAT_fopen(DB__name(id, MDB), r_b);
02138 
02139     // Read back the entire record here.
02140     FAT_fseek(dbfile, offset, SEEK_HEAD);
02141     DB__getRecord(dbfile, (DB_DATA *)buf);
02142 
02143     FAT_fseek(dbfile, offset, SEEK_HEAD);
02144     FAT_fread(dbfile, (unsigned short *)&usTmp, 1);
02145     usTmp |= RECORD_DELETED;
02146     FAT_fseek(dbfile, -1, SEEK_MID);
02147     FAT_fwrite(dbfile, (unsigned short *)&usTmp, 1);
02148     FAT_fclose(dbfile);
02149 
02150 
02151     /* Check all the children database. */
02152     node = &DB_idtree.node[id];
02153     fldidx = 0;
02154 
02155     if(node->child)
02156     {
02157         node = node->child;
02158         
02159         while(node->next)
02160         {
02161             node = node->next;
02162             childID = node->id;
02163 
02164             fldidx++;
02165             
02166             fldlen = DB__getField(buf, fldidx, fld)>>1;
02167             
02168             // Sort all SAIs in field if any.
02169             _sortSAI(fld, fldlen);
02170             
02171             idxfile = FAT_fopen(DB__name(childID, SAI), rb);            
02172             FAT_fseek(idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
02173             FAT_fread(idxfile, &entryNum, 1);
02174 
02175             // Note that entry has to be checked from the end of file to 
02176             // support recursively deleting. 
02177             while( (entryNum) && (fldlen) ) 
02178             {
02179                 entryNum--;
02180                 FAT_fseek(idxfile, ((unsigned long)(entryNum + DB_SAIFIRSTENTRY)<<2), SEEK_HEAD);
02181                 FAT_fread(idxfile, (unsigned short *)&sai, 2);
02182                 FAT_fread(idxfile, (unsigned short *)&pai, 2);
02183                 
02184                 if( sai == fld[fldlen-1])
02185                 {
02186                     fldlen--;
02187 
02188                     // If pai == 0, there is no PAI entries available, does 
02189                     // NOT need to check.
02190                     if(pai) DB__removePAIentry(childID, offset, pai, &entryLeft);
02191                 }
02192                 
02193                 else continue;
02194                 
02195                 // if( (sai != fld[fldlen-1]) || (pai == 0) ) continue;
02196                 // fldlen may have been post decremented already.
02197                 if(pai == 0) continue;
02198 
02199                 if(entryLeft == 0)
02200                 {
02201                     /* Close file before deleting SAI entry. */
02202                     FAT_fclose(idxfile);
02203 
02204                     // The first entry always(?) points to the default empty record,
02205                     // do not delete it even when it is empty since it defaults to
02206                     // have at least one virtual record.                
02207                     if(entryNum != 0)
02208                     {                    
02209                         DB__deleteChildRecord(childID, entryNum);
02210                     }
02211 
02212                     /* Reopen SAI file after deleting. */
02213                     idxfile = FAT_fopen(DB__name(childID, SAI), rb);
02214                 }
02215             }
02216 
02217             /* Close file before return. */
02218             FAT_fclose(idxfile);
02219         }
02220     }
02221 
02222     return TRUE;
02223 }
02224 
02225 #pragma CODE_SECTION(_sortSAI, ".db_code")
02234 static void _sortSAI ( unsigned long * pSAI, USHORT numOfSAI )
02235 {
02236 //DeepB
02237 #ifdef USE_DATABASE_HACKS
02238     BOOL          bSortPending = TRUE;
02239     USHORT        ii;
02240     unsigned long sai;
02241     
02242     if( numOfSAI < 2 ) return;
02243     
02244     while( bSortPending == TRUE )
02245     {
02246         ii = numOfSAI;        
02247         bSortPending = FALSE;
02248         
02249         while(ii > 1)
02250         {
02251             ii--;
02252             
02253             if( (*(pSAI+ii)) <  (*(pSAI+ii-1)) )
02254             {
02255                 // Switch.
02256                 sai = *(pSAI+ii);
02257                 *(pSAI+ii) = *(pSAI+ii-1);
02258                 *(pSAI+ii-1) = sai;
02259                 bSortPending = TRUE;
02260             }        
02261         }    
02262     }
02263 #endif
02264 }
02265 
02266 #pragma CODE_SECTION (DB_creator, ".dbinit_code")
02276 
02277 BOOL DB_creator( BOOL force2create )
02278 {
02279     BOOL    ret = TRUE;
02280     
02281     FAT_cd(strDISKD);
02282     if( FAT_cd(strDBDIR) == FALSE )
02283     {       
02284         if( FAT_mkdir(strDBDIR) == FALSE)   return FALSE;
02285         if( FAT_cd(strDBDIR) == FALSE )     return FALSE;
02286     }
02287     
02288     /* Check to create audio DB. */
02289     ret = _createDB((ULONG)AUDIO_MDB_INIT_TABLE, strAUDIO, force2create);
02290     
02291     /* Check to create PC audio DB. */
02292     if( ret == TRUE )
02293     {       
02294         ret = _createDB((ULONG)PCAUDIO_MDB_INIT_TABLE, strPCAUDIO, force2create);
02295     }
02296 
02297     /* Check to create identified hisi DB. */
02298     if( ret == TRUE )
02299     {       
02300         ret = _createDB((ULONG)IDEDHISI_MDB_INIT_TABLE, strIDEDHISI, force2create);
02301     }
02302     
02303     /* Check to create unidentified hisi DB. */
02304     if( ret == TRUE )
02305     {       
02306         ret = _createDB((ULONG)UNIDHISI_MDB_INIT_TABLE, strUNIDEDHISI, force2create);
02307     }
02308 
02309     /* Check to create unsuccessful hisi DB. */
02310     if( ret == TRUE )
02311     {       
02312         ret = _createDB((ULONG)FAILHISI_MDB_INIT_TABLE, strFAILEDHISI, force2create);
02313     }
02314 
02315     return ret;
02316 }
02317 
02318 
02319 #pragma CODE_SECTION (_createDB, ".dbinit_code")
02333 static BOOL _createDB(  ULONG           dptr,
02334                         const char *    name,
02335                         BOOL            force2create  ) 
02336 {
02337     ULONG       addr;
02338     int         ii;
02339     int         numOfDB;
02340     char        dir[22]; // hard-coded to save stack.
02341     char        fname[22];
02342     char *      pC;
02343     File *      file;
02344     
02345     /* Form DB directory. */
02346     ii = strlen(name) - 4; // strip out the extension.
02347     memcpy(dir, name, ii);
02348     dir[ii] = 0;
02349     
02350     if( FAT_cd(dir) == FALSE )
02351     {
02352         if( FAT_mkdir(dir) == FALSE) return FALSE;      
02353         if( FAT_cd(dir) == FALSE ) return FALSE;
02354     }
02355 
02356     file = FAT_fopen(name, rb);
02357     if( (file == NULL) || ( force2create == TRUE ) ) 
02358     {   
02359         if(file) FAT_fclose(file);
02360         
02361         /* Skip reserved data. */
02362         dptr++; 
02363         
02364         GEN_rdSRAM(dptr++, (USHORT*)&numOfDB, 1);
02365         while(numOfDB--)
02366         {       
02367             /* Fetch file name. */
02368             GEN_readXdata(dptr, (USHORT *)&addr, 2);
02369             dptr += 2;
02370             
02371             /* Packed file name length is hardcoded to 10. !!! */
02372             GEN_readXdata(addr, (USHORT *)fname, 10);       
02373             
02374             /* unpack string. */
02375             GEN_strUnpack((UINT16 *)fname, 10);
02376         
02377             /* Generate mdb file. */
02378             if(_genFile(dptr, fname) == FALSE) return FALSE;
02379             
02380             dptr += 4;          
02381             
02382             /* Generate sai file. */
02383             ii = strlen(fname);
02384             pC = fname+ii-1;
02385             *pC-- = 'i';
02386             *pC-- = 'a';
02387             *pC   = 's';
02388             
02389             if(_genFile(dptr, fname) == FALSE) return FALSE;            
02390             dptr += 4;          
02391             
02392             /* Generate pai file. */
02393             *pC   = 'p';
02394             
02395             if(_genFile(dptr, fname) == FALSE) return FALSE;            
02396             dptr += 4;          
02397         }
02398     }
02399     
02400     if(file) FAT_fclose(file);
02401     
02402     /* Restore to DB directory. */
02403     FAT_cd(strDOTDOT);
02404     
02405     return TRUE;
02406 }
02407 
02408 
02409 #pragma CODE_SECTION (_genFile, ".dbinit_code")
02420 static BOOL _genFile( ULONG dptr, const char * name)
02421 {
02422     BOOL            ret = TRUE;
02423     File *          file;
02424     unsigned short  buf[360];
02425     ULONG           addr;
02426     int             len;
02427 
02428     /* Get data address. */
02429     GEN_readXdata(dptr, (USHORT *)&addr, 2);    
02430     if(addr == 0) return TRUE;
02431         
02432     dptr += 3;
02433         
02434     /* Get data length. */
02435     GEN_readXdata(dptr, (USHORT *)&len, 1);
02436     
02437     DB_assert(len<360, DB_CREATOR);
02438             
02439     file = FAT_fopen(name, wb);
02440     if(file == NULL) return FALSE;
02441     
02442     GEN_readXdata(addr, buf, len);
02443     if( FAT_fwrite(file, buf, len) != len ) ret = FALSE;
02444     
02445     FAT_fclose(file);
02446     return ret;
02447 }
02448 #pragma CODE_SECTION(DB_add2child, ".db_code")
02461 BOOL DB_add2child(  DB_MDBOFFSET    rootMdb,
02462                     DB_ID           childID, 
02463                     const DB_DATA * childRecord)
02464 {
02465     DB_ID               rootID;
02466     st_DBIDNODE *       node;
02467     DB_FIELDIDX         fldidx;
02468     DB_MDBOFFSET        childMdb;
02469     DB_MDBOFFSET        newOffset;
02470     DB_MDBOFFSET        tmpMdb;
02471     DB_RECLEN           originalLen;
02472     DB_RECLEN           childLen;
02473     DB_RECLEN           newLen;
02474     unsigned short      flag;
02475     File *              dbfile;
02476     File *              idxfile;
02477     unsigned short      record[DB_MAXRECLEN];
02478     //unsigned short    childRecord[DB_MAXRECLEN];
02479 
02480     /* Fetch root MDB entry. */
02481     rootID = DB__rootID(childID);
02482 
02483     if(DB__cdDBdir(DB__name(rootID, MDB)) == FALSE)   return FALSE; 
02484     
02485     //idxfile = FAT_fopen(DB__name(rootID, SAI), rb);
02486     //FAT_fseek(idxfile, (unsigned long)(rootEntry+DB_SAIFIRSTENTRY) << 2, SEEK_HEAD);
02487     //FAT_fread(idxfile, (unsigned short *)&mdb, 2);
02488     //FAT_fclose(idxfile);
02489 
02490     /* Fetch root record. */
02491     dbfile = FAT_fopen(DB__name(rootID, MDB), rb);
02492     FAT_fseek(dbfile, rootMdb, SEEK_HEAD);
02493     DB__getRecord(dbfile, record);
02494     FAT_fclose(dbfile);
02495 
02496 
02497     /* Fetch child MDB entry. */
02498     //idxfile = FAT_fopen(DB__name(childID, SAI), rb);
02499     //FAT_fseek(idxfile, (unsigned long)(childEntry+DB_SAIFIRSTENTRY) << 2, SEEK_HEAD);
02500     //FAT_fread(idxfile, (unsigned short *)&newOffset, 2);
02501     //FAT_fclose(idxfile);
02502 
02503     /* Fetch child record. */
02504     //dbfile = FAT_fopen(DB__name(childID, MDB), rb);
02505     //FAT_fseek(dbfile, newOffset, SEEK_HEAD);
02506     //DB__getRecord(dbfile, childRecord);
02507     //FAT_fclose(dbfile);
02508     
02509     /* ID to field index. */
02510     fldidx = DB__fieldIndex(childID);
02511 
02512     originalLen = DB__recordLen(record);
02513     childLen = DB__recordLen(childRecord);
02514     
02515     /* Insert to child. */
02516     childMdb = DB__insert2leaf( childID, 
02517                                 rootID, 
02518                                 rootMdb,
02519                                 record, 
02520                                 childRecord, 
02521                                 childLen, 
02522                                 TRUE);
02523                             
02524     /* Update root DB field value. */
02525     DB__addChildIdx(record, fldidx, childMdb);
02526     
02527     newLen = DB__recordLen(record);
02528         
02529     /* If newLen == originalLen, the original is able to hold the new
02530     ** index without extending record length, we'll just write back the 
02531     ** new record.
02532     */
02533     if(newLen == originalLen) 
02534     {       
02535         dbfile = FAT_fopen(DB__name(rootID, MDB), r_b);
02536         FAT_fseek(dbfile, rootMdb, SEEK_HEAD);
02537         FAT_fwrite(dbfile, (unsigned short *)record, newLen);
02538         FAT_fclose(dbfile);
02539     
02540         return TRUE;    
02541     }
02542     
02543     else
02544     {
02545         /* Mark the original as deleted. */
02546         dbfile = FAT_fopen(DB__name(rootID, MDB), r_b);
02547 
02548         newOffset = dbfile->size;
02549 
02550         FAT_fseek(dbfile, rootMdb, SEEK_HEAD);
02551         FAT_fread(dbfile, (unsigned short *)&flag, 1);
02552         
02553         flag |= RECORD_DELETED;
02554 
02555         FAT_fseek(dbfile, -1, SEEK_MID);
02556         FAT_fwrite(dbfile, (unsigned short *)&flag, 1);
02557 
02558         /* Append new to the end of file. */
02559         FAT_fseek(dbfile, newOffset, SEEK_HEAD);
02560         FAT_fwrite(dbfile, (unsigned short *)record, newLen);
02561         FAT_fclose(dbfile);
02562 
02563         /* Search and replace SAI entry. */
02564         idxfile = FAT_fopen(DB__name(rootID, SAI), r_b);
02565         FAT_fseek(idxfile,(unsigned long)(DB_SAIFIRSTENTRY) << 2,SEEK_HEAD);
02566         while(1)
02567         {
02568             FAT_fread(idxfile, (unsigned short*)&tmpMdb, 2);
02569             DB_assert(tmpMdb != 0, DB_ADD2CHILD);
02570             
02571             if(tmpMdb == rootMdb)
02572             {
02573                 FAT_fseek(idxfile,-2,SEEK_MID);
02574                 FAT_fwrite(idxfile, (unsigned short *)&newOffset, 2);
02575                 break;
02576             }               
02577             // Skip PAI entry.
02578             FAT_fread(idxfile, (unsigned short*)&tmpMdb, 2);
02579         }       
02580         FAT_fclose(idxfile);
02581 
02582         /* Search and replace all children PAIs. */
02583         node = &DB_idtree.node[rootID];
02584         node = node->child;
02585 
02586         while(node->next)
02587         {
02588             _replacePAI(node->next->id, rootMdb, newOffset);
02589             
02590             node = node->next;
02591         }
02592     }
02593     return TRUE;
02594 }
02595 
02596 #pragma CODE_SECTION(_replacePAI, ".db_code") 
02609 static BOOL _replacePAI(    DB_ID           id, 
02610                             DB_MDBOFFSET    oldOffset,  
02611                             DB_MDBOFFSET    newOffset) 
02612 {
02613     DB_MDBOFFSET        mdb;    
02614     DB_PAIOFFSET        offset;
02615     st_DBPAICTL         control;
02616     File *              idxfile;
02617 
02618     idxfile = FAT_fopen(DB__name(id, PAI), r_b);
02619 
02620     offset = DB_PAIHEADERLEN;
02621 
02622     while(1)
02623     {
02624         FAT_fseek(idxfile, offset, SEEK_HEAD);
02625 
02626         if( FAT_fread(idxfile, (unsigned short *)&control, sizeof(st_DBPAICTL)) == 0 ) break;
02627 
02628         
02629         while(control.entryNum--)
02630         {
02631             FAT_fread(idxfile, (unsigned short *)&mdb, 2);
02632 
02633             if(oldOffset == mdb)
02634             {
02635                 FAT_fseek(idxfile, -2, SEEK_MID);
02636                 FAT_fwrite(idxfile, (unsigned short *)&newOffset, 2);
02637             }
02638         }
02639 
02640         offset += control.dlen;
02641     }
02642 
02643     FAT_fclose(idxfile);
02644 
02645     return TRUE;
02646 }
02647 #pragma CODE_SECTION(DB__removePAIentry, ".db_code")
02662 BOOL DB__removePAIentry(    DB_ID               id, 
02663                             DB_MDBOFFSET        entry, 
02664                             DB_PAIOFFSET        pai,
02665                             unsigned short *    pEntryNum)
02666 {   
02667     st_DBPAICTL     control;
02668     DB_PAIOFFSET    rdstart;
02669     DB_PAIOFFSET    wrstart;
02670     unsigned short  dataleft;
02671     unsigned short  counter;
02672     unsigned short  rdlen;
02673     unsigned short  wrlen;
02674     unsigned short  ii; 
02675     DB_MDBOFFSET    rdbuf[DB_MAXPAIBUFLEN];
02676     DB_MDBOFFSET    wrbuf[DB_MAXPAIBUFLEN];
02677     DB_MDBOFFSET *  pWr;
02678     File *          idxfile;
02679 
02680     idxfile = FAT_fopen(DB__name(id, PAI), r_b);
02681     FAT_fseek(idxfile, pai - sizeof(st_DBPAICTL), SEEK_HEAD);
02682     FAT_fread(idxfile, (unsigned short *)&control, sizeof(st_DBPAICTL));
02683 
02684     rdstart = pai;
02685     wrstart = pai;
02686     dataleft = control.entryNum;
02687     *pEntryNum = control.entryNum;
02688 
02689     while(dataleft)
02690     {
02691         if(dataleft > DB_MAXPAIBUFLEN)  rdlen = DB_MAXPAIBUFLEN << 1;           
02692         else                            rdlen = dataleft << 1;
02693 
02694         counter = 0;
02695 
02696         FAT_fread(idxfile, (unsigned short *)rdbuf, rdlen);
02697 
02698         pWr = wrbuf;
02699 
02700         for(ii = 0; ii < (rdlen>>1); ii++)
02701         {           
02702             if(rdbuf[ii] != entry)      *pWr++ = rdbuf[ii];
02703             else                        counter++;
02704         }
02705 
02706         wrlen = rdlen - (counter<<1);
02707         *pEntryNum -= counter;
02708 
02709         FAT_fseek(idxfile, wrstart, SEEK_HEAD);
02710         FAT_fwrite(idxfile, (unsigned short *)wrbuf, wrlen);
02711 
02712         wrstart += wrlen;
02713 
02714         dataleft -= (rdlen>>1);
02715 
02716         rdstart += rdlen;
02717 
02718         FAT_fseek(idxfile, rdstart, SEEK_HEAD);
02719     }
02720 
02721 
02722     /* Zero out all free entries. */
02723     if( control.entryNum > *pEntryNum)
02724     {
02725         wrstart = pai + ( (long)(*pEntryNum) << 1 );
02726 
02727         dataleft = (control.entryNum - *pEntryNum) << 1;
02728 
02729         for(ii = 0; ii < DB_MAXPAIBUFLEN; ii++) wrbuf[ii] = 0L;
02730 
02731         while(dataleft)
02732         {
02733             if(dataleft > (DB_MAXPAIBUFLEN<<1)) wrlen = (DB_MAXPAIBUFLEN<<1);
02734             else                                wrlen = dataleft;
02735         
02736             FAT_fseek(idxfile, wrstart, SEEK_HEAD);
02737             FAT_fwrite(idxfile, (unsigned short *)wrbuf, wrlen);
02738 
02739             wrstart += wrlen;
02740             dataleft -= wrlen;
02741         }
02742     }
02743 
02744 
02745     /* Update entryNum. */
02746     if(*pEntryNum)
02747     {
02748         FAT_fseek(idxfile, pai - sizeof(st_DBPAICTL) + 2, SEEK_HEAD);
02749         FAT_fwrite(idxfile, pEntryNum, 1);  
02750     }
02751     else
02752     {       
02753         /* Mark this module to be free. */
02754         FAT_fseek(idxfile, pai - sizeof(st_DBPAICTL) + 1, SEEK_HEAD);
02755         control.flag |= PAI_FREE;
02756 
02757         FAT_fwrite(idxfile, (unsigned short *)&control.flag, 1);
02758         FAT_fwrite(idxfile, pEntryNum, 1);
02759     }
02760 
02761     FAT_fclose(idxfile);
02762     
02763     return TRUE;
02764 }
02765 
02766 #pragma CODE_SECTION (DB__register, ".dbinit_code")
02779 DB_ID DB__register(const DB_FNAME name, st_DBIDNODE * parent, st_DBIDNODE * prev )
02780 {
02781     File *              file;   
02782     st_DBHEADER         header;
02783     DB_ID               id, tmpid;
02784     st_DBIDNODE *       prevnode;
02785     char                tmpname[DB_MAXLFN];
02786     char *              pC;
02787     unsigned short      tmp;
02788     
02789 #ifdef DB_REGIST2SRAM
02790     unsigned long       pBuf[64]; // support up to 16 children per DB.
02791     unsigned long *     pp;
02792     unsigned long       dname;
02793 #else
02794     DB_FNAME            dname;
02795     unsigned long *     pp; 
02796 #endif
02797     unsigned short      ii;
02798     unsigned long       signature;
02799 
02800 
02801     if( (file = FAT_fopen(name, rb)) == NULL ) return DB_INVALID_ID;
02802 
02803     /* Check header file signature. */
02804     if( FAT_fread(file, (unsigned short *)&header, sizeof(st_DBHEADER)) 
02805             != sizeof(st_DBHEADER) )    RETURN_ERROR_DB;
02806 
02807     /* Seek to fetch signature. */
02808     FAT_fseek(file, header.len - 2, SEEK_HEAD);
02809     FAT_fread(file, (unsigned short *)&signature, 2);
02810     if( signature != DB_HEADER_SIGNATURE ) RETURN_ERROR_DB;
02811 
02812 
02813     /* Register database and all its children if any, build the ID tree. */
02814 #ifdef DB_REGIST2SRAM
02815 
02816     /* Allocate header file name buffer. */
02817     ii = strlen(name);  
02818     dname = GEN_malloc( ii + 1 );   
02819     GEN_wrSRAM(dname, (unsigned short *)name, ii+1);    
02820     
02821     /* Register database ID. */
02822     id = DB_idtree.node[DB_idtree.counter].id = DB_idtree.counter;  
02823     
02824     //DB_assert (id < DB_MAX_ID, DB__REGISTER);
02825     if(id >= DB_MAX_ID)
02826     {
02827         SYS_die(DB__REGISTER);
02828     }
02829     
02830     /* Register this id. */
02831     DB_registration[id].fname = dname;
02832     DB_registration[id].len = ii;
02833 
02834 #else   
02835     /* Allocate header file name buffer. */
02836     dname = (DB_FNAME)malloc( strlen(name) + 1 );   
02837     strcpy((char *)dname, (char *)name);
02838 
02839     /* Register database ID. */
02840     id = DB_idtree.node[DB_idtree.counter].id = DB_idtree.counter;
02841 
02842     /* Register this id. */
02843     DB_registration[id].fname = dname;
02844     DB_registration[id].len = strlen(dname);
02845 #endif
02846 
02847     DB_idtree.counter++;
02848 
02849     /* Always put the newly-registered at last. */
02850     DB_idtree.node[id].next = NULL;
02851     
02852     /* Only register root database here. */
02853     DB_idtree.node[id].parent = parent;
02854 
02855     /* Set up previous sibling. */
02856     DB_idtree.node[id].prev = prev;
02857 
02858     if( prev ) prev->next = &DB_idtree.node[id];
02859 
02860     /* Set up child default to NULL. */
02861     DB_idtree.node[id].child = NULL;
02862     
02863     
02864     /* Check to see if children available. */
02865     if(header.numOfKeys > 1 )
02866     {   
02867         /* First child. */
02868         DB_idtree.node[id].child = &DB_idtree.node[id+1];
02869         
02870         /* First child will always be a virtual DB. */
02871         DB_registration[id+1].fname = NULL;
02872 
02873         DB_registration[id+1].len = 0;
02874 
02875         DB_idtree.node[id+1].id = id+1;
02876 
02877         DB_idtree.counter++;
02878 
02879         /* Always put the newly-registered at last. */
02880         DB_idtree.node[id+1].next = NULL;
02881         
02882         /* Only register root database here. */
02883         DB_idtree.node[id+1].parent = &DB_idtree.node[id];
02884 
02885         /* Set up previous sibling. */
02886         DB_idtree.node[id+1].prev = NULL;
02887 
02888         /* Set up child default to NULL. */
02889         DB_idtree.node[id+1].child = NULL;              
02890         
02891         /* Points to first child. */
02892         prevnode = &DB_idtree.node[id+1];;
02893         
02894         /* Allocate memory to read back file name pointers. */
02895         ii = (header.numOfKeys+1)<<1;
02896 
02897 #ifdef DB_REGIST2SRAM
02898         pp = pBuf;
02899 #else
02900         if ( (pp = (unsigned long *)malloc( ii * sizeof(unsigned long))) 
02901                 == NULL ) RETURN_ERROR_DB;
02902 #endif
02903 
02904         ii <<= 1;
02905 
02906         FAT_fseek(file, sizeof(st_DBHEADER), SEEK_HEAD);
02907         if( FAT_fread(file, (unsigned short *)pp, ii ) != ii ) RETURN_ERROR_DB;
02908 
02909         /* Skip database name, database parent file name and first child. */
02910         pp += 5; 
02911         
02912         /* Register all its children if any. */
02913         for( ii = 0; ii < header.numOfKeys - 1; ii++ )
02914         {
02915             pC = tmpname;
02916 
02917             FAT_fseek(file, *pp, SEEK_HEAD);
02918 
02919             while(1)
02920             {
02921                 FAT_fread(file, &tmp, 1);
02922 
02923                 /* little endian PC data. */
02924                 *pC++ = tmp >> 8;
02925                 
02926                 *pC++ = tmp & 0x00FF;
02927                 
02928                 if( (tmp & 0x00FF) == 0 ) break;
02929                 
02930                 // Error handling.
02931                 if(pC - tmpname > DB_MAXLFN) RETURN_ERROR_DB;
02932             }
02933             
02934             tmpid = DB__register(tmpname, &DB_idtree.node[id], prevnode); 
02935 
02936             if( tmpid == DB_INVALID_ID )
02937             { 
02938                 RETURN_ERROR_DB;
02939             }
02940             else
02941             {
02942                 prevnode = &DB_idtree.node[tmpid];
02943                 /* Points to next key file name. */
02944                 pp += 2;
02945             }
02946         }
02947     }   
02948 
02949     /* Close DB header file before return. */
02950     FAT_fclose(file);
02951 
02952     /* Write ID back to header file. */
02953 #if 0
02954     file = FAT_fopen(name, r_b);
02955     FAT_fseek(file, DB_ID_OFFSET, SEEK_HEAD);
02956     FAT_fwrite(file, &id, 1);
02957     FAT_fclose(file);
02958 #endif
02959 
02960     return id;
02961 }
02962 
02963 #pragma CODE_SECTION(DB__recordPosition, ".db_code")
02979 BOOL DB__recordPosition(    DB_ID               id, 
02980                             DB_ENTRY *          pPosition, 
02981                             const DB_DATA *     pRecord,
02982                             BOOL                bIgnoreRule )
02983 {
02984     unsigned short  field[DB_MAXFIELDLEN];
02985     DB_ENTRY        entry;          /* SAI entry number. */
02986     DB_MDBOFFSET    offset;         /* File offset in MDB file. */
02987     short           comp;           /* Field compare result. */
02988     File *          idxfile;
02989     File *          dbfile;
02990 
02991     /* Open MDB and SAI files. */
02992     idxfile = FAT_fopen(DB__name(id, SAI), rb);
02993     dbfile  = FAT_fopen(DB__name(id, MDB), rb);
02994     
02995     
02996     /* Points to the first valid entry. */
02997     entry = DB_SAIFIRSTENTRY;
02998 
02999 
03000     /* SAI entry takes 64bits, 4 words per entry. */
03001     FAT_fseek(idxfile, (long)entry << 2, SEEK_HEAD);
03002     FAT_fread(idxfile, (unsigned short *)&offset, 2);
03003 
03004     while(offset)
03005     {
03006         FAT_fseek(dbfile, offset, SEEK_HEAD);
03007         FAT_fread(dbfile, field, DB_MAXFIELDLEN);
03008 
03009         /* Only compare the primary field. */
03010         comp = DB__compare(field, (unsigned short *)pRecord );
03011 
03012         if( comp == 0)
03013         {
03014             /* Record found!. */
03015             FAT_fclose(idxfile);
03016             FAT_fclose(dbfile);
03017 
03018             *pPosition = entry;
03019             return TRUE;
03020         }
03021         else if (comp < 0)
03022         {
03023             /* ASSUMPTIION:
03024             ** If data under this rule are not presorted, this rule must 
03025             ** support multiple record references, which means any record
03026             ** can possibly occur multiple times under this rule. 
03027             */
03028             entry++;
03029 
03030             /* Skip PAI entry. */
03031             FAT_fseek(idxfile, 2, SEEK_MID);            
03032             FAT_fread(idxfile, (unsigned short *)&offset, 2);
03033         }
03034         else
03035         {
03036             if(bIgnoreRule == FALSE) break;
03037             
03038             else
03039             {
03040                 entry++;
03041 
03042                 /* Skip PAI entry. */
03043                 FAT_fseek(idxfile, 2, SEEK_MID);            
03044                 FAT_fread(idxfile, (unsigned short *)&offset, 2);
03045             }
03046         }
03047     }
03048 
03049 
03050     /* Record does not exist. */
03051     FAT_fclose(idxfile);
03052     FAT_fclose(dbfile);
03053 
03054     
03055     /* Sets up position. */
03056     *pPosition = entry;
03057 
03058     return FALSE;   
03059 }
03060 
03061 #pragma CODE_SECTION(DB__recordLen, ".db_code")
03070 DB_RECLEN DB__recordLen(const DB_DATA * pRecord)
03071 {   
03072     unsigned short *    pR;
03073     
03074     pR = (unsigned short *) pRecord;
03075     
03076     if(*pR == DB_RECDLMT)   return 0;
03077 
03078     while( 1 ) 
03079     {
03080         pR++;
03081         
03082         if( *pR == DB_RECDLMT ) 
03083         {
03084             if( *(pR-1) != DB_ESCCHAR ) break;
03085         }       
03086     }
03087     
03088     return (pR-(unsigned short *)pRecord+1);
03089 }
03090 
03091 #pragma CODE_SECTION(DB__name, ".db_code")
03101 DB_FNAME DB__name(DB_ID id, DB_FEXTNAME ext)
03102 {   
03103     unsigned short  len = DB_registration[id].len;
03104 #ifdef DB_REGIST2SRAM
03105     static char     DBnameBUF[DB_MAXLFN]; 
03106     char *          pC = &DBnameBUF[len-1];
03107     GEN_rdSRAM(DB_registration[id].fname, (unsigned short *)DBnameBUF, len+1);  
03108 #else
03109     char *          pC = DB_registration[id].fname;
03110 #endif
03111     
03112     switch( ext ) 
03113     {
03114         case MDB:
03115             *pC-- = 'b';
03116             *pC-- = 'd';
03117             *pC   = 'm';
03118             break;
03119         
03120         case SAI:
03121             *pC-- = 'i';
03122             *pC-- = 'a';
03123             *pC   = 's';
03124             break;
03125     
03126         case PAI:
03127             *pC-- = 'i';
03128             *pC-- = 'a';
03129             *pC   = 'p';
03130             break;
03131     }
03132     
03133 #ifdef DB_REGIST2SRAM
03134     return (DB_FNAME)DBnameBUF;
03135 #else   
03136     return DB_registration[id].fname;
03137 #endif      
03138 
03139 }
03140 #pragma CODE_SECTION(DB__locateField, ".db_code")
03151 DB_DATA * DB__locateField(const DB_DATA * pRecord, DB_FIELDIDX fldIdx)
03152 {
03153 
03154     const unsigned short *  pSrc;
03155     unsigned short          count;
03156     
03157     count = 0;
03158     
03159     /* Skip the record flag. */
03160     pSrc = (unsigned short *)pRecord + 1;
03161 
03162     if( fldIdx != 0 )
03163     {
03164         while( 1 ) 
03165         {   
03166             if(*pSrc == DB_ESCCHAR) pSrc += 2;
03167             
03168             if(*pSrc == DB_RECDLMT) 
03169             {               
03170                 /* End of record, field not found. */
03171                 return NULL;
03172             }
03173     
03174             if(*pSrc == DB_FLDDLMT) 
03175             {               
03176                 /* Field detected. */
03177                 count++;
03178                 
03179                 if( count == fldIdx ) 
03180                 {
03181                     pSrc++;
03182                     break;
03183                 }
03184             }
03185             
03186             pSrc++;
03187         }
03188     }
03189     
03190     return((DB_DATA *)pSrc);
03191 }
03192 
03193 
03194 #pragma CODE_SECTION(_checkPAI, ".db_code")
03208 static DB_PAIOFFSET _checkPAI(  DB_ID               id, 
03209                                 DB_PAIOFFSET        pai, 
03210                                 DB_MDBOFFSET        mdb )
03211 {
03212 
03213     DB_PAIOFFSET    matchPai;
03214     DB_MDBOFFSET    matchMdb;
03215     File *          idxfile;
03216 
03217     matchPai = pai;
03218 
03219     idxfile = FAT_fopen(DB__name(id, PAI), rb);
03220     FAT_fseek(idxfile, pai, SEEK_HEAD);
03221     FAT_fread(idxfile, (unsigned short *)&matchMdb, 2); 
03222     
03223     while(matchMdb)
03224     {
03225         if(matchMdb == mdb) 
03226         {           
03227             FAT_fclose(idxfile);
03228             return matchPai;
03229         }
03230         else matchPai += 2;
03231 
03232         FAT_fread(idxfile, (unsigned short *)&matchMdb, 2); 
03233     }
03234 
03235     FAT_fclose(idxfile);
03236     
03237     /* No match found. */
03238     return 0L;
03239 }
03240 
03241 #pragma CODE_SECTION(_createPAIentry, ".db_code")
03252 static DB_PAIOFFSET _createPAIentry(    DB_ID               id, 
03253                                         DB_MDBOFFSET    parentMdb )
03254 {
03255     File *              file;
03256     unsigned long       offset;
03257     unsigned short      tmp[DB_MINPAILEN];
03258     unsigned short      len;
03259     unsigned short      flag;
03260     unsigned short      ii;
03261     
03262         file = FAT_fopen(DB__name(id, PAI), r_b);
03263         
03264         offset = (long)DB_PAIHEADERLEN;
03265 
03266         /* Search the first empty module if any. */
03267         while(1)
03268         {
03269             /* Seek to next PAI module. */
03270             FAT_fseek(file, offset, SEEK_HEAD);
03271 
03272             if(FAT_fread(file, &len, 1) == 0)
03273             {
03274                 /* End of file. */
03275                 break;
03276             }
03277 
03278             FAT_fread(file, &flag, 1);
03279             if( flag & PAI_FREE)
03280             {
03281                 /* Free PAI found! */
03282 
03283                 /* Clear the free flag. */
03284                 flag &= ~PAI_FREE;
03285 
03286                 FAT_fseek(file, -1, SEEK_MID);
03287                 FAT_fwrite(file, &flag, 1);
03288 
03289                 /* Update entry counter. */
03290                 tmp[0] = 1;
03291 
03292                 FAT_fwrite(file, tmp, 1);
03293                 
03294 
03295 
03296                 /* Skip reserved 3 words. */
03297                 FAT_fseek(file, 3, SEEK_MID);
03298 
03299                 /* Write entry. */
03300                 FAT_fwrite(file, (unsigned short *)&parentMdb, 2);
03301                 FAT_fclose(file);
03302 
03303                 return (offset + sizeof(st_DBPAICTL));
03304             }
03305             offset += len;
03306         }
03307         
03308 
03309         /* Add to end of file. */
03310         FAT_fseek(file, offset, SEEK_HEAD);
03311         
03312 
03313         /* Following to create a new PAI module. */
03314         for( ii = 0; ii < DB_MINPAILEN; ii++) tmp[ii] = 0;
03315 
03316         tmp[0] = DB_MINPAILEN;
03317 
03318         tmp[2] = 1;
03319         
03320         tmp[sizeof(st_DBPAICTL)] = (unsigned short)((long)parentMdb >> 16);
03321 
03322         tmp[sizeof(st_DBPAICTL) + 1] = (unsigned short)(parentMdb & 0xFFFF);
03323 
03324         FAT_fwrite(file, tmp, DB_MINPAILEN);
03325         FAT_fclose(file);
03326 
03327         return (offset + sizeof(st_DBPAICTL));
03328 }
03329 
03330 #pragma CODE_SECTION(DB__getRecord, ".db_code")
03343 BOOL DB__getRecord(File * file, DB_DATA * pData)
03344 {
03345     unsigned short *    p;
03346     unsigned short      len;
03347     
03348     // This is from queryFirst.
03349     if(pData == NULL) return TRUE;
03350     
03351     // Let's split it to speed up, since normally record will be 
03352     // 256 words less.
03353     
03354     p = (unsigned short *)pData;
03355     len = FAT_fread(file, p, DB_MAXRECLEN/2);
03356     
03357     // check for record delimiter, for safe?.
03358     while( 1 ) 
03359     {
03360         if( *p == DB_RECDLMT ) 
03361         {           
03362             if( *(p-1) != DB_ESCCHAR ) return TRUE;
03363         }
03364         p++;
03365         if ( (p-(unsigned short *)pData) >= len ) break;
03366     }
03367 
03368     // Second attempt.
03369     if( len != DB_MAXRECLEN/2) return FALSE;
03370     
03371     p = (unsigned short *)pData+DB_MAXRECLEN/2;
03372     len = FAT_fread(file, p, DB_MAXRECLEN/2);
03373     
03374     // check for record delimiter, for safe?.
03375     while( 1 ) 
03376     {
03377         if( *p == DB_RECDLMT ) 
03378         {           
03379             if( *(p-1) != DB_ESCCHAR ) return TRUE;
03380         }
03381         p++;
03382         if ( (p-(unsigned short *)pData) == len ) break;
03383     }
03384     
03385     return TRUE;    
03386 }
03387 
03388 #pragma CODE_SECTION(DB__fieldIndex, ".db_code")
03396 DB_FIELDIDX DB__fieldIndex(DB_ID id)
03397 {
03398     st_DBIDNODE *   node;
03399     DB_FIELDIDX     fldidx;
03400 
03401     fldidx = 0;
03402     node = &DB_idtree.node[id];
03403     
03404     /* The very first child does not have previous node. */
03405     while(node->prev)
03406     {
03407         fldidx++;
03408         node = node->prev;
03409     }
03410     
03411     return fldidx;
03412 }
03413 
03414 #pragma CODE_SECTION(DB__cdDBdir, ".db_code")
03423 BOOL DB__cdDBdir(const DB_FNAME name)
03424 {
03425     char           dir[DB_MAXLFN];
03426     char *         pD = &dir[0];
03427     const char *   pC = name;
03428     
03429     // DB always resides in NAND flash.
03430     FAT_cd(strDISKD);
03431     
03432     // Always load DB from database directory.
03433     if( FAT_cd(strDBDIR) == FALSE ) return FALSE;
03434     
03435     while(*pC != '.')
03436     {
03437         *pD++ = *pC++;
03438     }
03439     *pD = 0;
03440     
03441     return(FAT_cd(dir));    
03442 }
03443 
03444 #pragma CODE_SECTION(DB__addSAIentry, ".db_code")
03459 BOOL DB__addSAIentry(DB_ID              id, 
03460                      DB_ENTRY           entry,
03461                      DB_MDBOFFSET       mdb,
03462                      DB_PAIOFFSET       pai)
03463 {
03464 
03465     unsigned long   offset[2];
03466     unsigned long   fsize;
03467     unsigned short  entryNum;
03468     File *          idxfile;
03469 
03470     /* Update record number. */
03471     idxfile = FAT_fopen(DB__name(id, SAI), r_b);
03472     fsize = idxfile->size;
03473     
03474     FAT_fseek(idxfile, DB_SAIENTRYNUMOFFSET, SEEK_HEAD);
03475     FAT_fread(idxfile, &entryNum, 1);
03476 
03477     entryNum++;
03478 
03479     FAT_fseek(idxfile, -1, SEEK_MID);
03480     FAT_fwrite(idxfile, &entryNum, 1);
03481 
03482 
03483     /* Load buffer. */
03484     offset[0] = mdb;
03485     offset[1] = pai;
03486 
03487     /* Check to see if there is any free entries. */
03488     if((long)fsize >= (long)((unsigned long)(entryNum + DB_SAIFIRSTENTRY + 1)<<2) ){
03489 
03490         FAT_finsert( idxfile, 
03491                     ( (unsigned long)entry << 2), 
03492                     (unsigned short *)offset, 
03493                     4, fsize);
03494     }
03495     else
03496     {
03497         FAT_finsert(idxfile, 
03498                     ( (unsigned long)entry << 2), 
03499                     (unsigned short *)offset, 
03500                     4, 0L);
03501     }
03502 
03503     FAT_fclose(idxfile);
03504     
03505     return TRUE;
03506 }
03507 
03508 //EOF

Generated on Wed Jan 19 01:12:38 2005 for neuros-firmware by  doxygen 1.3.9.1