From 3eaf79140660d99690b85ea55bbbae24f79ee91f Mon Sep 17 00:00:00 2001 From: ahodgkinson Date: Tue, 28 Mar 2006 19:25:14 +0000 Subject: [PATCH] Added support for large field values (up to 4 GB), async and direct I/O on Linux and Solaris, and performed major code cleanup. git-svn-id: https://svn.code.sf.net/p/flaim/code/trunk@213 0109f412-320b-0410-ab79-c3e0c5ffbbe6 --- flaim/src/checksum.cpp | 523 +- flaim/src/ddcreate.cpp | 956 --- flaim/src/ddprep.cpp | 1577 ---- flaim/src/ecache.h | 4 +- flaim/src/f64bitfh.cpp | 131 +- flaim/src/f64bitfh.h | 2 +- flaim/src/f_coltb1.cpp | 403 - flaim/src/f_nici.cpp | 80 +- flaim/src/f_tocoll.cpp | 772 -- flaim/src/f_uncoll.cpp | 574 -- flaim/src/fbcd.cpp | 372 - flaim/src/fbuff.h | 10 + flaim/src/fcs.h | 26 +- flaim/src/fcs_bios.cpp | 297 - flaim/src/fcs_dis.cpp | 1422 ---- flaim/src/fcs_dos.cpp | 898 -- flaim/src/fcs_fis.cpp | 224 - flaim/src/fcs_ipis.cpp | 264 - flaim/src/fcs_ipos.cpp | 176 - flaim/src/fcs_tcp.cpp | 960 --- flaim/src/fcs_util.cpp | 2458 ------ flaim/src/fcs_wire.cpp | 2444 ------ flaim/src/fdb.cpp | 2 +- flaim/src/fdbcnfig.cpp | 3368 ++++---- flaim/src/fdbcopy.cpp | 4 +- flaim/src/fdbremov.cpp | 50 +- flaim/src/fdbrenam.cpp | 16 +- flaim/src/fddpcode.h | 233 - flaim/src/fdict.cpp | 3882 ++++++++- flaim/src/fdictbld.cpp | 1369 ---- flaim/src/fdir.h | 4 +- flaim/src/fdynsset.h | 7 +- flaim/src/fexpimp.cpp | 599 -- flaim/src/ffilehdl.cpp | 13 - flaim/src/ffilehdl.h | 14 +- flaim/src/ffilehdr.cpp | 770 +- flaim/src/filesys.h | 3053 +++---- flaim/src/fitem.cpp | 64 - flaim/src/flaim.h | 205 +- flaim/src/flaimsys.h | 708 +- flaim/src/flbackup.cpp | 415 +- flaim/src/flblddb.cpp | 2063 ----- flaim/src/flblddbo.cpp | 786 -- flaim/src/flblksum.cpp | 301 - flaim/src/flchkdb.cpp | 5461 +++++++++++-- flaim/src/flchkix.cpp | 2061 ----- flaim/src/flchktr.cpp | 2349 ------ flaim/src/flclose.cpp | 2 +- flaim/src/flconvrt.cpp | 70 +- flaim/src/flcreate.cpp | 81 +- flaim/src/flerror.cpp | 383 +- flaim/src/flerrstr.cpp | 130 - flaim/src/flfixed.h | 16 +- flaim/src/flgdrecs.cpp | 348 - flaim/src/flgethdr.cpp | 64 - flaim/src/flindex.cpp | 28 +- flaim/src/flkeymak.cpp | 543 -- flaim/src/flkeyret.cpp | 61 +- flaim/src/flkeys.cpp | 65 - flaim/src/flmimon.h | 35 +- flaim/src/flmstat.cpp | 4 +- flaim/src/flopen.cpp | 473 +- flaim/src/flrcodes.cpp | 292 - flaim/src/flrddrct.cpp | 65 +- flaim/src/flreduce.cpp | 106 +- flaim/src/flresdrn.cpp | 212 - flaim/src/flsweep.cpp | 16 +- flaim/src/fltrabrt.cpp | 383 - flaim/src/fltrbeg.cpp | 1043 --- flaim/src/fltrcmit.cpp | 581 -- flaim/src/fltrnum.cpp | 173 - flaim/src/flupdate.cpp | 253 +- flaim/src/flverify.cpp | 2515 +++--- flaim/src/fmisc.cpp | 147 +- flaim/src/fnative.cpp | 448 - flaim/src/fntable.cpp | 2 +- flaim/src/fposix.cpp | 202 +- flaim/src/fqcur.cpp | 267 +- flaim/src/fqdecl.cpp | 46 +- flaim/src/fqeval.cpp | 5923 ++++++++------ flaim/src/fqeval2.cpp | 1031 --- flaim/src/fqeval3.cpp | 277 - flaim/src/fqget.cpp | 76 +- flaim/src/fqkeys.cpp | 1599 +++- flaim/src/fqlog.cpp | 8 +- flaim/src/fqopt.cpp | 82 +- flaim/src/fqparse.cpp | 4 +- flaim/src/fqprep.cpp | 114 +- flaim/src/fqread.cpp | 87 +- flaim/src/fqsrch.cpp | 70 +- flaim/src/fqstack.cpp | 100 +- flaim/src/fqtextc.cpp | 1423 ---- flaim/src/fquery.h | 244 +- flaim/src/frec.cpp | 781 +- flaim/src/frestore.cpp | 543 -- flaim/src/frestore.h | 149 - flaim/src/frset.h | 5 +- flaim/src/fsblk_u.cpp | 707 +- flaim/src/fscomblk.cpp | 1341 +-- flaim/src/fsconvrt.cpp | 26 +- flaim/src/fscounts.cpp | 193 +- flaim/src/fscursor.cpp | 488 +- flaim/src/fscursor.h | 326 +- flaim/src/fsdatacu.cpp | 87 +- flaim/src/fsdelelm.cpp | 1534 ++-- flaim/src/fsinselm.cpp | 752 +- flaim/src/fslfileu.cpp | 23 +- flaim/src/fsnext.cpp | 912 ++- flaim/src/fsprev.cpp | 533 +- flaim/src/fsrecget.cpp | 705 +- flaim/src/fsrecupd.cpp | 702 +- flaim/src/fsrefspl.cpp | 682 +- flaim/src/fsrefupd.cpp | 1179 +-- flaim/src/fsrvlock.cpp | 28 +- flaim/src/fsrvlock.h | 31 +- flaim/src/fssearch.cpp | 1163 +-- flaim/src/fssplblk.cpp | 1855 +++-- flaim/src/fstructs.h | 506 +- flaim/src/fsuperfl.cpp | 4 +- flaim/src/fsuperfl.h | 8 +- flaim/src/fsv.h | 13 +- flaim/src/fsv_glob.cpp | 147 - flaim/src/fsv_hdlr.cpp | 4243 ---------- flaim/src/fsv_sctx.cpp | 655 -- flaim/src/fsv_sesn.cpp | 666 -- flaim/src/fsv_sev.cpp | 142 - flaim/src/fsv_tcph.cpp | 535 -- flaim/src/fsv_wire.cpp | 267 - flaim/src/fsysdata.cpp | 435 +- flaim/src/ftk.h | 287 +- flaim/src/ftkmem.h | 2 +- flaim/src/ftkpath.cpp | 44 +- flaim/src/ftkthrd.h | 1 + flaim/src/ftkwptxt.h | 767 -- flaim/src/funicode.cpp | 551 -- flaim/src/fwin.cpp | 137 +- flaim/src/fwpasia.cpp | 1078 --- flaim/src/fwpchar.cpp | 727 -- flaim/src/fwpchrs.cpp | 3166 ------- flaim/src/fwpcoll.cpp | 1784 ---- flaim/src/fxml.h | 10 +- flaim/src/gbinary.cpp | 160 - flaim/src/gd2tree.cpp | 356 - flaim/src/gdcopy.cpp | 233 - flaim/src/gddiff.cpp | 785 -- flaim/src/gddiff.h | 188 - flaim/src/gdfind.cpp | 142 - flaim/src/gdgraft.cpp | 208 - flaim/src/gdmisc.cpp | 571 -- flaim/src/gdpool.cpp | 16 +- flaim/src/gdtrvrs1.cpp | 135 - flaim/src/gnative.cpp | 150 - flaim/src/gnbcd.cpp | 594 -- flaim/src/gnum2txt.cpp | 194 - flaim/src/gtxt2num.cpp | 198 - flaim/src/gunicode.cpp | 162 - flaim/src/imonbase.cpp | 5479 ++++++------- flaim/src/imonfact.cpp | 6 - flaim/src/imonfdb.cpp | 34 +- flaim/src/imonffil.cpp | 34 +- flaim/src/imonfhsh.cpp | 2 +- flaim/src/imonfmgr.cpp | 2 +- flaim/src/imonfsys.cpp | 157 +- flaim/src/imonix.cpp | 5 +- flaim/src/imonlhdr.cpp | 4 +- flaim/src/imonqury.cpp | 52 +- flaim/src/imonrche.cpp | 12 +- flaim/src/imonsche.cpp | 14 +- flaim/src/imonslmg.cpp | 2 +- flaim/src/imonstat.cpp | 4 +- flaim/src/imonutil.cpp | 2 +- flaim/src/kyasia1.cpp | 357 - flaim/src/kyasia2.cpp | 602 -- flaim/src/kybldkey.cpp | 1327 --- flaim/src/kybuild.cpp | 1616 +++- flaim/src/kycollat.cpp | 8550 ++++++++++++++++++- flaim/src/kycompnd.cpp | 824 -- flaim/src/kyeword.cpp | 224 - flaim/src/kyget.cpp | 1795 ++-- flaim/src/kyqsort.cpp | 615 -- flaim/src/kyunlock.cpp | 162 - flaim/src/lock.cpp | 321 +- flaim/src/rcache.cpp | 77 +- flaim/src/recover.cpp | 89 +- flaim/src/rfl.cpp | 15844 +++++++++++++++++++----------------- flaim/src/rfl.h | 135 +- flaim/src/scache.cpp | 362 +- flaim/src/translog.cpp | 50 +- flaim/util/basic_test.cpp | 161 +- flaim/util/dbshell.cpp | 2 +- flaim/util/rebuild.cpp | 2 +- flaim/util/view.cpp | 4 +- flaim/util/viewblk.cpp | 1 - flaim/util/viewfhdr.cpp | 5 +- flaim/util/viewlfil.cpp | 1 - flaim/util/viewlhdr.cpp | 8 +- flaim/util/viewsrch.cpp | 1 - 197 files changed, 53521 insertions(+), 82897 deletions(-) delete mode 100644 flaim/src/ddcreate.cpp delete mode 100644 flaim/src/ddprep.cpp delete mode 100644 flaim/src/f_coltb1.cpp delete mode 100644 flaim/src/f_tocoll.cpp delete mode 100644 flaim/src/f_uncoll.cpp delete mode 100644 flaim/src/fbcd.cpp delete mode 100644 flaim/src/fcs_bios.cpp delete mode 100644 flaim/src/fcs_dis.cpp delete mode 100644 flaim/src/fcs_dos.cpp delete mode 100644 flaim/src/fcs_fis.cpp delete mode 100644 flaim/src/fcs_ipis.cpp delete mode 100644 flaim/src/fcs_ipos.cpp delete mode 100644 flaim/src/fcs_tcp.cpp delete mode 100644 flaim/src/fcs_util.cpp delete mode 100644 flaim/src/fcs_wire.cpp delete mode 100644 flaim/src/fddpcode.h delete mode 100644 flaim/src/fdictbld.cpp delete mode 100644 flaim/src/fexpimp.cpp delete mode 100644 flaim/src/fitem.cpp delete mode 100644 flaim/src/flblddb.cpp delete mode 100644 flaim/src/flblddbo.cpp delete mode 100644 flaim/src/flblksum.cpp delete mode 100644 flaim/src/flchkix.cpp delete mode 100644 flaim/src/flchktr.cpp delete mode 100644 flaim/src/flerrstr.cpp delete mode 100644 flaim/src/flgdrecs.cpp delete mode 100644 flaim/src/flgethdr.cpp delete mode 100644 flaim/src/flkeymak.cpp delete mode 100644 flaim/src/flkeys.cpp delete mode 100644 flaim/src/flrcodes.cpp delete mode 100644 flaim/src/flresdrn.cpp delete mode 100644 flaim/src/fltrabrt.cpp delete mode 100644 flaim/src/fltrbeg.cpp delete mode 100644 flaim/src/fltrcmit.cpp delete mode 100644 flaim/src/fltrnum.cpp delete mode 100644 flaim/src/fnative.cpp delete mode 100644 flaim/src/fqeval2.cpp delete mode 100644 flaim/src/fqeval3.cpp delete mode 100644 flaim/src/fqtextc.cpp delete mode 100644 flaim/src/frestore.cpp delete mode 100644 flaim/src/frestore.h delete mode 100644 flaim/src/fsv_glob.cpp delete mode 100644 flaim/src/fsv_hdlr.cpp delete mode 100644 flaim/src/fsv_sctx.cpp delete mode 100644 flaim/src/fsv_sesn.cpp delete mode 100644 flaim/src/fsv_sev.cpp delete mode 100644 flaim/src/fsv_tcph.cpp delete mode 100644 flaim/src/fsv_wire.cpp delete mode 100644 flaim/src/ftkwptxt.h delete mode 100644 flaim/src/funicode.cpp delete mode 100644 flaim/src/fwpasia.cpp delete mode 100644 flaim/src/fwpchar.cpp delete mode 100644 flaim/src/fwpchrs.cpp delete mode 100644 flaim/src/fwpcoll.cpp delete mode 100644 flaim/src/gbinary.cpp delete mode 100644 flaim/src/gd2tree.cpp delete mode 100644 flaim/src/gdcopy.cpp delete mode 100644 flaim/src/gddiff.cpp delete mode 100644 flaim/src/gddiff.h delete mode 100644 flaim/src/gdfind.cpp delete mode 100644 flaim/src/gdgraft.cpp delete mode 100644 flaim/src/gdmisc.cpp delete mode 100644 flaim/src/gdtrvrs1.cpp delete mode 100644 flaim/src/gnative.cpp delete mode 100644 flaim/src/gnbcd.cpp delete mode 100644 flaim/src/gnum2txt.cpp delete mode 100644 flaim/src/gtxt2num.cpp delete mode 100644 flaim/src/gunicode.cpp delete mode 100644 flaim/src/kyasia1.cpp delete mode 100644 flaim/src/kyasia2.cpp delete mode 100644 flaim/src/kybldkey.cpp delete mode 100644 flaim/src/kycompnd.cpp delete mode 100644 flaim/src/kyeword.cpp delete mode 100644 flaim/src/kyqsort.cpp delete mode 100644 flaim/src/kyunlock.cpp diff --git a/flaim/src/checksum.cpp b/flaim/src/checksum.cpp index 538d88a..8a714ef 100644 --- a/flaim/src/checksum.cpp +++ b/flaim/src/checksum.cpp @@ -24,10 +24,6 @@ #include "flaimsys.h" -#if( defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) - -static unsigned long gv_mmxCheckSumFlag = 1; - #if defined( FLM_WATCOM_NLM) extern void FastBlockCheckSumMMX( @@ -44,7 +40,9 @@ static unsigned long gv_mmxCheckSumFlag = 1; extern unsigned long GetMMXSupported(void); -#else + static unsigned long gv_mmxCheckSumFlag = 1; + +#elif (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) static void FastBlockCheckSumMMX( void * pBlk, @@ -60,6 +58,8 @@ static unsigned long gv_mmxCheckSumFlag = 1; static unsigned long GetMMXSupported(void); + static unsigned long gv_mmxCheckSumFlag = 1; + #endif /******************************************************************** @@ -77,7 +77,7 @@ Ret: 0 or 1 if CPU supports MMX 0x0F 0x95 0xC0 /* setnz al */\ modify exact [EAX EBX ECX EDX]; -#else +#elif (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) unsigned long GetMMXSupported( void) { @@ -208,7 +208,7 @@ Desc: Performs part of the FLAIM block checksum algorithm parm [ESI] [eax] [ebx] [ecx] \ modify exact [eax ebx ecx edx ESI EDI]; -#else +#elif (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) static void FastBlockCheckSumMMX( void * pBlk, @@ -405,84 +405,85 @@ Desc: Performs part of the FLAIM block checksum algorithm 0x89 0x17 /* mov [edi], edx */\ parm [ESI] [eax] [ebx] [ecx] \ modify exact [eax ebx ecx edx ESI EDI]; -#else + +#elif (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) -static void FastBlockCheckSum386( - void * pBlk, - unsigned long *puiChecksum, - unsigned long *puiXORdata, - unsigned long uiNumberOfBytes) -{ - __asm + static void FastBlockCheckSum386( + void * pBlk, + unsigned long *puiChecksum, + unsigned long *puiXORdata, + unsigned long uiNumberOfBytes) { - mov esi, pBlk - - // Load up the starting checksum values into edx (add) and ebx (XOR) - - mov eax, puiChecksum - mov edx, [eax] // Set local add - and edx, 0ffh ;clear unneeded bits - mov eax, puiXORdata - mov ebx, [eax] - and ebx, 0ffh ;clear unneeded bits - mov ecx, uiNumberOfBytes - - ;dl contains the sum to this point - ;ebx contains the xor to this point - 32 bits wide. - ;ecx contains the bytes still left to do - ;esi contains pointer to data to checksum - cmp ecx, 4 - jb SmallStuff - mov edi, ecx - shr ecx, 2 - and edi, 3 -DSSumLoop: - mov eax, [esi] - add esi, 4 - xor ebx, eax - add dl, al - add dh, ah - shr eax, 16 - add dl, al - add dh, ah - dec ecx - jnz DSSumLoop - mov ecx, edi ;load up the rest of the length - ;dl contains half the sum to this point - ;dh contains half the sum to this point - ;ebx contains the xor to this point - 32 bits wide. - ;ecx contains the bytes still left to do - ;esi contains pointer to data to checksum -SmallStuff: - add dl, dh ;get complete sum in dl - mov eax, ebx ;get complete xor in bl - shr eax, 16 - xor bx, ax - xor bl, bh - cmp ecx, 0 ;see if anything left to do - 3 or less bytes - jz Done - -SmallStuffLoop: - mov al, [esi] - inc esi - add dl, al - xor bl, al - dec ecx - jnz SmallStuffLoop -Done: - and edx, 0ffh ;clear unneeded bits - and ebx, 0ffh ;clear unneeded bits - - // Set the return values. - - mov eax, puiChecksum // Address of add result/start - mov [eax], edx - - mov eax, puiXORdata // Address of xor result/start - mov [eax], ebx + __asm + { + mov esi, pBlk + + // Load up the starting checksum values into edx (add) and ebx (XOR) + + mov eax, puiChecksum + mov edx, [eax] // Set local add + and edx, 0ffh ;clear unneeded bits + mov eax, puiXORdata + mov ebx, [eax] + and ebx, 0ffh ;clear unneeded bits + mov ecx, uiNumberOfBytes + + ;dl contains the sum to this point + ;ebx contains the xor to this point - 32 bits wide. + ;ecx contains the bytes still left to do + ;esi contains pointer to data to checksum + cmp ecx, 4 + jb SmallStuff + mov edi, ecx + shr ecx, 2 + and edi, 3 + DSSumLoop: + mov eax, [esi] + add esi, 4 + xor ebx, eax + add dl, al + add dh, ah + shr eax, 16 + add dl, al + add dh, ah + dec ecx + jnz DSSumLoop + mov ecx, edi ;load up the rest of the length + ;dl contains half the sum to this point + ;dh contains half the sum to this point + ;ebx contains the xor to this point - 32 bits wide. + ;ecx contains the bytes still left to do + ;esi contains pointer to data to checksum + SmallStuff: + add dl, dh ;get complete sum in dl + mov eax, ebx ;get complete xor in bl + shr eax, 16 + xor bx, ax + xor bl, bh + cmp ecx, 0 ;see if anything left to do - 3 or less bytes + jz Done + + SmallStuffLoop: + mov al, [esi] + inc esi + add dl, al + xor bl, al + dec ecx + jnz SmallStuffLoop + Done: + and edx, 0ffh ;clear unneeded bits + and ebx, 0ffh ;clear unneeded bits + + // Set the return values. + + mov eax, puiChecksum // Address of add result/start + mov [eax], edx + + mov eax, puiXORdata // Address of xor result/start + mov [eax], ebx + } + return; } - return; -} #endif /****************************************************************************** @@ -491,7 +492,7 @@ Desc: Performs part of the FLAIM block checksum algorithm Note: FastBlockCheckSum will start with the checksum and xordata you pass in. It assumes that the data is already dword aligned. ******************************************************************************/ - +#if (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) void FastBlockCheckSum( void * pBlk, FLMUINT * puiChecksum, @@ -509,111 +510,295 @@ void FastBlockCheckSum( (unsigned long *) puiXORdata, (unsigned long) uiNumberOfBytes); } } +#endif /****************************************************************************** Desc: Sets the global variable to check if MMX instructions are allowed. ******************************************************************************/ -void InitFastBlockCheckSum(void) +#if (defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM) +void InitFastBlockCheckSum( void) { - /* NOTE that GetMMXSupported assumes that we are running on at least a - * pentium. The check to see if we are on a pentium requires that we - * modify the flags register, and we can't do that if we are running - * in ring3. Because NetWare 5 - according to our product marketing - - * requires at least a P5 90Mhz, we will be safe. When you port this - * code to NT, you may need to come up with a safe way to see if we - * can do MMX instructions - unless you can assume that even on NT you - * will be on at least a P5. - */ + // NOTE that GetMMXSupported assumes that we are running on at least a + // pentium. The check to see if we are on a pentium requires that we + // modify the flags register, and we can't do that if we are running + // in ring3. Because NetWare 5 - according to our product marketing - + // requires at least a P5 90Mhz, we will be safe. When you port this + // code to NT, you may need to come up with a safe way to see if we + // can do MMX instructions - unless you can assume that even on NT you + // will be on at least a P5. + gv_mmxCheckSumFlag = GetMMXSupported(); } +#endif -/****************************************************************************/ - - -/* - Routine to memset the stack. This is used to find code - that may access uninitialized values on the stack. - - How to use this under Netware. - - 1. Compile what code as if you were running the profiler. - To do this type "m debug PROFILE NLM". This adds a __PRO - and a __EPI call to every routine. - - 2. Make sure that this file is NOT compiled with the PROFILE - on the command line - or else we could recurse forever. - Recompile this file just to make sure "m debug nlm" after - you remove the comments before "#define STACK_CLEAR below. - - 3. Run the nlm watching for any protection errors. You may - want to change EAX in the memset to 0xFE so that some code - like - if (pUninitialized) *pUninitialized = 0; - will cause a protection fault. -*/ - -//#define STACK_CLEAR - -#if defined( FLM_NLM) && defined( STACK_CLEAR) -extern "C" +/******************************************************************** +Desc: Compares or sets the checksum value in a block. + Operates to compare the block checksum with the actual checksum. +Ret: if (Compare) returns FERR_BLOCK_CHECKSUM block checksum does + not agree with checksum header values. +*********************************************************************/ +RCODE BlkCheckSum( + FLMBYTE * pucBlkPtr, // Points to block + FLMINT iCompare, // TRUE compare checksums, FALSE set chksum + // Use CHECKSUM_CHECK or CHECKSUM_SET + FLMUINT uiBlkAddress, // Expected block address (3.x version) + FLMUINT uiBlkSize) // Used to verify that we don't read outside + // of an allocation. { - // This routines will have to be defined in the nlm.imp file. + RCODE rc = FERR_OK; +#if !((defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM)) + FLMBYTE ucTmp; + FLMBYTE * pucCur; + FLMBYTE * pucEnd; +#endif + FLMUINT uiAdds; + FLMUINT uiXORs; + FLMUINT uiCurrCheckSum = 0; + FLMUINT uiNewCheckSum; + FLMUINT uiEncryptSize; + FLMBYTE * pucSaveBlkPtr = pucBlkPtr; - LONG GetRunningProcess(void); - void *GetPCBStackLimit( struct PCBStructure *pcb ); + // Check the block length against the maximum block size - void __PRO() + uiEncryptSize = (FLMUINT)getEncryptSize( pucBlkPtr); + if( uiEncryptSize > uiBlkSize || uiEncryptSize < BH_OVHD) { - ; + rc = RC_SET( FERR_BLOCK_CHECKSUM); + goto Exit; + } + + // If we are comparing, but there is no current checksum just return. + // The next time the checksum is modified, the comparison will be performed. + // Version 3.x will store the full block address or if + // a checksum is used, the lost low byte of block address is checksummed. + + if( iCompare == CHECKSUM_CHECK) + { + uiCurrCheckSum = (FLMUINT)(((FLMUINT)pucBlkPtr[ BH_CHECKSUM_HIGH] << 8) + + (FLMUINT)pucBlkPtr[ BH_CHECKSUM_LOW]); } - void __EPI() + // We need to checksum the data that is encrypted. + // This is done by the getEncryptSize() call. + + // Check all of block, except for embedded checksum bytes. + // For speed, the initial values of uiAdds and uiXORs effectively ignore/skip + // the checksum values already embedded in the source: (a - a) == 0 and + // (a ^ a) == 0 so the initial values, net of the 2nd operations, equal zero + // too. + + uiAdds = 0 - (pucBlkPtr[ BH_CHECKSUM_LOW] + pucBlkPtr[ BH_CHECKSUM_HIGH]); + uiXORs = pucBlkPtr[ BH_CHECKSUM_LOW] ^ pucBlkPtr[ BH_CHECKSUM_HIGH]; + + // The 3.x version checksums the low byte of the address. + + if( uiBlkAddress != BT_END) { - char *pStackLimit; + uiAdds += (FLMBYTE)uiBlkAddress; + uiXORs ^= (FLMBYTE)uiBlkAddress; + } + +#if defined( FLM_NLM) || (defined( FLM_WIN) && !defined( FLM_64BIT)) + + FastBlockCheckSum( pucBlkPtr, &uiAdds, &uiXORs, + (unsigned long)uiEncryptSize); + +#else + +#ifdef FLM_64BIT + pucCur = pucBlkPtr; + pucEnd = pucBlkPtr + (uiEncryptSize & 0xFFFFFFFFFFFFFFF8); +#else + pucCur = pucBlkPtr; + pucEnd = pucBlkPtr + (uiEncryptSize & 0xFFFFFFFC); +#endif + + while( pucCur < pucEnd) + { + FLMUINT uiValue = *(FLMUINT *)pucCur; + + uiXORs ^= uiValue; + + uiAdds += (FLMBYTE)uiValue; + + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; + + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; + +#ifdef FLM_64BIT + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; + + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; + + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; + + uiValue >>= 8; + uiAdds += (FLMBYTE)uiValue; +#endif + + uiAdds += (FLMBYTE)(uiValue >> 8); + pucCur += sizeof( FLMUINT); + } + + ucTmp = (FLMBYTE)uiXORs; + ucTmp ^= (FLMBYTE)(uiXORs >> 8); + ucTmp ^= (FLMBYTE)(uiXORs >> 16); + ucTmp ^= (FLMBYTE)(uiXORs >> 24); +#ifdef FLM_64BIT + ucTmp ^= (FLMBYTE)(uiXORs >> 32); + ucTmp ^= (FLMBYTE)(uiXORs >> 40); + ucTmp ^= (FLMBYTE)(uiXORs >> 48); + ucTmp ^= (FLMBYTE)(uiXORs >> 56); +#endif + uiXORs = ucTmp; + + pucCur = pucEnd; + pucEnd = pucBlkPtr + uiEncryptSize; + + while( pucCur < pucEnd) + { + uiAdds += *pucCur; + uiXORs ^= *pucCur++; + } +#endif + + uiNewCheckSum = (((uiAdds << 8) + uiXORs) & 0xFFFF); + + // Set the checksum + + if (iCompare == CHECKSUM_SET) + { + pucSaveBlkPtr[ BH_CHECKSUM_HIGH] = (FLMBYTE)(uiNewCheckSum >> 8); + pucSaveBlkPtr[ BH_CHECKSUM_LOW] = (FLMBYTE)uiNewCheckSum; + goto Exit; + } + + // The checksum is different from the stored checksum. + // For version 3.x database we don't store the low byte of the + // address. Thus, it will have to be computed from the checksum. + + if( uiBlkAddress == BT_END) + { + FLMBYTE byXor; + FLMBYTE byAdd; + FLMBYTE byDelta; - __asm - { - // Save these registers before making any call. - // The "C" call already saves EBX, EDI and ESI on the stack. - push eax - push ecx - } - - pStackLimit = (char *) - GetPCBStackLimit((struct PCBStructure *)GetRunningProcess()); + // If there is a one byte value that will satisfy both + // sides of the checksum, the checksum is OK and that value + // is the first byte value. - __asm + byXor = (FLMBYTE) uiNewCheckSum; + byAdd = (FLMBYTE) (uiNewCheckSum >> 8); + byDelta = byXor ^ pucSaveBlkPtr [BH_CHECKSUM_LOW]; + + // Here is the big check, if byDelta is also what is + // off with the add portion of the checksum, we have + // a good value. + + if( ((FLMBYTE) (byAdd + byDelta)) == pucSaveBlkPtr[ BH_CHECKSUM_HIGH] ) { - // put in ecx the number of bytes remaining on the stack. - mov eax, pStackLimit - mov ecx, esp - sub ecx, eax - - // only set the first 1096 bytes or less if less remains on the stack. - cmp ecx, 1096 - jb smallMove - mov ecx, 1096 - -smallMove: - - // Move into edi the address to start the memset. - mov eax, esp - sub eax, 4 // Back off 4 bytes. - sub eax, ecx - mov edi, eax - - // Set dwords at a time - shr ecx, 2 - xor eax, eax // Could set eax to FE. - //cld - Not necessary - better always be clear - rep stosd - - // Restore ecx and eax - pop ecx - pop eax + // Set the low checksum value with the computed value. + + pucSaveBlkPtr[ BH_CHECKSUM_LOW] = byDelta; + goto Exit; } } + else + { + // This has the side effect of setting the low block address byte + // in the block thus getting rid of the low checksum byte. + + // NOTE: We are allowing the case where the calculated checksum is + // zero and the stored checksum is one because we used to change + // a calculated zero to a one in old databases and store the one. + // This is probably a somewhat rare case (1 out of 65536 checksums + // will be zero), so forgiving it will be OK most of the time. + // So that those don't cause us to report block checksum errors, + // we just allow it - checksumming isn't a perfect check anyway. + // VISIT: We do eventually want to get rid of this forgiving code. + + if (uiNewCheckSum == uiCurrCheckSum || + ((!uiNewCheckSum) && (uiCurrCheckSum == 1))) + { + pucSaveBlkPtr [BH_CHECKSUM_LOW] = (FLMBYTE) uiBlkAddress; + goto Exit; + } + } + + // Otherwise, we have a checksum error. + + rc = RC_SET( FERR_BLOCK_CHECKSUM); + +Exit: + + return( rc); } -#endif -#endif +/******************************************************************** +Desc: +*********************************************************************/ +FLMUINT lgHdrCheckSum( + FLMBYTE * pucLogHdr, + FLMBOOL bCompare) +{ + FLMUINT uiCnt; + FLMUINT uiTempSum; + FLMUINT uiCurrCheckSum; + FLMUINT uiTempSum2; + FLMUINT uiBytesToChecksum; + + uiBytesToChecksum = (FB2UW( &pucLogHdr [LOG_FLAIM_VERSION]) < + FLM_FILE_FORMAT_VER_4_3) + ? LOG_HEADER_SIZE_VER40 + : LOG_HEADER_SIZE; + + // If we are comparing, but there is no current checksum, return + // zero to indicate success. The next time the checksum is + // modified, the comparison will be performed. + // + // Unconverted databases may have a 0xFFFF or a zero in the checksum + // If 0xFFFF, change to a zero so we only have to deal with one value. + + if( (uiCurrCheckSum = (FLMUINT)FB2UW( + &pucLogHdr[ LOG_HDR_CHECKSUM])) == 0xFFFF) + { + uiCurrCheckSum = 0; + } + + if( bCompare && !uiCurrCheckSum) + { + return( 0); + } + + // Check all of log header except for the bytes which contain the + // checksum. + // + // For speed, uiTempSum is initialized to effectively ignore or skip + // the checksum embedded in the source: (a - a) == 0 so we store a negative + // that the later addition clears out. Also, the loop counter, i, + // is 1 larger than the number of FLMUINT16's so that we can + // pre-decrement by "for(;--i != 0;)" -- basically "loop-non-zero". + + for( uiTempSum = 0 - (FLMUINT)FB2UW( &pucLogHdr[ LOG_HDR_CHECKSUM]), + uiCnt = 1 + uiBytesToChecksum / sizeof( FLMUINT16); --uiCnt != 0; ) + { + uiTempSum += (FLMUINT)FB2UW( pucLogHdr); + pucLogHdr += sizeof( FLMUINT16); + } + + // Don't want a zero or 0xFFFF checksum - change to 1 + + if( (0 == (uiTempSum2 = (uiTempSum & 0xFFFF))) || (uiTempSum2 == 0xFFFF)) + { + uiTempSum2 = 1; + } + + return( (FLMUINT)(((bCompare) && (uiTempSum2 == uiCurrCheckSum)) + ? (FLMUINT)0 + : uiTempSum2) ); +} diff --git a/flaim/src/ddcreate.cpp b/flaim/src/ddcreate.cpp deleted file mode 100644 index 62afb7a..0000000 --- a/flaim/src/ddcreate.cpp +++ /dev/null @@ -1,956 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Data dictionary creation routines. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: ddcreate.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE DDMakeDictIxKey( - FDB * pDb, - FlmRecord * pRecord, - FLMBYTE * pKeyBuf, - FLMUINT * puiKeyLenRV); - -FSTATIC RCODE DDCheckNameConflict( - FDB * pDb, - LFILE * pDictIxLFile, - FlmRecord * pNewRec, - FLMUINT uiDrn, - FlmRecord * pOldRec); - -FSTATIC RCODE DDCheckIDConflict( - FDB * pDb, - LFILE * pDictContLFile, - FLMUINT uiDrn); - -FSTATIC RCODE DDIxDictRecord( - FDB * pDb, - LFILE * pDictIxLFile, - FLMUINT uiDrn, - FlmRecord * pRecord, - FLMUINT uiFlags); - -/**************************************************************************** -Desc: Allocate the LFILE and read in the LFile entries. The default - data container and the dictionary container will be at hard coded - slots at the first of the table. The LFiles do not need to be in - any numeric order. -****************************************************************************/ -RCODE fdictReadLFiles( - FDB * pDb, /* (IN) (OUT) table pointers */ - FDICT * pDict) -{ - RCODE rc = FERR_OK; - LFILE * pLFiles = NULL; - LFILE * pLFile; - SCACHE * pSCache; - FLMBOOL bReleaseCache = FALSE; - FLMBYTE * pucBlk; - FLMUINT uiBlkAddress; - FLMUINT uiPos; - FLMUINT uiEndPos; - FLMUINT uiEstCount; - FLMUINT uiLFileCnt; - FLMUINT uiLFHCnt; - FFILE * pFile = pDb->pFile; - FLMUINT uiBlkSize = pFile->FileHdr.uiBlockSize; - LFILE TmpLFile; - - f_memset( &TmpLFile, 0, sizeof( LFILE)); - - for( uiEstCount = 0, uiLFileCnt = 4, - uiBlkAddress = pDb->pFile->FileHdr.uiFirstLFHBlkAddr - ; uiBlkAddress != BT_END - ; ) - { - if( RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_LFH_BLK, - uiBlkAddress, NULL, &pSCache))) - { - goto Exit; - } - bReleaseCache = TRUE; - - pucBlk = pSCache->pucBlk; - uiPos = BH_OVHD; - if( (uiEndPos = (FLMUINT)FB2UW( &pucBlk[ BH_ELM_END])) <= BH_OVHD) - { - uiEndPos = BH_OVHD; - uiLFHCnt = 0; - } - else - { - if( uiEndPos > uiBlkSize) - uiEndPos = uiBlkSize; - uiLFHCnt = (FLMUINT)((uiEndPos - BH_OVHD) / LFH_SIZE); - uiEndPos = (FLMUINT)(BH_OVHD + uiLFHCnt * LFH_SIZE); - } - - // May allocate too many like the inactive ones but OK for now. - // Allocate an additional 2 for the default data and dict containers. - - if( !uiEstCount) /* First time */ - { - uiEstCount = uiLFHCnt + uiLFileCnt; - if( uiEstCount) - { - if( RC_BAD( rc = f_calloc( uiEstCount * sizeof( LFILE), &pLFiles))) - { - goto Exit; - } - } - } - else if( uiLFHCnt) - { - uiEstCount += uiLFHCnt; - - if( RC_BAD(rc = f_recalloc( uiEstCount * sizeof(LFILE), &pLFiles))) - { - goto Exit; - } - } - - /* Read through all of the logical file definitions in the block */ - - for( ; uiPos < uiEndPos; uiPos += LFH_SIZE) - { - FLMUINT uiLfNum; - - // Have to fix up the offsets later when they are read in - - if( RC_BAD( rc = flmBufferToLFile( &pucBlk[ uiPos], &TmpLFile, - uiBlkAddress, uiPos))) - { - goto Exit; - } - - if( TmpLFile.uiLfType == LF_INVALID) - { - continue; - } - - uiLfNum = TmpLFile.uiLfNum; - - if( uiLfNum == FLM_DATA_CONTAINER) - { - pLFile = pLFiles + LFILE_DATA_CONTAINER_OFFSET; - } - else if( uiLfNum == FLM_DICT_CONTAINER) - { - pLFile = pLFiles + LFILE_DICT_CONTAINER_OFFSET; - } - else if( uiLfNum == FLM_DICT_INDEX) - { - pLFile = pLFiles + LFILE_DICT_INDEX_OFFSET; - } - else if( uiLfNum == FLM_TRACKER_CONTAINER) - { - pLFile = pLFiles + LFILE_TRACKER_CONTAINER_OFFSET; - } - else - { - pLFile = pLFiles + uiLFileCnt++; - } - - f_memcpy( pLFile, &TmpLFile, sizeof(LFILE)); - } - - // Get the next block in the chain - - uiBlkAddress = (FLMUINT)FB2UD( &pucBlk[ BH_NEXT_BLK]); - ScaReleaseCache( pSCache, FALSE); - bReleaseCache = FALSE; - } - - // This routine could be called to re-read in the dictionary. - - if( pDict->pLFileTbl) - { - f_free( &pDict->pLFileTbl); - } - - pDict->pLFileTbl = pLFiles; - pDict->uiLFileCnt = uiLFileCnt; - -Exit: - - if( bReleaseCache) - { - ScaReleaseCache( pSCache, FALSE); - } - - if( RC_BAD(rc) && pLFiles) - { - f_free( &pLFiles); - } - - return( rc); -} - -/**************************************************************************** -Desc: Add data dictionary records to the data dictionary. -****************************************************************************/ -RCODE fdictCreate( - FDB * pDb, - const char * pszDictPath, - const char * pDictBuf) -{ - RCODE rc = FERR_OK; - F_FileHdl * pDictFileHdl = NULL; - FlmRecord * pDictRec = NULL; - void * pvField; - const char * pucGedBuf; - LFILE * pDictContLFile; - LFILE * pDictIxLFile; - FLMUINT uiDrn = 0; - FLMUINT uiCurrDictNum; - FLMUINT uiLFileCount; - FLMBOOL bFileOpen = FALSE; - LFILE DictContLFile; - LFILE DictIxLFile; - LFILE TempLFile; - char ucTempBuf[ 256]; - FLMUINT uiBufLen = sizeof( ucTempBuf); - F_NameTable nameTable; - - // Initialize the name table - - if( RC_BAD( rc = nameTable.setupFromDb( HFDB_NULL))) - { - goto Exit; - } - - /* Create Dictionary and Default Data containers */ - - if( RC_BAD(rc = flmLFileCreate( pDb, &DictContLFile, FLM_DICT_CONTAINER, - LF_CONTAINER))) - { - goto Exit; - } - uiCurrDictNum = FLM_DICT_CONTAINER; - - if( RC_BAD(rc = flmLFileCreate( pDb, &TempLFile, FLM_DATA_CONTAINER, - LF_CONTAINER))) - { - goto Exit; - } - - if( RC_BAD( rc = flmLFileCreate( pDb, &DictIxLFile, FLM_DICT_INDEX, - LF_INDEX))) - { - goto Exit; - } - - if( RC_BAD( rc = flmLFileCreate( pDb, &TempLFile, FLM_TRACKER_CONTAINER, - LF_CONTAINER))) - { - goto Exit; - } - - uiLFileCount = 4; - - // If we have a GEDCOM buffer, there is no need to open the file - - if( pDictBuf) - { - pucGedBuf = pDictBuf; - uiBufLen = f_strlen( pDictBuf) + 1; - } - else if( pszDictPath) - { - pucGedBuf = ucTempBuf; - if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( - pszDictPath, F_IO_RDONLY, &pDictFileHdl))) - { - goto Exit; - } - bFileOpen = TRUE; - } - else - { - /* - Neither a dictionary buffer or file were specified. Create will - be done with an empty dictionary. - */ - - goto Done_Getting_Dict; - } - - /* - Create a new FDICT so we can write the dictionary records. - This FDICT is temporary and will be allocated again. - */ - - if( RC_BAD( rc = fdictCreateNewDict( pDb))) - { - goto Exit; - } - - if( (pDictRec = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = fdictGetContainer( pDb->pDict, - FLM_DICT_CONTAINER, &pDictContLFile))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, - FLM_DICT_INDEX, &pDictIxLFile, NULL))) - { - goto Exit; - } - - /* - Read through the dictionary records, adding them or creating dictionaries - as we go. - */ - - for( ;;) - { - /* Get records from buffer or file. */ - - rc = ( pDictFileHdl) - ? pDictRec->importRecord( pDictFileHdl, &nameTable) - : pDictRec->importRecord( &pucGedBuf, uiBufLen, &nameTable); - - if( RC_BAD( rc)) - { - if( rc == FERR_END || rc == FERR_EOF_HIT) - { - rc = FERR_OK; - break; - } - else if( uiDrn) - { - // If an error occur then at least set the DRN of the - // previous record in the diagnostic information. - - pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; - pDb->Diag.uiDrn = uiDrn; - } - goto Exit; - } - - // See if we are switching dictionaries. - - pvField = pDictRec->root(); - if( pDictRec->getFieldID( pvField) == FLM_DICT_TAG) - { - rc = RC_SET( FERR_INVALID_TAG); - goto Exit; - } - - // Assign all fields a DRN value - parse for completeness. - // If there is no DRN in the record (zero), one will be assigned - // by FDDDictRecUpdate. - - uiDrn = pDictRec->getID(); - - /* - Add the data dictionary record. This also checks to see - if the record is already defined. - */ - - if( RC_BAD( rc = fdictRecUpdate( pDb, pDictContLFile, - pDictIxLFile, &uiDrn, pDictRec, NULL))) - { - goto Exit; - } - - // Don't need to do the processing below if it is not a record - // being put into the dictionary. - - if( uiCurrDictNum != FLM_DICT_CONTAINER) - { - continue; - } - - // Create an LFILE for each index and container. - - if( pDictRec->getFieldID( pvField) == FLM_INDEX_TAG || - pDictRec->getFieldID( pvField) == FLM_CONTAINER_TAG) - { - pvField = pDictRec->root(); - if( RC_BAD( rc = flmLFileCreate( pDb, &TempLFile, uiDrn, - ((pDictRec->getFieldID( pvField) == FLM_INDEX_TAG) - ? (FLMUINT)LF_INDEX - : (FLMUINT)LF_CONTAINER)))) - { - goto Exit; - } - uiLFileCount++; - } - } - -Done_Getting_Dict: - - // Create the FDICT again, this time with the dictionary pcode. - - if( RC_BAD( rc = fdictCreateNewDict( pDb))) - { - goto Exit; - } - -Exit: - - if( bFileOpen) - { - pDictFileHdl->Close(); - } - - if( pDictFileHdl) - { - pDictFileHdl->Release(); - } - - if( pDictRec) - { - pDictRec->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Creates a new dictionary for a database. - This occurs when on database create and on a dictionary change. -****************************************************************************/ -RCODE fdictCreateNewDict( - FDB * pDb) -{ - RCODE rc = FERR_OK; - - // Unlink the DB from the current FDICT, if any. - - if( pDb->pDict) - { - f_mutexLock( gv_FlmSysData.hShareMutex); - flmUnlinkFdbFromDict( pDb); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - } - - // Allocate a new FDICT structure for the new dictionary we - // are going to create. - - if( RC_BAD( rc = fdictRebuild( pDb))) - { - goto Exit; - } - - // Update the FDB structure to indicate that the dictionary - // was updated. - - pDb->uiFlags |= FDB_UPDATED_DICTIONARY; - -Exit: - - // If we allocated an FDICT and there was an error, free the FDICT. - - if( (RC_BAD( rc)) && (pDb->pDict)) - { - flmFreeDict( pDb->pDict); - pDb->pDict = NULL; - } - - return( rc); -} - -/**************************************************************************** -Desc: Add a new field, container or index definition to the dictionary. -****************************************************************************/ -RCODE flmAddRecordToDict( - FDB * pDb, - FlmRecord * pRecord, - FLMUINT uiDictId, - FLMBOOL bRereadLFiles) -{ - RCODE rc = FERR_OK; - TDICT tDict; - FLMBOOL bTDictInitialized = FALSE; - - if( RC_BAD( rc = fdictCopySkeletonDict( pDb))) - { - goto Exit; - } - - bTDictInitialized = TRUE; - if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictProcessRec( &tDict, pRecord, uiDictId))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictBuildTables( &tDict, bRereadLFiles, TRUE))) - { - goto Exit; - } - - pDb->uiFlags |= FDB_UPDATED_DICTIONARY; - -Exit: - - if( bTDictInitialized) - { - GedPoolFree( &tDict.pool); - } - - // If we allocated an FDICT and there was an error, free the FDICT. - - if( (RC_BAD( rc)) && (pDb->pDict)) - { - flmFreeDict( pDb->pDict); - pDb->pDict = NULL; - } - - return( rc); -} - -/**************************************************************************** -Desc: Add an index a dictionary record to the container LFILE and the - index LFILE. -****************************************************************************/ -RCODE fdictRecUpdate( - FDB * pDb, - LFILE * pDictContLFile, - LFILE * pDictIxLFile, - FLMUINT * puiDrnRV, - FlmRecord * pNewRec, - FlmRecord * pOldRec, - FLMBOOL bRebuildOp) -{ - RCODE rc = FERR_OK; - FLMUINT uiDrn = *puiDrnRV; - FLMBOOL bAllocatedID; - void * pvField; - FLMBYTE * pucKeyField = NULL; - FLMUINT32 ui32BufLen; - FLMUINT uiEncType; - - bAllocatedID = FALSE; - - // Make sure we are using a valid DRN - - if( (uiDrn >= FLM_RESERVED_TAG_NUMS) && - (uiDrn != 0xFFFFFFFF)) - { - pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; - pDb->Diag.uiDrn = uiDrn; - rc = RC_SET( FERR_BAD_DICT_DRN); - goto Exit; - } - - // Allocate an unused DRN, if one has not been allocated. - - if( (pNewRec) && ((!uiDrn) || (uiDrn == 0xFFFFFFFF))) - { - FLMBOOL bAllocAtEnd = (!uiDrn) ? TRUE : FALSE; - - bAllocatedID = TRUE; - if( bAllocAtEnd) - { - if( RC_BAD( rc = FSGetNextDrn( pDb, pDictContLFile, FALSE, &uiDrn))) - { - goto Exit; - } - } - else - { - // Scott 12/99: This must not be called any more. - // The code merged ITT values into the table. - - flmAssert(0); - } - - // Verify that we are not at our highest possible dictionary DRN. - - if( uiDrn >= FLM_RESERVED_TAG_NUMS) - { - rc = RC_SET( FERR_NO_MORE_DRNS); - goto Exit; - } - } - - // The following code makes sure that the DRN and name have not already been - // used, if adding. It also makes sure that there is no conflict in - // the type/name index. It checks the entire shared dictionary - // hierarchy if necessary - child and parent - to ensure no - // conflicts. - - if( pNewRec) - { - // Check for ID conflicts in the dictionary being added to - - if( (!pOldRec) && (!bAllocatedID)) - { - if( RC_BAD( rc = DDCheckIDConflict( pDb, pDictContLFile, uiDrn))) - { - if( (rc == FERR_ID_RESERVED) || (rc == FERR_DUPLICATE_DICT_REC)) - { - pvField = pNewRec->root(); - if( (rc == FERR_DUPLICATE_DICT_REC) && - (pNewRec->getFieldID( pvField) == FLM_RESERVED_TAG)) - { - rc = RC_SET( FERR_CANNOT_RESERVE_ID); - } - pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; - pDb->Diag.uiDrn = uiDrn; - } - goto Exit; - } - } - - // Check for name conflicts in the dictionary being added to - - if (pNewRec) - { - if (RC_BAD( rc = DDCheckNameConflict( pDb, pDictIxLFile, pNewRec, - uiDrn, pOldRec))) - goto Exit; - } - } - - if (!pOldRec && pNewRec) - { - // If this is an encryption definition record, we need to generate - // a new key. - - if (pNewRec->getFieldID( pNewRec->root()) == FLM_ENCDEF_TAG && - !bRebuildOp && !(pDb->uiFlags & FDB_REPLAYING_RFL)) - { - F_CCS Ccs; - - // If we are running in limited mode, we will not be able to complete - // this operation. - - if( pDb->pFile->bInLimitedMode) - { - rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); - goto Exit; - } - - // Should not have a key yet. - - if( pNewRec->find(pNewRec->root(), - FLM_KEY_TAG) != NULL) - { - rc = RC_SET( FERR_CANNOT_SET_KEY); - goto Exit; - } - - if( (pvField = pNewRec->find( pNewRec->root(), - FLM_TYPE_TAG)) == NULL) - { - rc = RC_SET( FERR_MISSING_ENC_TYPE); - goto Exit; - } - - if( RC_BAD( rc = DDGetEncType( pNewRec, pvField, &uiEncType))) - { - goto Exit; - } - - if( RC_BAD( rc = Ccs.init( FALSE, uiEncType))) - { - goto Exit; - } - - if( RC_BAD( rc = Ccs.generateEncryptionKey())) - { - goto Exit; - } - - if( RC_BAD( rc = Ccs.getKeyToStore( &pucKeyField, &ui32BufLen, - NULL, pDb->pFile->pDbWrappingKey))) - { - goto Exit; - } - - // Create the key field - - if( RC_BAD( rc = pNewRec->insert( pNewRec->root(), INSERT_LAST_CHILD, - FLM_KEY_TAG, FLM_TEXT_TYPE, &pvField))) - { - goto Exit; - } - - // Set the value of the new field - - if( RC_BAD( rc = pNewRec->setNative( pvField, - (const char *)pucKeyField))) - { - goto Exit; - } - } - } - - // Delete the old record and its index entries, if any - - if( pOldRec) - { - // Delete the old record's index entries - - if( RC_BAD( rc = DDIxDictRecord( pDb, pDictIxLFile, uiDrn, - pOldRec, KREF_DELETE_FLAG))) - { - goto Exit; - } - - // Delete the old record - unless it is a modify - - if( !pNewRec) - { - if( RC_BAD( rc = FSRecUpdate( pDb, pDictContLFile, NULL, uiDrn, - REC_UPD_DELETE))) - { - goto Exit; - } - } - } - - // Add the new record, if any - - if( pNewRec) - { - // Add the record's index keys - - if( RC_BAD( rc = DDIxDictRecord( pDb, pDictIxLFile, uiDrn, - pNewRec, 0))) - { - goto Exit; - } - - // Add or modify the record itself - - if( RC_BAD( rc = FSRecUpdate( pDb, pDictContLFile, pNewRec, - uiDrn, (FLMUINT)((pOldRec) - ? (FLMUINT)REC_UPD_MODIFY - : (FLMUINT)REC_UPD_ADD)))) - { - goto Exit; - } - } - -Exit: - - if( RC_OK( rc)) - { - *puiDrnRV = uiDrn; - } - - if (pucKeyField) - { - f_free( &pucKeyField); - } - - return( rc); -} - -/**************************************************************************** -Desc: Creates a collated type/name key for a dictionary record. -****************************************************************************/ -FSTATIC RCODE DDMakeDictIxKey( - FDB * pDb, - FlmRecord * pRecord, - FLMBYTE * pKeyBuf, - FLMUINT * puiKeyLenRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiElmLen; - FLMUINT uiKeyLen = 0; - void * pvField = pRecord->root(); - const FLMBYTE * pExportPtr; - - // Collate the name - - pExportPtr = pRecord->getDataPtr( pvField), - uiElmLen = MAX_KEY_SIZ - uiKeyLen; - - if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, - pExportPtr, - pRecord->getDataLength( pvField), - FLM_TEXT_TYPE, uiElmLen, - NULL, NULL, - pDb->pFile->FileHdr.uiDefaultLanguage, - FALSE, FALSE, FALSE, NULL))) - { - goto Exit; - } - - uiKeyLen += uiElmLen; - -Exit: - - *puiKeyLenRV = uiKeyLen; - return( rc); -} - -/**************************************************************************** -Desc: Checks to make sure a dictionary name has not already been used. -****************************************************************************/ -FSTATIC RCODE DDCheckNameConflict( - FDB * pDb, - LFILE * pDictIxLFile, /* Dictionary index to check in. */ - FlmRecord * pNewRec, /* Record whose name is to be checked. */ - FLMUINT uiDrn, /* DRN of new record. */ - FlmRecord * pOldRec) /* Old record, non-NULL indicates that this - is a modifiy operation. */ -{ - RCODE rc = FERR_OK; - BTSK StackArray[ BH_MAX_LEVELS]; - BTSK_p pStack; - FLMBYTE BtKeyBuf[ MAX_KEY_SIZ]; - FLMBYTE IxKeyBuf[ MAX_KEY_SIZ]; - FLMUINT uiKeyLen; - void * pvField; - - FSInitStackCache( &StackArray [0], BH_MAX_LEVELS); - - if (RC_BAD( rc = DDMakeDictIxKey( pDb, pNewRec, IxKeyBuf, &uiKeyLen))) - goto Exit; - StackArray[0].pKeyBuf = BtKeyBuf; - pStack = StackArray; - if (RC_BAD( rc = FSBtSearch( pDb, pDictIxLFile, &pStack, - IxKeyBuf, uiKeyLen, 0L))) - goto Exit; - if (pStack->uiCmpStatus == BT_EQ_KEY) - { - FLMUINT uiElmDoman; - DIN_STATE DinState; - FLMUINT uiFoundDrn; - - /* - If this is an ADD (!pOldRec), or the record found - is different than the one being updated, we have - a problem. - */ - - uiFoundDrn = FSRefFirst( pStack, &DinState, &uiElmDoman); - if ((!pOldRec) || (uiFoundDrn != uiDrn)) - { - pvField = pNewRec->root(); - pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; - pDb->Diag.uiDrn = uiDrn; - rc = (pNewRec->getFieldID( pvField) == FLM_RESERVED_TAG) - ? RC_SET( FERR_CANNOT_RESERVE_NAME) - : RC_SET( FERR_DUPLICATE_DICT_NAME); - goto Exit; - } - } -Exit: - FSReleaseStackCache( StackArray, BH_MAX_LEVELS, FALSE); - return( rc); -} - - -/**************************************************************************** -Desc: Checks to make sure a dictionary DRN has not already been used. -****************************************************************************/ -FSTATIC RCODE DDCheckIDConflict( - FDB * pDb, - LFILE * pDictContLFile, // Pointer to dictionary container LFILE. - FLMUINT uiDrn) // DRN of record. -{ - RCODE rc = FERR_OK; - FlmRecord * pOldRec = NULL; - - // Read to see if there is an existing record. - // NOTE: Deliberately not bringing into cache if not found. - - if( RC_BAD( rc = FSReadRecord( pDb, pDictContLFile, uiDrn, - &pOldRec, NULL, NULL))) - { - if (rc == FERR_NOT_FOUND) - { - rc = FERR_OK; - } - else - { - goto Exit; - } - } - - if( pOldRec) - { - void * pvField = pOldRec->root(); - - rc = ( pOldRec->getFieldID( pvField) == FLM_RESERVED_TAG) - ? RC_SET( FERR_ID_RESERVED) - : RC_SET( FERR_DUPLICATE_DICT_REC); - } - -Exit: - if( pOldRec) - { - pOldRec->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Generate a key for an index record and add or delete it from - the index. -****************************************************************************/ -FSTATIC RCODE DDIxDictRecord( - FDB * pDb, - LFILE * pDictIxLFile, - FLMUINT uiDrn, - FlmRecord * pRecord, - FLMUINT uiFlags) -{ - RCODE rc; - union - { - FLMBYTE KeyBuf [sizeof( KREF_ENTRY) + MAX_KEY_SIZ]; - KREF_ENTRY KrefEntry; - }; - FLMUINT uiKeyLen; - - flmAssert( pDictIxLFile->uiLfNum > 0 && - pDictIxLFile->uiLfNum < FLM_UNREGISTERED_TAGS); // Sanity check - KrefEntry.ui16IxNum = (FLMUINT16)pDictIxLFile->uiLfNum; - KrefEntry.uiDrn = uiDrn; - KrefEntry.uiFlags = uiFlags; - KrefEntry.uiTrnsSeq = 1; - - /* Add or delete the key/reference. */ - - if (RC_BAD( rc = DDMakeDictIxKey( pDb, pRecord, - &KeyBuf [sizeof( KREF_ENTRY)], &uiKeyLen))) - { - goto Exit; - } - KrefEntry.ui16KeyLen = (FLMUINT16)uiKeyLen; - - rc = FSRefUpdate( pDb, pDictIxLFile, &KrefEntry); -Exit: - return( rc); -} - diff --git a/flaim/src/ddprep.cpp b/flaim/src/ddprep.cpp deleted file mode 100644 index 697a472..0000000 --- a/flaim/src/ddprep.cpp +++ /dev/null @@ -1,1577 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Routines to verify all dictionary syntax. -// Tabs: 3 -// -// Copyright (c) 1992-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: ddprep.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define FDD_MAX_VALUE_SIZE 64 - -FSTATIC RCODE fdictAddDictIndex( - TDICT * pTDict); - -FSTATIC RCODE DDFieldParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord, - FLMUINT uiDictRecNum); - -FSTATIC RCODE DDGetReference( - FlmRecord * pRecord, - void * pvField, - const char * pszBuffer, - FLMUINT * puiIdRef); - -FSTATIC RCODE DDAllocEntry( - TDICT * pTDict, - FlmRecord * pRecord, - FLMUINT uiDictRecNum, - DDENTRY ** ppDDEntryRV); - -FSTATIC RCODE DDIxParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord, - void * pvField); - -FSTATIC RCODE DDBuildFldPath( - TDICT * pTDict, - TIFD ** ppTIfd, - FlmRecord * pRecord, - void * pvField, - FLMUINT uiBaseNum); - -FSTATIC FLMBOOL DDMoveWord( - char * pucDest, - char * pucSrc, - FLMUINT uiMaxDestLen, - FLMUINT * puiPos); - -FSTATIC RCODE DDContainerParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord); - -FSTATIC void DDTextToNative( - FlmRecord * pRecord, - void * pvField, - char * pszBuffer, - FLMUINT uiBufLen, - FLMUINT * puiBufLen); - -FSTATIC RCODE DDParseStateOptions( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo); - -FSTATIC RCODE DDEncDefParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord, - FLMUINT uiDictRecNum); - -FSTATIC RCODE DDGetEncKey( - TDICT * pTDict, - FlmRecord * pRecord, - void * pvField, - TENCDEF * pTEncDef); - -#define MAX_ENC_TYPES 3 - -// NOTE: If you change the arrangement of the values in this array, make sure -// you search the entire codebase for references to DDEncOpts and DDGetEncType -// and verify that the changes won't cause problems. This is particularly -// important because these values DO NOT match up exactly with the values in -// the SMEncryptionScheme enum that's used at the SMI level. - -const char * DDEncOpts[ MAX_ENC_TYPES] = -{ - "aes", - "des3", - "des" -}; - -#define START_DD_INDEX_OPTS 0 -#define DD_IX_FIELD_OPT 0 -#define DD_IX_COMPOUND_OPT 1 -#define DD_IX_UPPER_OPT 2 -#define DD_IX_EACHWORD_OPT 3 -#define DD_IX_MIXED_OPT 4 -#define DD_IX_CONTEXT_OPT 5 -#define DD_IX_POST_OPT 6 -#define MAX_DD_INDEX_OPTS 7 - -/**************************************************************************** -Desc: Read all data dictionary records parsing and sending to process. - All temporary structures are off of pTDict. pTDict must be setup. -****************************************************************************/ -RCODE fdictProcessAllDictRecs( - FDB * pDb, - TDICT * pTDict) -{ - RCODE rc; - LFILE * pLFile = pTDict->pLFile; - BTSK stackBuf[ BH_MAX_LEVELS ]; // Stack to hold b-tree variables - BTSK * stack = stackBuf; // Points to proper stack frame - FLMBYTE btKeyBuf[ DRN_KEY_SIZ +8]; // Key buffer pointed to by stack - FLMBYTE key[4]; // Used for dummy empty key - FLMUINT uiDrn; - FlmRecord * pRecord = NULL; - - // Add the dictionary index to the front of TDICT. - if( RC_BAD( rc = fdictAddDictIndex( pTDict))) - { - goto Exit; - } - - // Position to the first of the data dictionary data records & read. - FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); - stack->pKeyBuf = btKeyBuf; - flmUINT32ToBigEndian( 0, key); - if( RC_BAD(rc = FSBtSearch( pDb, pLFile, &stack, key, DRN_KEY_SIZ, 0 ))) - goto Exit; - - // Special case of no records. - if( stack->uiCmpStatus == BT_END_OF_DATA) - goto Exit; - stack->uiFlags = NO_STACK; // Fake out the stack for speed. - - do - { - if( (uiDrn = flmBigEndianToUINT32( btKeyBuf)) == DRN_LAST_MARKER) - { - break; - } - - // VERY IMPORTANT NOTE: - // DO NOT READ FROM CACHE - THE RECORD MAY - // NOT HAVE BEEN PUT INTO RECORD CACHE YET, AND WE NEED TO HAVE - // THE CORRECT VERSION OF THE RECORD. - - if( RC_BAD( rc = FSReadElement( pDb, &pDb->TempPool, pLFile, - uiDrn, stack, TRUE, &pRecord, NULL, NULL))) - { - break; - } - - if( RC_BAD(rc = fdictProcessRec( pTDict, pRecord, uiDrn))) - { - pDb->Diag.uiDrn = uiDrn; - pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; - if( pTDict->uiBadField != 0) - { - pDb->Diag.uiFieldNum = pTDict->uiBadField; - pDb->Diag.uiInfoFlags |= FLM_DIAG_FIELD_NUM; - } - break; - } - - // Position to the next record - SUCCESS or FERR_BT_END_OF_DATA - rc = FSNextRecord( pDb, pLFile, stack); - - } while( RC_OK(rc)); - - rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; - -Exit: - - if( pRecord) - { - pRecord->Release(); - } - - FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); - return( rc ); -} - -/**************************************************************************** -Desc: Add the dictionary index to pTDict. -****************************************************************************/ -RCODE fdictAddDictIndex( - TDICT * pTDict) -{ - RCODE rc; - DDENTRY * pDDEntry; - TIXD * pTIxd; - TIFD * pTIfd; - TIFP * pTIfp; - - if( RC_BAD( rc = DDAllocEntry( pTDict, NULL, FLM_DICT_INDEX, &pDDEntry))) - { - goto Exit; - } - pDDEntry->uiType = ITT_INDEX_TYPE; - - if( (pTIxd = (TIXD *) GedPoolAlloc( &pTDict->pool, sizeof( TIXD))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTDict->uiNewIxds++; - pDDEntry->vpDef = (void *) pTIxd; - pTIxd->uiFlags = IXD_UNIQUE; - pTIxd->uiContainerNum = FLM_DICT_CONTAINER; - pTIxd->uiNumFlds = 1; - pTIxd->uiLanguage = pTDict->uiDefaultLanguage; - pTIxd->uiEncId = 0; - - if( (pTIfd = (TIFD *) GedPoolAlloc( &pTDict->pool, sizeof( TIFD))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTIxd->pNextTIfd = pTIfd; - pTDict->uiNewIfds++; - pTIfd->pTIfp = NULL; - pTIfd->pNextTIfd = NULL; - pTIfd->uiFlags = (FLMUINT)(IFD_FIELD | FLM_TEXT_TYPE); - pTIfd->uiNextFixupPos = 0; - pTIfd->uiLimit = IFD_DEFAULT_LIMIT; - pTIfd->uiCompoundPos = 0; - - if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, sizeof( TIFP ))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTDict->uiNewFldPaths += 2; - pTIfd->pTIfp = pTIfp; - - pTIfp->pNextTIfp = NULL; - pTIfp->bFieldInThisDict = FALSE; - pTIfp->uiFldNum = FLM_NAME_TAG; - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Process a single data dictionary record. Parse the record for syntax - errors depending on flag value. Only supports adding new stuff - to pTDict. -****************************************************************************/ -RCODE fdictProcessRec( - TDICT * pTDict, - FlmRecord * pRecord, - FLMUINT uiDictRecNum) -{ - RCODE rc = FERR_OK; - DDENTRY * pDDEntry; - void * pvField = pRecord->root(); - - // Ignore items with root nodes that are in the unregistered range. - - if( pRecord->getFieldID( pvField) >= FLM_UNREGISTERED_TAGS) - { - goto Exit; - } - - // Parse only on modify or add. - - switch( pRecord->getFieldID( pvField)) - { - case FLM_FIELD_TAG: - { - if( RC_BAD( rc = DDAllocEntry( - pTDict, pRecord, uiDictRecNum, &pDDEntry))) - { - goto Exit; - } - - pDDEntry->uiType = 0; // Type of zero means field. - if( RC_BAD( rc = DDFieldParse( pTDict, pDDEntry, - pRecord, uiDictRecNum))) - { - goto Exit; - } - break; - } - - case FLM_INDEX_TAG: - { - if( RC_BAD( rc = DDAllocEntry( - pTDict, pRecord, uiDictRecNum, &pDDEntry))) - { - goto Exit; - } - pDDEntry->uiType = ITT_INDEX_TYPE; - if( RC_BAD( rc = DDIxParse( pTDict, pDDEntry, pRecord, pvField))) - { - goto Exit; - } - pTDict->uiNewIxds++; - break; - } - - case FLM_CONTAINER_TAG: - { - if( RC_BAD( rc = DDAllocEntry( - pTDict, pRecord, uiDictRecNum, &pDDEntry))) - { - goto Exit; - } - pDDEntry->uiType = ITT_CONTAINER_TYPE; - if( RC_BAD( rc = DDContainerParse( pTDict, pDDEntry, pRecord))) - { - goto Exit; - } - pTDict->uiTotalLFiles++; - break; - } - case FLM_ENCDEF_TAG: - { - if( RC_BAD( rc = DDAllocEntry( - pTDict, pRecord, uiDictRecNum, &pDDEntry))) - { - goto Exit; - } - pDDEntry->uiType = ITT_ENCDEF_TYPE; - if (RC_BAD( rc = DDEncDefParse( pTDict, pDDEntry, pRecord, uiDictRecNum))) - { - goto Exit; - } - break; - } - case FLM_AREA_TAG: - case FLM_RESERVED_TAG: - { - break; - } - - default: - { - // Cannot allow anything else to pass through the dictionary. - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Allocate, check and add a name to the DDEntry structure. -****************************************************************************/ -FSTATIC RCODE DDAllocEntry( - TDICT * pTDict, - FlmRecord * pRecord, - FLMUINT uiDictRecNum, - DDENTRY ** ppDDEntryRV) -{ - RCODE rc = FERR_OK; - DDENTRY * pNewEntry; - - pNewEntry = (DDENTRY *)GedPoolAlloc( &pTDict->pool, sizeof(DDENTRY)); - if( !pNewEntry) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pNewEntry->pNextEntry = NULL; - pNewEntry->vpDef = NULL; - pNewEntry->uiEntryNum = uiDictRecNum; - pNewEntry->uiType = 0; - - // Zero length name NOT allowed for dictionary items. - - if( pRecord) - { - if( pRecord->getDataLength( pRecord->root()) == 0) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - - if( pTDict->pLastEntry) - { - pTDict->pLastEntry->pNextEntry = pNewEntry; - } - else - { - pTDict->pFirstEntry = pNewEntry; - } - pTDict->pLastEntry = pNewEntry; - *ppDDEntryRV = pNewEntry; - -Exit: - - return( rc ); -} - -/**************************************************************************** -Desc: Parse field definition -****************************************************************************/ -FSTATIC RCODE DDFieldParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord, - FLMUINT uiDictRecNum) -{ - RCODE rc = FERR_OK; - TFIELD * pTField; - void * pvField; - - if( (pTField = (TFIELD *)GedPoolAlloc( &pTDict->pool, sizeof(TFIELD))) == NULL) - { - return( RC_SET( FERR_MEM)); - } - - pTField->uiFldNum = uiDictRecNum; - pTField->uiFldInfo = FLM_CONTEXT_TYPE; - pDDEntry->vpDef = (void *) pTField; - - if( (pvField = pRecord->firstChild( pRecord->root())) == NULL) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - for( ; pvField; pvField = pRecord->nextSibling( pvField)) - { - switch( pRecord->getFieldID( pvField)) - { - case FLM_TYPE_TAG: - { - rc = DDGetFieldType( pRecord, pvField, &pTField->uiFldInfo); - break; - } - - case FLM_STATE_TAG: - { - rc = DDParseStateOptions( pRecord, pvField, &pTField->uiFldInfo); - break; - } - - default: - { - if( pRecord->getFieldID( pvField) < FLM_UNREGISTERED_TAGS && - pRecord->getFieldID( pvField) != FLM_COMMENT_TAG) - { - rc = RC_SET( FERR_SYNTAX); - } - break; - } - } - } - -Exit: - - if( RC_BAD(rc) && pvField) - { - pTDict->uiBadField = pRecord->getFieldID( pvField); - } - return( rc ); -} - -/**************************************************************************** -Desc: Returns the fields data type. May be called outside of DDPREP.C -****************************************************************************/ -RCODE DDGetFieldType( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo) -{ - RCODE rc = FERR_OK; - char szNativeBuf[ FDD_MAX_VALUE_SIZE]; - - DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL ); - - // Parse the type keyword - only one type allowed. - - if (f_strnicmp( szNativeBuf, "text", 4) == 0) - { - *puiFldInfo = FLM_TEXT_TYPE; - } - else if (f_strnicmp( szNativeBuf, "numb", 4) == 0) - { - *puiFldInfo = FLM_NUMBER_TYPE; - } - else if (f_strnicmp( szNativeBuf, "bina", 4) == 0) - { - *puiFldInfo = FLM_BINARY_TYPE; - } - else if (f_strnicmp( szNativeBuf, "cont", 4) == 0) - { - *puiFldInfo = FLM_CONTEXT_TYPE; - } - else if (f_strnicmp( szNativeBuf, "blob", 4) == 0) - { - *puiFldInfo = FLM_BLOB_TYPE; - } - else - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Parses the 'state' option that is found within the 'field' - dictionary definition. -Format: state [checking | unused | purge | active] -****************************************************************************/ -FSTATIC RCODE DDParseStateOptions( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo) -{ - RCODE rc = FERR_OK; - char szNativeBuf[ FDD_MAX_VALUE_SIZE]; - - DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL); - - // Parse the 'state' keyword - only one type allowed - - if( f_strnicmp( szNativeBuf, "chec", 4) == 0) - { - // 0xFFCF is used to clear out any existing field 'state' value - - *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_CHECKING); - } - else if( f_strnicmp( szNativeBuf, "unus", 4) == 0) - { - *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_UNUSED); - } - else if( f_strnicmp( szNativeBuf, "purg", 4) == 0) - { - *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_PURGE); - } - else if( f_strnicmp( szNativeBuf, "acti", 4) == 0) - { - *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_ACTIVE); - } - else - { - rc = RC_SET( FERR_SYNTAX); - } - - return( rc); -} - -/**************************************************************************** -Desc: Get a number reference and set in the (OUT) parameter. -****************************************************************************/ -FSTATIC RCODE DDGetReference( - FlmRecord * pRecord, - void * pvField, - const char * pszBuffer, - FLMUINT * puiIdRef) -{ - RCODE rc = FERR_OK; - - *puiIdRef = 0; - if( pszBuffer) - { - if( !(*pszBuffer)) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - *puiIdRef = f_atoud( pszBuffer); - } - else - { - if( RC_BAD( rc = pRecord->getUINT( pvField, puiIdRef))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Returns the encryption type. May be called outside of DDPREP.C -****************************************************************************/ -RCODE DDGetEncType( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo) -{ - RCODE rc = FERR_OK; - FLMUINT uiType; - char szNativeBuf[ FDD_MAX_VALUE_SIZE]; - - DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL ); - - // Parse the type keyword - only one type allowed. - - for( uiType = 0; - uiType < MAX_ENC_TYPES ; - uiType++) - { - if( f_strnicmp( szNativeBuf, DDEncOpts[ uiType], - f_strlen(DDEncOpts[ uiType])) == 0) - { - *puiFldInfo = uiType; - goto Exit; - } - } - - rc = RC_SET( FERR_SYNTAX); - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Returns the binary key info. May be called outside of DDPREP.C -****************************************************************************/ -FSTATIC RCODE DDGetEncKey( - TDICT * pTDict, - FlmRecord * pRecord, - void * pvField, - TENCDEF * pTEncDef) -{ - RCODE rc = FERR_OK; - char * pucBuffer = NULL; - FLMUINT uiLength; - - pTEncDef->uiLength = 0; - - if (RC_BAD( rc = pRecord->getNativeLength( pvField, &uiLength))) - { - goto Exit; - } - uiLength++; - - // Allocate the buffer from the pool so it will be easily freed later. - - if( (pucBuffer = (char *)GedPoolAlloc( &pTDict->pool, uiLength)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if (RC_BAD( rc = pRecord->getNative( pvField, pucBuffer, &uiLength))) - { - goto Exit; - } - - pTEncDef->uiLength = uiLength; - pTEncDef->pucKeyInfo = (FLMBYTE *)pucBuffer; - -Exit: - - return( rc); - -} - -/**************************************************************************** -Desc: Parse an data dictionary index definition for correct syntax & - assign the correct attributes. Build the pcode buffer for the index. -Return: RCODE - SUCCESS or FERR_SYNTAX -Format: - -0 index # FLM_INDEX_TAG -[ 1 area [ 0 | ]] # FLM_AREA_TAG - QF files area, 0 = "same as DB" -[ 1 container {DEFAULT | }] # FLM_CONTAINER_TAG - indexes span only one container -[ 1 count [ KEYS &| REFS]] # FLM_COUNT_TAG - key count of keys and/or refs -[ 1 language {US | }] # FLM_LANGUAGE_TAG - for full-text parsing and/or sorting -[ 1 positioning] # FLM_POSITIONING_TAG - full reference counts at all b-tree elements -[ 1 encdef ] # FLM_ENCDEF_TAG - identify the encryption definition to use - - 1 key [EACHWORD] # FLM_KEY_TAG - 'use' defaults based on type - [ 2 base ] # FLM_BASE_TAG - base rec/field for fields below - [ 2 combinations # FLM_COMBINATIONS_TAG - how to handle repeating fields - { ALL | NORMALIZED}] - [ 2 post] # FLM_POST_TAG - case-flags post-pended to key - [ 2 required*] # FLM_REQUIRED_TAG - key value is required - [ 2 unique] # FLM_UNIQUE_TAG - key has only 1 reference - { 2 }... # FLM_FIELD_TAG - compound key if 2 or more - [ 3 case mixed | upper] # FLM_CASE_TAG - text-only, define chars case - [ 3 ]... # FLM_FIELD_TAG - alternate field(s) - [ 3 paired] # FLM_PAIRED_TAG - add field ID to key - [ 3 optional* # FLM_OPTIONAL_TAG - component's value is optional - | 3 required] # FLM_REQUIRED_TAG - component's value is required - [ 3 use eachword|value|field|minspaces|nounderscore|nospace|nodash] # FLM_USE_TAG - - == - n field # path identifies field -- maybe "based" - [ m type ] # FLM_TYPE_TAG - only for ixing unregistered fields - -Please Note: This code only supports the minimal old 11 index format - needed for skads databases. -****************************************************************************/ -FSTATIC RCODE DDIxParse( - TDICT * pTDict, - DDENTRY * pDDEntry, // Points to defined entry. - FlmRecord * pRecord, // Index definition record. - void * pvField) -{ - RCODE rc = FERR_OK; - FLMUINT uiIfdFlags; - FLMUINT uiTempIfdFlags; - FLMUINT uiBaseNum; - FLMUINT uiNLen; - TIXD * pTIxd; - TIFD * pLastTIfd; - TIFD * pTIfd; - void * pvTempField = NULL; - void * pvIfdField = NULL; - char szNativeBuf[ 64]; - FLMUINT uiCompoundPos; - FLMUINT uiTemp; - FLMBOOL bHasRequiredTag = TRUE; - FLMBOOL bOld11Mode = FALSE; - - if( (pTIxd = (TIXD *) GedPoolAlloc( &pTDict->pool, sizeof( TIXD))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTIxd->pNextTIfd = NULL; - pTIxd->uiFlags = 0; - pTIxd->uiContainerNum = FLM_DATA_CONTAINER; - pTIxd->uiNumFlds = 0; - pTIxd->uiLanguage = pTDict->uiDefaultLanguage; - pTIxd->uiEncId = 0; - - if( (pvField = pRecord->firstChild( pRecord->root())) == NULL) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - pLastTIfd = NULL; - for( ; pvField; pvField = pRecord->nextSibling( pvField)) - { - switch ( pRecord->getFieldID( pvField)) - { - case FLM_CONTAINER_TAG: - { - char szTmpBuf [50]; - FLMUINT uiLen = sizeof( szTmpBuf); - - // See if a special keyword is used - ALL or * - - if ((pRecord->getDataType( pvField) == FLM_TEXT_TYPE) && - (RC_OK( pRecord->getNative( pvField, szTmpBuf, &uiLen))) && - (f_stricmp( "ALL", szTmpBuf) == 0 || - f_stricmp( "*", szTmpBuf) == 0)) - { - if (pTDict->pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_50) - { - rc = RC_SET( FERR_UNSUPPORTED_FEATURE); - goto Exit; - } - - // Zero will mean all containers - - pTIxd->uiContainerNum = 0; - } - else - { - if( RC_BAD( rc = DDGetReference( pRecord, pvField, NULL, - &pTIxd->uiContainerNum))) - { - goto Exit; - } - if( pTIxd->uiContainerNum == 0) - { - pTIxd->uiContainerNum = FLM_DATA_CONTAINER; - } - } - break; - } - - case FLM_COUNT_TAG: - pTIxd->uiFlags |= IXD_COUNT; - break; - - case FLM_LANGUAGE_TAG: - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); - pTIxd->uiLanguage = FlmLanguage( szNativeBuf); - break; - - - case FLM_ENCDEF_TAG: - { - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); - pTIxd->uiEncId = f_atoud( szNativeBuf); - flmAssert( pTIxd->uiEncId); - break; - } - - case FLM_TYPE_TAG: - // Is only compound for NDS definitions. This parsers default. - bOld11Mode = TRUE; - break; - - case FLM_POSITIONING_TAG: - if (pTDict->pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - pTIxd->uiFlags |= IXD_POSITIONING; - } - else - { - - // Positioning indexes not allowed prior to 4.3 - - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - break; - - case FLM_FIELD_TAG: - uiCompoundPos = 0; - uiBaseNum = 0; - uiIfdFlags = IFD_FIELD; - bHasRequiredTag = TRUE; - pvTempField = pvField; - bOld11Mode = TRUE; - goto Parse_Fields; - - case FLM_KEY_TAG: - uiCompoundPos = 0; - uiBaseNum = 0; - uiIfdFlags = IFD_FIELD | IFD_OPTIONAL; - bHasRequiredTag = FALSE; - - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); - - if( f_strnicmp( szNativeBuf, "EACH", 4) == 0) - { - pTIxd->uiFlags |= IXD_EACHWORD; - uiIfdFlags = IFD_EACHWORD | IFD_OPTIONAL; - } - - if( (pvTempField = pRecord->firstChild( pvField)) == NULL) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } -Parse_Fields: - for( ; pvTempField; pvTempField = pRecord->nextSibling( pvTempField)) - { - switch( pRecord->getFieldID( pvTempField)) - { - case FLM_BASE_TAG: - if( RC_BAD( rc = DDGetReference( pRecord, - pvTempField, NULL, &uiBaseNum))) - { - goto Exit; - } - break; - - case FLM_COMBINATIONS_TAG: - rc = RC_SET( FERR_SYNTAX); - goto Exit; - - case FLM_POST_TAG: - pTIxd->uiFlags |= IXD_HAS_POST; - uiIfdFlags |= IFD_POST; - break; - - case FLM_REQUIRED_TAG: // Default - doesn't mean anything - break; - - case FLM_OPTIONAL_TAG: - rc = RC_SET( FERR_SYNTAX); - goto Exit; - - case FLM_UNIQUE_TAG : - pTIxd->uiFlags |= IXD_UNIQUE; - uiIfdFlags |= IFD_UNIQUE_PIECE; // Set the Unique Index Flag - break; - - case FLM_FIELD_TAG: - pTIxd->uiNumFlds++; - - if( bOld11Mode) - { - pvField = pvTempField; - } - - // Need to set IFD_COMPOUND if there is more than one field. - - if( pTIxd->uiNumFlds == 1 && - (pRecord->find( pvTempField, FLM_FIELD_TAG, 2) != NULL)) - { - uiIfdFlags |= IFD_COMPOUND; - } - - pTIfd = pLastTIfd; - if( RC_BAD(rc = DDBuildFldPath( pTDict, &pLastTIfd, - pRecord, pvTempField, uiBaseNum))) - { - goto Exit; - } - - pLastTIfd->uiCompoundPos = uiCompoundPos++; - - if( !pTIfd) // First time? - { - pTIxd->pNextTIfd = pLastTIfd; // Link first IFD - } - else - { - pTIfd->pNextTIfd = pLastTIfd; - } - uiTempIfdFlags = uiIfdFlags; - if( bOld11Mode) - { - // Default is required for each field. - uiTempIfdFlags &= ~IFD_OPTIONAL; - uiTempIfdFlags |= (IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); - } - - for( pvIfdField = pRecord->firstChild( pvTempField); - pvIfdField; pvIfdField = pRecord->nextSibling( pvIfdField)) - { - switch ( pRecord->getFieldID( pvIfdField)) - { - // - // General IFD options only for this field GROUP - // - case FLM_CASE_TAG: - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); - - if( f_strnicmp( szNativeBuf, "UPPE", 4) == 0) - { - uiTempIfdFlags |= IFD_UPPER; - } - break; - - case FLM_FIELD_TAG: - break; - - case FLM_OPTIONAL_TAG: - if( bOld11Mode) - { - // Old 11 format - default for each field is required. - uiTempIfdFlags |= IFD_OPTIONAL; - uiTempIfdFlags &= ~(IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); - } - // New format default is optional - break; - - case FLM_PAIRED_TAG: - uiTempIfdFlags |= IFD_FIELDID_PAIR; - break; - - case FLM_POST_TAG: - // FUTURE: Post piece where other pieces are not - uiTempIfdFlags |= IFD_POST; - break; - - case FLM_REQUIRED_TAG: - bHasRequiredTag = TRUE; - uiTempIfdFlags &= ~IFD_OPTIONAL; - uiTempIfdFlags |= (IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); - break; - - case FLM_LIMIT_TAG: - if( RC_BAD( pRecord->getUINT( pvIfdField, &uiTemp)) || - uiTemp > IFD_DEFAULT_LIMIT) - { - pLastTIfd->uiLimit = IFD_DEFAULT_LIMIT; - } - else - { - pLastTIfd->uiLimit = uiTemp; - } - break; - - case FLM_UNIQUE_TAG: - // FUTURE: option to select specific unique fields. - uiTempIfdFlags |= IFD_UNIQUE_PIECE; - pTIxd->uiFlags |= IXD_UNIQUE; - break; - - case FLM_USE_TAG: - // All these are exclusive values. Take the last value. - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); - - if( f_strnicmp( szNativeBuf, "EACH", 4) == 0) - { - uiTempIfdFlags |= IFD_EACHWORD; - uiTempIfdFlags &= ~(IFD_VALUE|IFD_SUBSTRING); - } - else if( f_strnicmp( szNativeBuf, "SUBS", 4) == 0) - { - pTIxd->uiFlags |= IXD_HAS_SUBSTRING; - uiTempIfdFlags |= IFD_SUBSTRING; - uiTempIfdFlags &= ~(IFD_VALUE|IFD_EACHWORD); - if( pLastTIfd->uiLimit == IFD_DEFAULT_LIMIT) - { - pLastTIfd->uiLimit = IFD_DEFAULT_SUBSTRING_LIMIT; - } - } - else if( f_strnicmp( szNativeBuf, "VALU", 4) == 0) - { - uiTempIfdFlags |= IFD_VALUE; - uiTempIfdFlags &= ~(IFD_EACHWORD|IFD_SUBSTRING); - } - else if( f_strnicmp( szNativeBuf, "FIEL", 4) == 0) - { - uiTempIfdFlags |= IFD_CONTEXT; - uiTempIfdFlags &= ~(IFD_VALUE|IFD_EACHWORD|IFD_SUBSTRING); - } - break; - - case FLM_FILTER_TAG: - uiNLen = sizeof( szNativeBuf); - (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); - - if( f_strnicmp( szNativeBuf, "MINS", 4) == 0) - { - uiTempIfdFlags |= IFD_MIN_SPACES; - } - else if( f_strnicmp( szNativeBuf, "NOUN", 4) == 0) - { - uiTempIfdFlags |= IFD_NO_UNDERSCORE; - } - else if( f_strnicmp( szNativeBuf, "NOSP", 4) == 0) - { - uiTempIfdFlags |= IFD_NO_SPACE; - } - else if( f_strnicmp( szNativeBuf, "NODA", 4) == 0) - { - uiTempIfdFlags |= IFD_NO_DASH; - } - else - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - break; - - default: - if( pRecord->getFieldID( pvIfdField) < FLM_UNREGISTERED_TAGS && - pRecord->getFieldID( pvIfdField) != FLM_COMMENT_TAG) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - break; - } // end switch - } // end for loop parsing all level 3 tags - - // Parse again the level 3 field definitions. Now we - // have the IFD uiFlags value to assign each piece that - // will have the same compound position. - - pLastTIfd->uiFlags |= uiTempIfdFlags; - - for( pvIfdField = pRecord->firstChild( pvTempField); - pvIfdField; pvIfdField = pRecord->nextSibling( pvIfdField)) - { - if( pRecord->getFieldID( pvIfdField) == FLM_FIELD_TAG ) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - break; // Done parsing "2 field xx yy zz" - - default: - if( bOld11Mode) - { - break; - } - - if( pRecord->getFieldID( pvTempField) < FLM_UNREGISTERED_TAGS && - pRecord->getFieldID( pvTempField) != FLM_COMMENT_TAG) - - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - break; - } // end switch - - } // end for loop - - // Special case for optional - if( !bHasRequiredTag) - { - // Set all of the IFD flags to IFD_REQUIRED_IN_SET - for( pTIfd = pTIxd->pNextTIfd; pTIfd; pTIfd = pTIfd->pNextTIfd) - { - pTIfd->uiFlags |= IFD_REQUIRED_IN_SET; - } - } - break; - - default: - if( pRecord->getFieldID( pvField) < FLM_UNREGISTERED_TAGS && - pRecord->getFieldID( pvField) != FLM_COMMENT_TAG) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - break; - } - } - pDDEntry->vpDef = (void *) pTIxd; - -Exit: - - if( RC_BAD(rc)) - { - if( pvIfdField) - pTDict->uiBadField = pRecord->getFieldID( pvIfdField); - else if( pvTempField) - pTDict->uiBadField = pRecord->getFieldID( pvTempField); - else if( pvField) - pTDict->uiBadField = pRecord->getFieldID( pvField); - } - else - { - pTDict->uiNewIxds++; - pTDict->uiNewIfds += pTIxd->uiNumFlds; - pTDict->uiNewLFiles++; - } - return( rc ); -} - -/**************************************************************************** -Desc: Build field path for each index field. This function will also - check for the existence of the 'batch' option for QF indexes. -****************************************************************************/ -FSTATIC RCODE DDBuildFldPath( - TDICT * pTDict, - TIFD ** ppTIfd, - FlmRecord * pRecord, - void * pvField, - FLMUINT uiBaseNum) -{ - RCODE rc = FERR_OK; - TIFD * pTIfd; - TIFP * pLastFldPath; - TIFP * pTIfp; - FLMUINT uiNumInFldPath; - char szNameBuf[ 32 ]; - char * pszCurrent; - char szNativeBuf[ FDD_MAX_VALUE_SIZE]; - FLMUINT uiBufLen; - FLMUINT uiPos; - - pTDict->uiTotalIfds++; - if( (pTIfd = (TIFD *) GedPoolAlloc( &pTDict->pool, sizeof( TIFD))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTIfd->pTIfp = NULL; - pTIfd->pNextTIfd = NULL; - pTIfd->uiFlags = 0; - pTIfd->uiNextFixupPos = 0; - pTIfd->uiLimit = IFD_DEFAULT_LIMIT; - pTIfd->uiCompoundPos = 0; - - pLastFldPath = NULL; - *ppTIfd = pTIfd; - - // Build the field paths - - DDTextToNative( pRecord, pvField, szNativeBuf, - FDD_MAX_VALUE_SIZE, &uiBufLen); - - pszCurrent = szNativeBuf; - uiNumInFldPath = uiPos = 0; - - if( uiBaseNum ) - { - uiNumInFldPath++; - if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, - sizeof( TIFP ))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pTIfp->pNextTIfp = NULL; - pTIfp->bFieldInThisDict = FALSE; - pTIfp->uiFldNum = uiBaseNum; - pTIfd->pTIfp = pTIfp; - pLastFldPath = pTIfp; - } - - while( uiPos < uiBufLen) - { - uiNumInFldPath++; - if( DDMoveWord( szNameBuf, pszCurrent, - sizeof( szNameBuf ), &uiPos ) == FALSE ) - { - break; - } - - if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, - sizeof( TIFP ))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pTIfp->pNextTIfp = NULL; - pTIfp->bFieldInThisDict = FALSE; - - if( pTIfd->pTIfp == NULL) - { - pTIfd->pTIfp = pTIfp; - } - else - { - pLastFldPath->pNextTIfp = pTIfp; - } - - pLastFldPath = pTIfp; - - // See if there is a wildcard in the path. - - if (f_stricmp( szNameBuf, "*") == 0) - { - if (pTDict->pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_50) - { - rc = RC_SET( FERR_UNSUPPORTED_FEATURE); - goto Exit; - } - else - { - pTIfp->uiFldNum = FLM_ANY_FIELD; - } - } - else - { - if( RC_BAD( rc = DDGetReference( NULL, NULL, szNameBuf, - &pTIfp->uiFldNum))) - { - goto Exit; - } - } - } - - if( uiNumInFldPath == 0) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - // Cannot have wildcard in last field of field path. - - if (pLastFldPath->uiFldNum == FLM_ANY_FIELD) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - // Single field has the field NULL terminated - - if( uiNumInFldPath == 1 ) - { - pTDict->uiNewFldPaths += 2; - } - else - { - // The field paths are stored child to parent and parent to child - // each are zero terminated. - - pTDict->uiNewFldPaths += 2 * (uiNumInFldPath + 1); - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Parse a data dictionary domain definition for correct syntax & - assign the correct attributes. -****************************************************************************/ -FSTATIC RCODE DDContainerParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord) -{ - RCODE rc = FERR_OK; - void * pvField = NULL; - - if( pDDEntry) - { - - if( (pvField = pRecord->firstChild( pRecord->root())) != NULL) - { - for( ; pvField; pvField = pRecord->nextSibling( pvField)) - { - // Only option is unregistered fields - - if( pRecord->getFieldID( pvField) < FLM_FREE_TAG_NUMS) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - } - } - -Exit: - - if( RC_BAD(rc) && pvField) - { - pTDict->uiBadField = pRecord->getFieldID( pvField); - } - - return( rc ); -} - -/**************************************************************************** -Desc: Parse a data dictionary domain definition for correct syntax & - assign the correct attributes. -****************************************************************************/ -FSTATIC RCODE DDEncDefParse( - TDICT * pTDict, - DDENTRY * pDDEntry, - FlmRecord * pRecord, - FLMUINT uiDictRecNum) -{ - RCODE rc = FERR_OK; - void * pvField = NULL; - TENCDEF * pTEncDef; - - // Make sure the version of the database is correct for encryption. - - if (pTDict->pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_60) - { - rc = RC_SET( FERR_UNSUPPORTED_FEATURE); - goto Exit; - } - - if( (pTEncDef = (TENCDEF *)GedPoolAlloc( &pTDict->pool, - sizeof(TENCDEF))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pTEncDef->uiRecNum = uiDictRecNum; - pTEncDef->uiAlgType = 0; - pTEncDef->uiState = 0; - pTEncDef->pucKeyInfo = NULL; - pTEncDef->uiLength = 0; - - if( pDDEntry) - { - - if( (pvField = pRecord->firstChild( pRecord->root())) != NULL) - { - for( ; pvField; pvField = pRecord->nextSibling( pvField)) - { - switch ( pRecord->getFieldID( pvField) ) - { - case FLM_TYPE_TAG: - { - // Get the encryption type. - if (RC_BAD( rc = DDGetEncType( pRecord, - pvField, - &pTEncDef->uiAlgType))) - { - goto Exit; - } - break; - } - - case FLM_KEY_TAG: - { - // Get the key information. - if (RC_BAD( rc = DDGetEncKey( pTDict, - pRecord, - pvField, - pTEncDef))) - { - goto Exit; - } - break; - } - - case FLM_STATE_TAG: - { - // Get the status information. - if (RC_BAD( rc = DDParseStateOptions( pRecord, - pvField, - &pTEncDef->uiState))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - } - - pDDEntry->vpDef = (void *)pTEncDef; - - } - else - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - -Exit: - - if (RC_BAD( rc) && pvField) - { - pTDict->uiBadField = pRecord->getFieldID( pvField); - } - - return( rc ); -} - -/**************************************************************************** -Desc: Move word delimited by spaces from src to dest. Used to move a - word at a time for field path lists. -Notes: Isolated so changes can be made to delemeting NAMES. -Visit: Still bugs when name > buffer size - won't happen because only #'s -****************************************************************************/ -FSTATIC FLMBOOL DDMoveWord( - char * pucDest, - char * pucSrc, - FLMUINT uiMaxDestLen, - FLMUINT * puiPos) -{ - FLMBOOL bFoundWord = TRUE; - FLMUINT uiPos = *puiPos; - char * pMatch; - FLMUINT uiBytesToCopy; - - pucSrc += uiPos; - while( *pucSrc == NATIVE_SPACE) - { - pucSrc++; - } - - pMatch = pucSrc; - while( *pMatch > NATIVE_SPACE) - { - pMatch++; - } - - if( !*pMatch) - { - if( *pucSrc == '\0') - { - bFoundWord = FALSE; - goto Exit; - } - - uiBytesToCopy = f_strlen( pucSrc); - - if( uiBytesToCopy + 1 > uiMaxDestLen) - { - uiBytesToCopy = uiMaxDestLen - 1; - } - - f_memcpy( pucDest, pucSrc, uiBytesToCopy + 1); - *puiPos = uiPos + uiBytesToCopy + 1; - } - else - { - // Copy the bytes between pucSrc and pMatch minus one - - uiBytesToCopy = (FLMUINT) (pMatch - pucSrc); - - if( uiBytesToCopy + 1 > uiMaxDestLen) - { - uiBytesToCopy = uiMaxDestLen - 1; - } - - f_memcpy( pucDest, pucSrc, uiBytesToCopy ); - pucDest[ uiBytesToCopy ] = '\0'; - - // Go past consuctive spaces - - while( pucSrc[ ++uiBytesToCopy ] == NATIVE_SPACE) - { - uiBytesToCopy++; - } - - *puiPos = uiPos + uiBytesToCopy; - } - -Exit: - - return( bFoundWord); -} - -/**************************************************************************** -Desc: Normalizes an internal string with possible formatting codes into - a NATIVE string. Drops all formatting codes and extended chars. -****************************************************************************/ -FSTATIC void DDTextToNative( - FlmRecord * pRecord, - void * pvField, - char * pszBuffer, - FLMUINT uiBufLen, - FLMUINT * puiBufLen) -{ - RCODE rc = FERR_OK; - - pszBuffer[ 0] = 0; - - if( pRecord->getDataLength( pvField)) - { - if( RC_BAD( rc = pRecord->getNative( pvField, pszBuffer, &uiBufLen))) - { - if( rc != FERR_CONV_DEST_OVERFLOW) - { - pszBuffer[0] = 0; - uiBufLen = 0; - } - } - } - else - { - uiBufLen = 0; - } - - if( puiBufLen) - { - // Length needs to include the null byte - - *puiBufLen = uiBufLen + 1; - } - - return; -} diff --git a/flaim/src/ecache.h b/flaim/src/ecache.h index 5b264d0..388bedd 100644 --- a/flaim/src/ecache.h +++ b/flaim/src/ecache.h @@ -37,7 +37,7 @@ typedef FLMUINT64 ESMADDR64; #pragma pack(push, 1) #endif -typedef struct +typedef struct ESMQueryInfo { FLMUINT64 ui64TotalExtendedMemory; FLMUINT64 ui64RemainingExtendedMemory; @@ -74,7 +74,7 @@ typedef FLMUINT (* ESM_MAP_MEM_FUNC)( ESMADDR64 esmAddress, FLMUINT32 ui32Size); -typedef struct +typedef struct ECACHE_HDR { ESMADDR64 esmAddr; FLMUINT uiStartBlkAddr; diff --git a/flaim/src/f64bitfh.cpp b/flaim/src/f64bitfh.cpp index 052f234..3f7cc6a 100644 --- a/flaim/src/f64bitfh.cpp +++ b/flaim/src/f64bitfh.cpp @@ -69,9 +69,7 @@ void F_64BitFileHandle::ReleaseLockFile( if( m_pLockFileHdl) { - /* - Release the lock file - */ + // Release the lock file (void)m_pLockFileHdl->Close(); m_pLockFileHdl->Release(); @@ -82,9 +80,7 @@ void F_64BitFileHandle::ReleaseLockFile( { char szTmpPath[ F_PATH_MAX_SIZE]; - /* - Delete the lock file - */ + // Delete the lock file f_strcpy( szTmpPath, pszBasePath); f_pathAppend( szTmpPath, "64.LCK"); @@ -132,9 +128,7 @@ void F_64BitFileHandle::Close( if( RC_OK( gv_FlmSysData.pFileSystem->OpenDir( m_ucPath, "*.64", &pDir))) { - /* - Remove all data files - */ + // Remove all data files for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next() ) { @@ -147,15 +141,11 @@ void F_64BitFileHandle::Close( pDir = NULL; } - /* - Release and delete the lock file - */ + // Release and delete the lock file (void)ReleaseLockFile( m_ucPath, TRUE); - /* - Remove the directory - */ + // Remove the directory (void)gv_FlmSysData.pFileSystem->RemoveDir( m_ucPath); } @@ -192,10 +182,8 @@ RCODE F_64BitFileHandle::Delete( if( !gv_FlmSysData.pFileSystem->IsDir( pszPath)) { - /* - If the path specifies a single file rather than a - 64-bit directory, just go ahead and delete the file. - */ + // If the path specifies a single file rather than a + // 64-bit directory, just go ahead and delete the file. rc = gv_FlmSysData.pFileSystem->Delete( pszPath); goto Exit; @@ -209,9 +197,7 @@ RCODE F_64BitFileHandle::Delete( if( RC_OK( gv_FlmSysData.pFileSystem->OpenDir( pszPath, "*.64", &pDir))) { - /* - Remove all data files - */ + // Remove all data files for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next()) { @@ -225,22 +211,17 @@ RCODE F_64BitFileHandle::Delete( rc = FERR_OK; } - /* - Release and delete the lock file - */ + // Release and delete the lock file (void)ReleaseLockFile( pszPath, TRUE); - /* - Remove the directory - */ + // Remove the directory (void)gv_FlmSysData.pFileSystem->RemoveDir( pszPath); Exit: (void)ReleaseLockFile( pszPath, FALSE); - return( rc); } @@ -267,27 +248,21 @@ RCODE F_64BitFileHandle::Create( f_strcpy( m_ucPath, pszPath); bCreatedDir = TRUE; - /* - Create the lock file - */ + // Create the lock file if( RC_BAD( rc = CreateLockFile( m_ucPath))) { goto Exit; } - /* - Initialize the EOF to 0 and set the state to open - */ + // Initialize the EOF to 0 and set the state to open m_ui64EOF = 0; m_bOpen = TRUE; Exit: - /* - Release the lock file - */ + // Release the lock file if( RC_BAD( rc)) { @@ -364,27 +339,21 @@ RCODE F_64BitFileHandle::CreateUnique( f_strcpy( m_ucPath, szTmpPath); bCreatedDir = TRUE; - /* - Create the lock file - */ + // Create the lock file if( RC_BAD( rc = CreateLockFile( m_ucPath))) { goto Exit; } - /* - Initialize the EOF to 0 and set the state to open - */ + // Initialize the EOF to 0 and set the state to open m_ui64EOF = 0; m_bOpen = TRUE; Exit: - /* - Release the lock file - */ + // Release the lock file if( RC_BAD( rc)) { @@ -426,18 +395,14 @@ RCODE F_64BitFileHandle::Open( f_strcpy( m_ucPath, pszPath); - /* - Create the lock file - */ + // Create the lock file if( RC_BAD( rc = CreateLockFile( m_ucPath))) { goto Exit; } - /* - Need to determine the current EOF - */ + // Need to determine the current EOF if( RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenDir( m_ucPath, "*.64", &pDir))) @@ -445,9 +410,7 @@ RCODE F_64BitFileHandle::Open( goto Exit; } - /* - Find all data files to determine the EOF - */ + // Find all data files to determine the EOF for( rc = pDir->Next(); !RC_BAD( rc) ; rc = pDir->Next() ) { @@ -473,9 +436,7 @@ Exit: pDir->Release(); } - /* - Release the lock file - */ + // Release the lock file if( RC_BAD( rc)) { @@ -534,9 +495,7 @@ RCODE F_64BitFileHandle::Read( FLMUINT uiMaxReadLen; F_FileHdl * pFileHdl; - /* - Handle the case of a 0-byte read - */ + // Handle the case of a 0-byte read if( !uiLength) { @@ -547,9 +506,7 @@ RCODE F_64BitFileHandle::Read( goto Exit; } - /* - Read the data file(s), moving to new files as needed. - */ + // Read the data file(s), moving to new files as needed. for( ;;) { @@ -570,10 +527,8 @@ RCODE F_64BitFileHandle::Read( { if( rc == FERR_IO_PATH_NOT_FOUND) { - /* - Handle the case of a sparse file by filling the unread - portion of the buffer with zeros. - */ + // Handle the case of a sparse file by filling the unread + // portion of the buffer with zeros. f_memset( pvBuffer, 0, uiBytesToRead); uiTmp = uiBytesToRead; @@ -591,10 +546,8 @@ RCODE F_64BitFileHandle::Read( { if( rc == FERR_IO_END_OF_FILE) { - /* - Handle the case of a sparse file by filling the unread - portion of the buffer with zeros. - */ + // Handle the case of a sparse file by filling the unread + // portion of the buffer with zeros. f_memset( &(((FLMBYTE *)(pvBuffer))[ uiTmp]), 0, (FLMUINT)(uiBytesToRead - uiTmp)); @@ -615,9 +568,7 @@ RCODE F_64BitFileHandle::Read( break; } - /* - Set up for next read - */ + // Set up for next read pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp; ui64Offset += uiTmp; @@ -649,15 +600,11 @@ RCODE F_64BitFileHandle::Write( FLMUINT uiMaxWriteLen; F_FileHdl * pFileHdl; - /* - Don't allow zero-length writes - */ + // Don't allow zero-length writes flmAssert( uiLength); - /* - Write to the data file(s), moving to new files as needed. - */ + // Write to the data file(s), moving to new files as needed. for( ;;) { @@ -687,9 +634,7 @@ RCODE F_64BitFileHandle::Write( break; } - /* - Set up for next write - */ + // Set up for next write pvBuffer = ((FLMBYTE *)pvBuffer) + uiTmp; uiFileNum = GetFileNum( ui64Offset); @@ -818,9 +763,7 @@ RCODE F_64BitFileHandle::GetFileNum( } else { - /* - Invalid character found in the file name - */ + // Invalid character found in the file name rc = RC_SET( FERR_IO_INVALID_PATH); goto Exit; @@ -853,13 +796,11 @@ RCODE F_64BitFileHandle::CreateLockFile( f_strcpy( szLockPath, pszBasePath); f_pathAppend( szLockPath, "64.LCK"); - /* - Attempt to create the lock file. If it fails, the lock file - may have been left because of a crash. Hence, we first try - to delete the file. If that succeeds, we then attempt to - create the file again. If it, or the 2nd create fail, we simply - return an access denied error. - */ + // Attempt to create the lock file. If it fails, the lock file + // may have been left because of a crash. Hence, we first try + // to delete the file. If that succeeds, we then attempt to + // create the file again. If it, or the 2nd create fail, we simply + // return an access denied error. #ifndef FLM_UNIX if( RC_BAD( gv_FlmSysData.pFileSystem->Create( szLockPath, diff --git a/flaim/src/f64bitfh.h b/flaim/src/f64bitfh.h index b96a646..40fd00c 100644 --- a/flaim/src/f64bitfh.h +++ b/flaim/src/f64bitfh.h @@ -33,7 +33,7 @@ #define F_64BIT_FHDL_LIST_SIZE 8 #define F_64BIT_FHDL_DEFAULT_MAX_FILE_SIZE ((FLMUINT)0xFFFFFFFF) -typedef struct +typedef struct FH_INFO { F_FileHdl * pFileHdl; FLMUINT uiFileNum; diff --git a/flaim/src/f_coltb1.cpp b/flaim/src/f_coltb1.cpp deleted file mode 100644 index d5ac840..0000000 --- a/flaim/src/f_coltb1.cpp +++ /dev/null @@ -1,403 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Collation tables to convert to/from WP characters. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: f_coltb1.cpp 12245 2006-01-19 14:29:51 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/* COMMENTS FROM WPSRTR.ASM */ -/* The code calls tskip() that skips all commas. - don't know why */ - - -/* Better agree with COLLSx+y values in wp_char.h and COLTBL.C */ -/* Character offset is COLS1 - length is COLS11 - COLLS = SHOULD BE 203 */ - -FLMUINT16 colToWPChr[ COLS11 - COLLS ] = { - 0x20, /* colls - */ - 0x2e, /* colls+1 - . */ - 0x2c, /* colls+2 - , */ - 0x3a, /* colls+3 - : */ - 0x3b, /* colls+4 - ; */ - 0x21, /* colls+5 - ! */ - 0, /* colls+6 - NO VALUE */ - 0x3f, /* colls+7 - ? */ - 0, /* colls+8 - NO VALUE */ - - 0x22, /* cols1 - " */ - 0x27, /* cols1+1 - ' */ - 0x60, /* cols1+2 - ` */ - 0, /* cols1+3 - NO VALUE */ - 0, /* cols1+4 - NO VALUE */ - - 0x28, /* cols2 - ( */ - 0x29, /* cols2+1 - ) */ - 0x5b, /* cols2+2 - japanese angle brackets */ - 0x5d, /* cols2+3 - japanese angle brackets */ - 0x7b, /* cols2+4 - { */ - 0x7d, /* cols2+5 - } */ - - 0x24, /* cols3 - $ */ - 0x413, /* cols3+1 - cent */ - 0x40b, /* cols3+2 - pound */ - 0x40c, /* cols3+3 - yen */ - 0x40d, /* cols3+4 - pacetes */ - 0x40e, /* cols3+5 - floren */ - - 0x2b, /* cols4 - + */ - 0x2d, /* cols4+1 - - */ - 0x2a, /* cols4+2 - * */ - 0x2f, /* cols4+3 - / */ - 0x5e, /* cols4+4 - ^ */ - 0, /* cols4+5 - NO VALUE */ - 0, /* cols4+6 - NO VALUE */ - 0, /* cols4+7 - NO VALUE */ - - 0x3c, /* cols5 - < */ - 0, /* cols5+1 - NO VALUE */ - 0x3d, /* cols5+2 - = */ - 0, /* cols5+3 - NO VALUE */ - 0x3e, /* cols5+4 - > */ - 0, /* cols5+5 - NO VALUE */ - 0, /* cols5+6 - NO VALUE */ - 0, /* cols5+7 - NO VALUE */ - 0, /* cols5+8 - NO VALUE */ - 0, /* cols5+9 - NO VALUE */ - 0, /* cols5+10 - NO VALUE */ - 0, /* cols5+11 - NO VALUE */ - 0, /* cols5+12 - NO VALUE */ - 0, /* cols5+13 - NO VALUE */ - - 0x25, /* cols6 - % */ - 0x23, /* cols6+1 - # */ - 0x26, /* cols6+2 - & */ - 0x40, /* cols6+3 - @ */ - 0x5c, /* cols6+4 - \ */ - 0x5f, /* cols6+5 - _ */ - 0x7c, /* cols6+6 - | */ - 0x7e, /* cols6+7 - ~ */ - 0, /* cols6+8 - NO VALUE */ - 0, /* cols6+9 - NO VALUE */ - 0, /* cols6+10 - NO VALUE */ - 0, /* cols6+11 - NO VALUE */ - 0, /* cols6+12 - NO VALUE */ - - 0x800, /* cols7 - Uppercase Alpha */ - 0x802, /* cols7+1 - Uppercase Beta */ - 0x806, /* cols7+2 - Uppercase Gamma */ - 0x808, /* cols7+3 - Uppercase Delta */ - 0x80a, /* cols7+4 - Uppercase Epsilon */ - 0x80c, /* cols7+5 - Uppercase Zeta */ - 0x80e, /* cols7+6 - Uppercase Eta */ - 0x810, /* cols7+7 - Uppercase Theta */ - 0x812, /* cols7+8 - Uppercase Iota */ - 0x814, /* cols7+9 - Uppercase Kappa */ - 0x816, /* cols7+10 - Uppercase Lambda */ - 0x818, /* cols7+11 - Uppercase Mu */ - 0x81a, /* cols7+12 - Uppercase Nu */ - 0x81c, /* cols7+13 - Uppercase Xi */ - 0x81e, /* cols7+14 - Uppercase Omicron */ - 0x820, /* cols7+15 - Uppercase Pi */ - 0x822, /* cols7+16 - Uppercase Rho */ - 0x824, /* cols7+17 - Uppercase Sigma */ - 0x828, /* cols7+18 - Uppercase Tau */ - 0x82a, /* cols7+19 - Uppercase Upsilon */ - 0x82c, /* cols7+20 - Uppercase Phi */ - 0x82e, /* cols7+21 - Uppercase Chi */ - 0x830, /* cols7+22 - Uppercase Psi */ - 0x832, /* cols7+23 - Uppercase Omega */ - 0, /* cols7+24 - NO VALUE */ - - 0x30, /* cols8 - 0 */ - 0x31, /* cols8+1 - 1 */ - 0x32, /* cols8+2 - 2 */ - 0x33, /* cols8+3 - 3 */ - 0x34, /* cols8+4 - 4 */ - 0x35, /* cols8+5 - 5 */ - 0x36, /* cols8+6 - 6 */ - 0x37, /* cols8+7 - 7 */ - 0x38, /* cols8+8 - 8 */ - 0x39, /* cols8+9 - 9 */ -/*0x80*/ - 0x41, /* cols9 - A */ - 0x124, /* cols9+1 - AE digraph */ - 0x42, /* cols9+2 - B */ - 0x43, /* cols9+3 - C */ - 0xffff, /* cols9+4 - CH in spanish */ - 0x162, /* cols9+5 - Holder for C caron in Czech */ - 0x44, /* cols9+6 - D */ - 0x45, /* cols9+7 - E */ - 0x46, /* cols9+8 - F */ - 0x47, /* cols9+9 - G */ - 0x48, /* cols9+10 - H */ - 0xffff, /* cols9+11 - CH in czech or dotless i in turkish */ - 0x49, /* cols9+12 - I */ - 0x18a, /* cols9+13 - IJ Digraph */ - 0x4a, /* cols9+14 - J */ - 0x4b, /* cols9+15 - K */ - 0x4c, /* cols9+16 - L */ - 0xffff, /* cols9+17 - LL in spanish */ - 0x4d, /* cols9+18 - M */ - 0x4e, /* cols9+19 - N */ - 0x138, /* cols9+20 - N Tilde */ - 0x4f, /* cols9+21 - O */ - 0x1a6, /* cols9+22 - OE digraph */ - 0x50, /* cols9+23 - P */ - 0x51, /* cols9+24 - Q */ - 0x52, /* cols9+25 - R */ - 0x1aa, /* cols9+26 - Holder for R caron in Czech */ - 0x53, /* cols9+27 - S */ - 0x1b0, /* cols9+28 - Holder for S caron in Czech */ - 0x54, /* cols9+29 - T */ - 0x55, /* cols9+30 - U */ - 0x56, /* cols9+31 - V */ -/*0xA0*/ - 0x57, /* cols9+32 - W */ - 0x58, /* cols9+33 - X */ - 0x59, /* cols9+34 - Y */ - 0x5a, /* cols9+35 - Z */ - 0x1ce, /* cols9+36 - Holder for Z caron in Czech */ - 0x158, /* cols9+37 - Uppercase Thorn */ - 0, /* cols9+38 - ??? */ - 0, /* cols9+39 - ??? */ - 0x5b, /* cols9+40 - [ (note: alphabetic - end of list) */ - 0x5d, /* cols9+41 - ] (note: alphabetic - end of list) */ -/*0xAA - also start of Hebrew */ - 0x124, /* cols9+42 - AE diagraph - DK */ - 0x124, /* cols9+43 - AE diagraph - NO */ - 0x122, /* cols9+44 - A ring - SW */ - 0x11E, /* cols9+45 - A diaeresis - DK */ - 0x124, /* cols9+46 - AE diagraph - IC */ - 0x150, /* cols9+47 - O slash - NO */ - 0x11e, /* cols9+48 - A diaeresis - SW */ - 0x150, /* cols9+49 - O slash - DK */ - 0x13E, /* cols9+50 - O Diaeresis - IC */ - 0x122, /* cols9+51 - A ring - NO */ - 0x13E, /* cols9+52 - O Diaeresis - SW */ - 0x13E, /* cols9+53 - O Diaeresis - DK */ - 0x150, /* cols9+54 - O slash - IC */ - 0x122, /* cols9+55 - A ring - DK */ - 0x124, /* cols9+56 - AE diagraph future */ - 0x13E, /* cols9+57 - O Diaeresis future */ - 0x150, /* cols9+58 - O slash future */ - 0, /* cols9+59 - NOT USED future */ - - 0xA00, /* cols10 - Russian A */ - 0xA02, /* cols10+1 - Russian BE */ - 0xA04, /* cols10+2 - Russian VE */ - 0xA06, /* cols10+3 - Russian GHE */ - 0xA46, /* cols10+4 - Ukrainian HARD G */ - 0xA08, /* cols10+5 - Russian DE */ - 0xA4a, /* cols10+6 - Serbian SOFT DJ */ - 0xA44, /* cols10+7 - Macedonian SOFT DJ */ - 0xA0a, /* cols10+8 - Russian E */ - 0xA0c, /* cols10+9 - Russian YO */ - 0xA4e, /* cols10+10 - Ukrainian YE */ - 0xA0e, /* cols10+11 - Russian ZHE */ - 0xA10, /* cols10+12 - Russian ZE */ - 0xA52, /* cols10+13 - Macedonian ZELO */ - 0xA12, /* cols10+14 - Russian I */ - 0xA58, /* cols10+15 - Ukrainian I */ - 0xA5a, /* cols10+16 - Ukrainian I with Two dots */ - 0xA14, /* cols10+17 - Russian SHORT I */ - 0xA5e, /* cols10+18 - Serbian--Macedonian JE */ - 0xA16, /* cols10+19 - Russian KA */ - 0xA18, /* cols10+20 - Russian EL */ - 0xA68, /* cols10+21 - Serbian--Macedonian SOFT L */ - 0xA1a, /* cols10+22 - Russian EM */ - 0xA1c, /* cols10+23 - Russian EN */ - 0xA6c, /* cols10+24 - Serbian--Macedonian SOFT N */ - 0xA1e, /* cols10+25 - Russian O */ - 0xA20, /* cols10+26 - Russian PE */ - 0xA22, /* cols10+27 - Russian ER */ - 0xA24, /* cols10+28 - Russian ES */ - 0xA26, /* cols10+29 - Russian TE */ - 0xA72, /* cols10+30 - Serbian SOFT T */ - 0xA60, /* cols10+31 - Macedonian SOFT K */ - 0xA28, /* cols10+32 - Russian U */ - 0xA74, /* cols10+33 - Byelorussian SHORT U */ - 0xA2a, /* cols10+34 - Russian EF */ - 0xA2c, /* cols10+35 - Russian HA */ - 0xA2e, /* cols10+36 - Russian TSE */ - 0xA30, /* cols10+37 - Russian CHE */ - 0xA86, /* cols10+38 - Serbian HARD DJ */ - 0xA32, /* cols10+39 - Russian SHA */ - 0xA34, /* cols10+40 - Russian SHCHA */ - 0xA36, /* cols10+41 - Russian ER (also hard */ - 0xA38, /* cols10+42 - Russian ERY */ - 0xA3a, /* cols10+43 - Russian SOFT SIGN */ - 0xA8e, /* cols10+44 - Old Russian YAT */ - 0xA3c, /* cols10+45 - Russian uppercase REVERSE E */ - 0xA3e, /* cols10+46 - Russian YU */ - 0xA40, /* cols10+47 - Russian YA */ - 0xA3a, /* cols10+48 - Russian SOFT SIGN - UKRAIN ONLY */ - 0 /* cols10+49 - future */ -}; - -FLMUINT16 HebArabColToWPChr[ ] = { - /* Start at COLS10a+0 */ -/*[0]*/ - 0x0D00 +164, /* hamzah */ - 0x0D00 + 58, /* [13,177] alef maddah */ - /* Read subcollation to get other alef values */ - 0x0D00 + 60, /* baa */ - 0x0E00 + 48, /* Sindhi bb */ - 0x0E00 + 52, /* Sindhi bh */ - 0x0E00 + 56, /* Misc p = peh */ - 0x0D00 +152, /* taa marbuuTah */ - /* subcollation of 1 is taa [13,64] */ - 0x0E00 + 60, /* Urdu T [14,60] */ - /* Pashto T [14,64] */ -/*[8]*/ - 0x0D00 + 68, /* thaa */ - 0x0E00 + 68, /* Sindhi th */ - 0x0E00 + 72, /* Sindhi tr */ - 0x0E00 + 76, /* Sindhi Th */ - 0x0D00 + 72, /* jiim - jeem */ - 0x0E00 + 80, /* Sindhi jj */ - 0x0E00 + 84, /* Sindhi ny */ - 0x0E00 + 88, /* Misc ch */ - /* Sinhi chh [14,92] */ -/*[16]*/ - 0x0D00 + 76, /* Haa */ - 0x0D00 + 80, /* khaa */ - 0x0E00 + 96, /* Pashto ts */ - 0x0E00 +100, /* Pashto dz */ - - 0x0D00 + 84, /* dal */ - 0x0E00 +104, /* Urdu D */ - /* Pashto D */ - 0x0D00 + 86, /* thal */ - 0x0E00 +108, /* Sindhi dh */ -/*[24]*/ - 0x0E00 +110, /* Sindhi D */ - 0x0E00 +112, /* Sindhi Dr */ - 0x0E00 +114, /* Sindhi Dh */ - - 0x0D00 + 88, /* ra */ - /* Kurdish rolled r [14,122] */ - 0x0E00 +116, /* Pashto r [14,116] - must pick this! */ - /* Urdu R [14,118] */ - /* Sindhi r [14,120] */ - - 0x0D00 + 90, /* zain */ - 0x0E00 +126, /* Mizc Z=jeh [14,126] */ - /* Pashto zz [14,128] */ - /* Pashto g [14,130] */ - - 0x0D00 + 92, /* seen */ -/*[32]*/ - 0x0D00 + 96, /* sheen */ - 0x0E00 +132, /* Pashto x */ - 0x0D00 +100, /* Sad */ - 0x0D00 +104, /* Dad */ - 0x0D00 +108, /* Tah */ - 0x0D00 +112, /* Za (dhah) */ - 0x0D00 +116, /* 'ain */ - 0x0D00 +120, /* ghain */ - /* malay ng [14,136] */ -/*[40]*/ - 0x0D00 +124, /* fa */ - 0x0E00 +140, /* Malay p, kurdish v = veh */ - /* Sindhi ph [14,144] */ - 0x0D00 +128, /* Qaf */ - 0x0D00 +132, /* kaf (caf) */ - /* Misc k [14,148] */ - /* misc k - no unicode [14,152] */ - /* Sindhi k [14,156] */ - - 0x0E00 +160, /* Persian/Urdu gaf */ - /* gaf - no unicode [14,164] */ - /* malay g [14,168] */ - /* Sindhi ng [14,172] */ - 0x0E00 +176, /* Singhi gg */ - - 0x0D00 +136, /* lam - all ligature variants */ - /* Kurdish valar lam [14,180] */ - /* Kurdish lamalef - no unicode [14,184] */ - - 0x0D00 +140, /* meem */ -/*[48]*/ - 0x0D00 +144, /* noon */ - /* Urdu n [14,186] */ - /* Pashto N [14,190] */ - /* Sindhi N [14,194] */ - 0x0D00 +148, /* ha - arabic language only! */ - 0x0D00 +154, /* waw */ - /* Kurdish o [14,198] */ - /* Kurdish o with bar [14,200] */ - /* Kurdish o with 2 dots [14,202] */ - 0x0D00 +148, /* ha - non-arabic language */ - /* Urdu h [14,204] */ - /* Farsi hamzah on ha [14,218] */ - 0x0D00 +160, /* alef maqsurah */ - /* Kurdish e - ya /w small v */ - - 0x0D00 +156, /* ya */ - 0x0E00 +212 /* Urdu ya barree */ - /* Malay ny [14,214] */ -}; - - -FLMUINT16 ArabSubColToWPChr[] = { - 0x0D00 +177, /* Alef maddah - default value - here for documentation */ - 0x0D00 +165, /* Alef Hamzah */ - 0x0D00 +169, /* Waw hamzah */ - 0x0D00 +167, /* Hamzah under alef */ - 0x0D00 +171, /* ya hamzah */ - 0x0D00 +175, /* alef fathattan */ - 0x0D00 +179, /* alef waslah */ - 0x0D00 + 58, /* alef */ - 0x0D00 + 64 /* taa - after taa marbuuTah */ -}; - - - /* Turns a collated diacritic value into the original diacritic value */ -FLMBYTE ml1_COLtoD[27] = { - 23, /* dbls sort value = 0 sorts as 'ss' */ - 6, /* acute sort value = 1 */ - 0, /* grave sort value = 2 */ - 22, /* breve sort value = 3 */ - 3, /* circum sort value = 4 */ - 19, /* caron sort value = 5 */ - 7, /* umlaut sort value = 6 */ - 2, /* tilde sort value = 7 */ - 14, /* ring sort value = 8 */ - 7, /* umlaut in SU,SV & CZ after ring = 9 */ - 5, /* slash sort value = 10 */ - 17, /* cedilla sort value = 11 */ - 4, /* crossb sort value = 12 */ - 15, /* dota sort value = 13 */ - 18, /* ogonek sort value = 14 */ - 20, /* stroke sort value = 15 */ - 1, /* centerd sort value = 16 */ - 8, /* macron sort value = 17 */ - 9, /* aposab sort value = 18 */ - 10, /* aposbes sort value = 19 */ - 11, /* aposba sort value = 20 */ - 12, /* aposbc sort value = 21 */ - 13, /* abosbl sort value = 22 */ - 16, /* dacute sort value = 23 */ - 21, /* bara sort value = 24 */ - 24, /* dotlesi sort value = 25 */ - 25 /* dotlesj sort value = 26 */ - }; - diff --git a/flaim/src/f_nici.cpp b/flaim/src/f_nici.cpp index 6542bf0..aae95a3 100644 --- a/flaim/src/f_nici.cpp +++ b/flaim/src/f_nici.cpp @@ -43,7 +43,7 @@ char F_Base64Encoder::m_ucEncodeTable[ 64] = ASCII_LOWER_W, ASCII_LOWER_X, ASCII_LOWER_Y, ASCII_LOWER_Z, ASCII_ZERO, ASCII_ONE, ASCII_TWO, ASCII_THREE, ASCII_FOUR, ASCII_FIVE, ASCII_SIX, ASCII_SEVEN, - ASCII_EIGHT, ASCII_NINE, ASCII_PLUS, ASCII_SLASH + ASCII_EIGHT, ASCII_NINE, ASCII_PLUS, ASCII_SLASH }; FLMBYTE F_Base64Decoder::m_ucDecodeTable[ 256] = @@ -169,10 +169,10 @@ RCODE F_CCS::wrapKey( goto Exit; } - f_memset( &wKey, 0, sizeof(NICI_ATTRIBUTE)); + f_memset( &wKey, 0, sizeof( NICI_ATTRIBUTE)); wKey.type = NICI_A_KEY_TYPE; - if( CCS_GetAttributeValue(context, wrappingKeyHandle, &wKey, 1) != 0) + if( CCS_GetAttributeValue( context, wrappingKeyHandle, &wKey, 1) != 0) { rc = RC_SET( FERR_NICI_ATTRIBUTE_VALUE); goto Exit; @@ -194,7 +194,7 @@ RCODE F_CCS::wrapKey( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } @@ -207,7 +207,7 @@ RCODE F_CCS::wrapKey( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } @@ -222,7 +222,7 @@ RCODE F_CCS::wrapKey( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; break; } @@ -268,7 +268,6 @@ Exit: return( rc); } - /**************************************************************************** Desc: ****************************************************************************/ @@ -303,7 +302,7 @@ RCODE F_CCS::unwrapKey( // Create NICI Context - if( CCS_CreateContext(0, &context) != 0) + if( CCS_CreateContext( 0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); goto Exit; @@ -841,7 +840,7 @@ RCODE F_CCS::encryptToStoreAES( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; if( CCS_DataEncryptInit(context, &algorithm, m_keyHandle) != 0) @@ -904,7 +903,7 @@ RCODE F_CCS::decryptFromStoreAES( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption @@ -969,7 +968,7 @@ RCODE F_CCS::encryptToStoreDES3( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption @@ -1036,7 +1035,7 @@ RCODE F_CCS::decryptFromStoreDES3( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption @@ -1101,7 +1100,7 @@ RCODE F_CCS::encryptToStoreDES( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption @@ -1168,7 +1167,7 @@ RCODE F_CCS::decryptFromStoreDES( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ8; /* 8-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ8; algorithm.parameter->parms[0].u.b.ptr = m_pucIV; // Init encryption @@ -1235,7 +1234,7 @@ Exit: } /**************************************************************************** -Desc: Pick a wrapping key that we can use to wrap & +Desc: Pick a wrapping key that we can use to wrap and unwrap the encryption key with. ****************************************************************************/ RCODE F_CCS::getWrappingKey( @@ -1383,7 +1382,7 @@ RCODE F_CCS::getKeyToStore( // The shrouded or wrapped key will be stored in m_pKey. - ui32PaddedLength = (ui32WrappedKeyLen + sizeof( FLMBOOL) + + ui32PaddedLength = (ui32WrappedKeyLen + sizeof( FLMUINT32) + sizeof( FLMUINT32) + IV_SZ ); // Make sure our buffer size is padded to a 16 byte boundary. @@ -1411,15 +1410,13 @@ RCODE F_CCS::getKeyToStore( // Save a flag indicating whether the key is wrapped or encoded in // a password. - UD2FBA( (pszEncKeyPasswd && pszEncKeyPasswd[0]) - ? (FLMUINT)TRUE - : (FLMUINT)FALSE, pucPtr); - pucPtr += sizeof(FLMBOOL); + UD2FBA( (pszEncKeyPasswd && pszEncKeyPasswd[0]) ? 1 : 0, pucPtr); + pucPtr += sizeof( FLMUINT32); // Copy the key length. UD2FBA(ui32WrappedKeyLen, pucPtr); - pucPtr += sizeof(FLMUINT32); + pucPtr += sizeof( FLMUINT32); // Copy the IV too. @@ -1568,8 +1565,7 @@ RCODE F_CCS::setKeyFromStore( // Buffer is Base64 encoded. We must first decode it. - pB64Decoder = f_new F_Base64Decoder; - if (pB64Decoder == NULL) + if( (pB64Decoder = f_new F_Base64Decoder) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -1594,12 +1590,12 @@ RCODE F_CCS::setKeyFromStore( // Extract the fields from the buffer bShrouded = FB2UD( pucTmp); - pucTmp += sizeof(FLMUINT); + pucTmp += sizeof( FLMUINT32); // Actual length - note that the passed buffer is padded to 16 byte boundary. ui32Length = FB2UD( pucTmp); - pucTmp += sizeof(FLMUINT32); + pucTmp += sizeof( FLMUINT32); // Get the IV @@ -1630,7 +1626,7 @@ RCODE F_CCS::setKeyFromStore( // to machines with different byte ordering. if( RC_BAD( rc = f_calloc( f_strlen(pszEncKeyPasswd) + - (f_strlen(pszEncKeyPasswd) % 2) + 2, &pszFormattedEncKeyPasswd))) + (f_strlen( pszEncKeyPasswd) % 2) + 2, &pszFormattedEncKeyPasswd))) { goto Exit; } @@ -2110,7 +2106,6 @@ RCODE F_CCS::injectKey( { case NICI_K_AES: { - /* Set key attributes */ uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_TYPE; keyAttr[uiIndx].u.f.hasValue = 1; @@ -2156,7 +2151,6 @@ RCODE F_CCS::injectKey( } case NICI_K_DES3X: { - /* Set key attributes */ uiIndx = 0; keyAttr[uiIndx].type = NICI_A_KEY_TYPE; keyAttr[uiIndx].u.f.hasValue = 1; @@ -2559,7 +2553,7 @@ RCODE flmDecryptBuffer( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ; algorithm.parameter->parms[0].u.b.ptr = pucIV; // Init encryption @@ -2594,8 +2588,7 @@ Desc: ****************************************************************************/ RCODE flmEncryptBuffer( FLMBYTE * pucBuffer, - FLMUINT * puiBufLen - ) + FLMUINT * puiBufLen) { RCODE rc = FERR_OK; @@ -2614,7 +2607,8 @@ RCODE flmEncryptBuffer( FLMBYTE oid_aes[] = {IDV_AES128CBC}; FLMBYTE pucIV[ IV_SZ]; - /* Create NICI Context */ + // Create NICI Context + if (CCS_CreateContext(0, &context) != 0) { rc = RC_SET( FERR_NICI_CONTEXT); @@ -2657,12 +2651,13 @@ RCODE flmEncryptBuffer( algorithm.parameter = parm; algorithm.parameter->count = 1; algorithm.parameter->parms[0].parmType = NICI_P_IV; - algorithm.parameter->parms[0].u.b.len = IV_SZ; /* 16-byte IV */ + algorithm.parameter->parms[0].u.b.len = IV_SZ; algorithm.parameter->parms[0].u.b.ptr = pucIV; GetIV(pucIV, IV_SZ); - /* init encryption */ + // Init encryption + if (CCS_DataEncryptInit(context, &algorithm, serverKeyHdl) != 0) { rc = RC_SET( FERR_NICI_ENC_INIT_FAILED); @@ -2721,16 +2716,13 @@ FSTATIC void GetIV( /***************************************************************************** Desc: *****************************************************************************/ -#ifdef FLM_USE_NICI -#ifndef FLM_UNIX -int CCSX_SetNewIV( - int ,//MODULEID, - FLMUINT32 ,//hContext, - pnuint8 ,//IV, - nuint32 //IVLen - ) +#if defined( FLM_USE_NICI) && !defined( FLM_UNIX) +int CCSX_SetNewIV( + int , // MODULEID, + FLMUINT32 , // hContext, + pnuint8 , // IV, + nuint32) // IVLen { - return(NICI_E_FUNCTION_NOT_SUPPORTED); + return( NICI_E_FUNCTION_NOT_SUPPORTED); } #endif -#endif diff --git a/flaim/src/f_tocoll.cpp b/flaim/src/f_tocoll.cpp deleted file mode 100644 index c2ab0c7..0000000 --- a/flaim/src/f_tocoll.cpp +++ /dev/null @@ -1,772 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Collation routines for indexing. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: f_tocoll.cpp 12245 2006-01-19 14:29:51 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -// Returns TRUE if upper case, FALSE if lower case. - -FINLINE FLMBOOL charIsUpper( - FLMUINT16 ui16Char) -{ - return( (FLMBOOL)((ui16Char < 0x7F) - ? (FLMBOOL)((ui16Char >= ASCII_LOWER_A && - ui16Char <= ASCII_LOWER_Z) - ? (FLMBOOL)FALSE - : (FLMBOOL)TRUE) - : fwpIsUpper( ui16Char))); -} - -extern FLMBYTE fwp_dia60Tbl[]; // Diacritic conversions -extern FLMBYTE fwp_alefSubColTbl[]; // Arabic sub collation table. -extern FLMBYTE fwp_ar2BitTbl[]; // Arabic 2 bit table. - -/**************************************************************************** -Desc: Convert a text string to a collated string. - If FERR_CONV_DEST_OVERFLOW is returned the string is truncated as - best as it can be. The caller must decide to return the error up - or deal with the truncation. -Return: RCODE = SUCCESS or FERR_CONV_DEST_OVERFLOW -VISIT: If the string is EXACTLY the length of the truncation - length then it should, but doesn't, set the truncation flag. - The code didn't match the design intent. Fix next major - version. -****************************************************************************/ -RCODE FTextToColStr( - const FLMBYTE * pucStr, // Points to the internal TEXT string - FLMUINT uiStrLen, // Length of the internal TEXT string - FLMBYTE * pucCollatedStr, // Returns collated string - FLMUINT * puiCollatedStrLen, // Returns total collated string length - // Input is maximum bytes in buffer - FLMUINT uiUppercaseFlag, // Set if to convert to uppercase - FLMUINT * puiCollationLen, // Returns the collation bytes length - FLMUINT * puiCaseLen, // Returns length of case bytes - FLMUINT uiLanguage, // Language - FLMUINT uiCharLimit, // Max number of characters in this key piece - FLMBOOL bFirstSubstring, // TRUE is this is the first substring key - FLMBOOL * pbOriginalCharsLost, - FLMBOOL * pbDataTruncated) -{ - RCODE rc = FERR_OK; - const FLMBYTE * pucStrEnd; // Points to the end of the string - FLMUINT16 ui16Base; // Value of the base character - FLMUINT16 ui16SubColVal; // Sub-collated value (diacritic) - FLMUINT uiObjLength = 0; - FLMUINT uiLength; // Temporary variable for length - FLMUINT uiTargetColLen = *puiCollatedStrLen - 8; // 4=ovhd,4=worse char - FLMUINT uiObjType; - FLMBOOL bDataTruncated = FALSE; - - // Need to increase the buffer sizes to not overflow. - // Characaters without COLL values will take up 3 bytes in - // the ucSubColBuf[] and easily overflow the buffer. - // Hard coded the values so as to minimize changes. - - FLMBYTE ucSubColBuf[ MAX_SUBCOL_BUF + 301]; // Holds sub-collated values(diac) - FLMBYTE ucCaseBits[ MAX_LOWUP_BUF + 81]; // Holds case bits - FLMUINT16 ui16WpChr; // Current WP character - FLMUNICODE unichr = 0; // Current unconverted Unicode character - FLMUINT16 ui16WpChr2; // 2nd character if any; default 0 for US lang - FLMUINT uiColLen; // Return value of collated length - FLMUINT uiSubColBitPos; // Sub-collation bit position - FLMUINT uiCaseBitPos; // Case bit position - FLMUINT uiFlags; // Clear all bit flags - FLMBOOL bHebrewArabic = FALSE; // Set if language is hebrew, arabic, farsi - FLMBOOL bTwoIntoOne; - - uiColLen = 0; - uiSubColBitPos = 0; - uiCaseBitPos = 0; - uiFlags = 0; - ui16WpChr2 = 0; - - // Don't allow any key component to exceed 256 bytes regardless of the - // user-specified character or byte limit. The goal is to prevent - // any single key piece from consuming too much of the key (which is - // limited to 640 bytes) and thus "starving" other pieces, resulting - // in a key overflow error. - - if( uiTargetColLen > 256) - { - uiTargetColLen = 256; - } - - // Code below sets ucSubColBuf[] and ucCaseBits[] values to zero. - - if (uiLanguage != US_LANG) - { - if (uiLanguage == AR_LANG || // Arabic - uiLanguage == FA_LANG || // Farsi - persian - uiLanguage == HE_LANG || // Hebrew - uiLanguage == UR_LANG) // Urdu - { - bHebrewArabic = TRUE; - } - } - pucStrEnd = &pucStr [uiStrLen]; - - while (pucStr < pucStrEnd) - { - - // Set the case bits and sub-collation bits to zero when - // on the first bit of the byte. - - if (!(uiCaseBitPos & 0x07)) - { - ucCaseBits [uiCaseBitPos >> 3] = 0; - } - if (!(uiSubColBitPos & 0x07)) - { - ucSubColBuf [uiSubColBitPos >> 3] = 0; - } - - // Get the next character from the TEXT string. - - for (ui16WpChr = ui16SubColVal = 0; // Default sub-collation value - !ui16WpChr && pucStr < pucStrEnd; - pucStr += uiObjLength) - { - FLMBYTE ucChar = *pucStr; - - uiObjType = GedTextObjType( ucChar); - switch (uiObjType) - { - case ASCII_CHAR_CODE: // 0nnnnnnn - uiObjLength = 1; - - // Character set zero is assumed. - - ui16WpChr = (FLMUINT16)ucChar; - continue; - case CHAR_SET_CODE: // 10nnnnnn - uiObjLength = 2; - - // Character set followed by character - - ui16WpChr = (((FLMUINT16)(ucChar & (~CHAR_SET_MASK)) << 8) - + (FLMUINT16)*(pucStr + 1)); - continue; - case WHITE_SPACE_CODE: // 110nnnnn - uiObjLength = 1; - ucChar &= (~WHITE_SPACE_MASK); - ui16WpChr = (ucChar == HARD_HYPHEN || - ucChar == HARD_HYPHEN_EOL || - ucChar == HARD_HYPHEN_EOP) - ? (FLMUINT16)0x2D // Minus sign -- character set 0 - : (FLMUINT16)0x20;// Space -- character set zero - continue; - - // Skip all of the unknown stuff - - case UNK_GT_255_CODE: - uiObjLength = 3 + FB2UW( pucStr + 1); - continue; - case UNK_LE_255_CODE: - uiObjLength = 2 + (FLMUINT16)*(pucStr + 1); - continue; - case UNK_EQ_1_CODE: - uiObjLength = 2; - continue; - case EXT_CHAR_CODE: - uiObjLength = 3; - - // Character set followed by character - - ui16WpChr = (((FLMUINT16)*(pucStr + 1) << 8) - + (FLMUINT16)*(pucStr + 2)); - continue; - case OEM_CODE: - - // OEM characters are always >= 128 - // Use character set zero to process them. - - uiObjLength = 2; - ui16WpChr = (FLMUINT16)*(pucStr + 1); - continue; - case UNICODE_CODE: // Unconvertable UNICODE code - uiObjLength = 3; - - // Unicode character followed by unicode character set - - unichr = (FLMUINT16)(((FLMUINT16)*(pucStr + 1) << 8) - + (FLMUINT16)*(pucStr + 2)); - ui16WpChr = UNK_UNICODE_CODE; - continue; - default: - - // Should not happen, but don't return an error - - flmAssert( 0); - continue; - } - } - - // If we didn't get a character, break out of while loop. - - if (!ui16WpChr) - { - break; - } - - // fwpCheckDoubleCollation modifies ui16WpChr if a digraph or a double - // character sequence is found. If a double character is found, pucStr - // is incremented and ui16WpChr2 is set to 1. If a digraph is found, - // pucStr is not changed, but ui16WpChr contains the first character and - // ui16WpChr2 contains the second character of the digraph. - - if (uiLanguage != US_LANG) - { - ui16WpChr2 = fwpCheckDoubleCollation( &ui16WpChr, &bTwoIntoOne, - &pucStr, uiLanguage); - } - - // Save the case bit - - if (!uiUppercaseFlag) - { - - // charIsUpper returns TRUE if upper case, 0 if lower case. - - if (!charIsUpper( ui16WpChr)) - { - uiFlags |= HAD_LOWER_CASE; - } - else - { - - // Set if upper case. - - SET_BIT( ucCaseBits, uiCaseBitPos); - } - uiCaseBitPos++; - } - - // Handle OEM characters, non-collating characters, - // characters with subcollating values, double collating - // values. - - // Get the collated value from the WP character-if not collating value - - if ((pucCollatedStr[ uiColLen++] = - (FLMBYTE)(fwpGetCollation( ui16WpChr, uiLanguage))) >= COLS11) - { - FLMUINT uiTemp; - - // Save OEM characters just like non-collating characters - - // If lower case, convert to upper case. - - if (!charIsUpper( ui16WpChr)) - { - ui16WpChr &= ~1; - } - - // No collating value given for this WP char. - // Save original WP char (2 bytes) in subcollating - // buffer. - - // 1110 is a new code that will store an insert over - // the character OR a non-convertable unicode character. - // Store with the same alignment as "store_extended_char" - // below. - - // 11110 is code for unmappable UNICODE value. - // A value 0xFE will be the collation value. The sub-collation - // value will be 0xFFFF followed by the UNICODE value. - // Be sure to eat an extra case bit. - - // See specific Hebrew and Arabic comments in the - // switch statement below. - - // Set the next byte that follows in the sub collation buffer. - - ucSubColBuf [(uiSubColBitPos + 8) >> 3] = 0; - - if (bHebrewArabic && (pucCollatedStr [uiColLen-1] == COLS0_ARABIC)) - { - - // Store first bit of 1110, fall through & store remaining 3 bits - - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos++; - - // Don't store collation value - - uiColLen--; - } - else if (unichr) - { - ui16WpChr = unichr; - unichr = 0; - - // Store 11 out of 11110 - - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos++; - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos++; - if (!uiUppercaseFlag) - { - ucCaseBits [(uiCaseBitPos + 7) >> 3] = 0; - - // Set upper case bit. - - SET_BIT( ucCaseBits, uiCaseBitPos); - uiCaseBitPos++; - } - } -store_extended_char: - - // Set the next byte that follows in the sub collation buffer. - - ucSubColBuf [(uiSubColBitPos + 8) >> 3] = 0; - ucSubColBuf [(uiSubColBitPos + 16) >> 3] = 0; - uiFlags |= HAD_SUB_COLLATION; - - // Set 110 bits in sub-collation - continued from above. - // No need to explicitly set the zero, but must increment - // for it. - - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos++; - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos += 2; - - // store_aligned_word: This label is not referenced. - // Go to the next byte boundary to write the character. - - uiSubColBitPos = (uiSubColBitPos + 7) & (~7); - uiTemp = BYTES_IN_BITS( uiSubColBitPos); - - // Need to big-endian - so it will sort correctly. - - ucSubColBuf [uiTemp] = (FLMBYTE)(ui16WpChr >> 8); - ucSubColBuf [uiTemp + 1] = (FLMBYTE)(ui16WpChr); - uiSubColBitPos += 16; - ucSubColBuf [uiSubColBitPos >> 3] = 0; - } - else - { - // Had a collation value - - // Add the lower/uppercase bit if a mixed case output. - - // If not lower ASCII set - check diacritic value for sub-collation - - if (!(ui16WpChr & 0xFF00)) - { - - // ASCII character set - set a single 0 bit - just need to - // increment to do this. - - uiSubColBitPos++; - } - else - { - FLMBYTE ucTmpChar = (FLMBYTE)ui16WpChr; - FLMBYTE ucCharSet = (FLMBYTE)(ui16WpChr >> 8); - - // Convert char to uppercase because case information - // is stored above. This will help - // ensure that the "ETA" doesn't sort before "eta" - - if (!charIsUpper(ui16WpChr)) - { - ui16WpChr &= ~1; - } - - switch (ucCharSet) - { - case CHSMUL1: // Multinational 1 - - // If we cannot break down a char into base and - // diacritic we cannot combine the charaacter - // later when converting back the key. In that case, - // write the entire WP char in the sub-collation area. - - if (fwpCh6Brkcar( ui16WpChr, &ui16Base, &ui16SubColVal)) - { - goto store_extended_char; - } - - // Write the FLAIM diacritic sub-collation value. - // Prefix is 2 bits "10". Remember to leave - // "111" alone for the future. - // NOTE: The "unlaut" character must sort after the "ring" - // character. - - ui16SubColVal = ((ui16SubColVal & 0xFF) == umlaut && - (uiLanguage == SU_LANG || - uiLanguage == SV_LANG || - uiLanguage == CZ_LANG || - uiLanguage == SL_LANG)) - ? (FLMUINT16)(fwp_dia60Tbl[ ring] + 1) - : (FLMUINT16)(fwp_dia60Tbl[ ui16SubColVal & 0xFF]); - -store_sub_col: - // Set the next byte that follows in the sub collation buffer. - - ucSubColBuf[ (uiSubColBitPos + 8) >> 3] = 0; - uiFlags |= HAD_SUB_COLLATION; - - // Set the 10 bits - no need to explicitly set the zero, but - // must increment for it. - - SET_BIT( ucSubColBuf, uiSubColBitPos); - uiSubColBitPos += 2; - - // Set sub-collation bits. - - SETnBITS( 5, ucSubColBuf, uiSubColBitPos, ui16SubColVal); - uiSubColBitPos += 5; - break; - - case CHSGREK: // Greek - - if (ucTmpChar >= 52 || // Keep case bit for 52-69 else ignore - ui16WpChr == 0x804 || // [ 8,4] BETA Medial | Terminal - ui16WpChr == 0x826) // [ 8,38] SIGMA terminal - { - goto store_extended_char; - } - - // No subcollation to worry about - set a zero bit by - // incrementing the bit position. - - uiSubColBitPos++; - break; - - case CHSCYR: - if (ucTmpChar >= 144) - { - goto store_extended_char; - } - - // No subcollation to worry about - set a zero bit by - // incrementing the bit position. - - uiSubColBitPos++; - - // VISIT: Georgian covers 208-249 - no collation defined yet - - break; - - case CHSHEB: // Hebrew - - // Three sections in Hebrew: - // 0..26 - main characters - // 27..83 - accents that apear over previous character - // 84..118- dagesh (ancient) hebrew with accents - - // Because the ancient is only used for sayings & scriptures - // we will support a collation value and in the sub-collation - // store the actual character because sub-collation is in - // character order. - - if (ucTmpChar >= 84) // Save ancient - value 84 and above - { - goto store_extended_char; - } - - // No subcollation to worry about - set a zero bit by - // incrementing the bit position. - - uiSubColBitPos++; - break; - - case CHSARB1: // Arabic 1 - - // Three sections in Arabic: - // 00..37 - accents that display OVER a previous character - // 38..46 - symbols - // 47..57 - numbers - // 58..163 - characters - // 164 - hamzah accent - // 165..180- common characters with accents - // 181..193- ligatures - common character combinations - // 194..195- extensions - throw away when sorting - - if (ucTmpChar <= 46) - { - goto store_extended_char; // save original character - } - - if (pucCollatedStr[ uiColLen-1] == COLS10a+1) // Alef? - { - ui16SubColVal = (ucTmpChar >= 165) - ? (FLMUINT16)(fwp_alefSubColTbl[ ucTmpChar - 165 ]) - : (FLMUINT16)7; // Alef subcol value - goto store_sub_col; - } - if (ucTmpChar >= 181) // Ligatures - char combination - { - goto store_extended_char; // save original character - } - - if (ucTmpChar == 64) // taa exception - { - ui16SubColVal = 8; - goto store_sub_col; - } - - // No subcollation to worry about - set a zero bit by - // incrementing the bit position. - - uiSubColBitPos++; - break; - - case CHSARB2: // Arabic 2 - - // There are some characters that share the same slot - // Check the bit table if above character 64 - - if (ucTmpChar >= 64 && - fwp_ar2BitTbl[(ucTmpChar - 64) >> 3] & - (0x80 >> (ucTmpChar & 0x07))) - { - goto store_extended_char; // Will save original - } - - // No subcollation to worry about - set a zero bit by - // incrementing the bit position. - - uiSubColBitPos++; - break; - - default: - - // Increment bit position to set a zero bit. - - uiSubColBitPos++; - break; - } - } - - - // Now let's worry about double character sorting - - if (ui16WpChr2) - { - if (pbOriginalCharsLost) - { - *pbOriginalCharsLost = TRUE; - } - - // Set the next byte that follows in the sub collation buffer. - - ucSubColBuf [(uiSubColBitPos + 7) >> 3] = 0; - - if (bTwoIntoOne) - { - - // Sorts after character in ui16WpChr after call to - // fwpCheckDoubleCollation - // Write the char 2 times so lower/upper bits are correct. - // Could write infinite times because of collation rules. - - pucCollatedStr[ uiColLen] = ++pucCollatedStr[ uiColLen-1]; - uiColLen++; - - // If original was upper case, set one more upper case bit - - if (!uiUppercaseFlag) - { - ucCaseBits[ (uiCaseBitPos + 7) >> 3] = 0; - if (!charIsUpper( (FLMUINT16) *(pucStr - 1))) - { - uiFlags |= HAD_LOWER_CASE; - } - else - { - SET_BIT( ucCaseBits, uiCaseBitPos); - } - uiCaseBitPos++; - } - - // Take into account the diacritical space - - uiSubColBitPos++; - } - else - { - - // We have a digraph, get second collation value - - pucCollatedStr[ uiColLen++] = - (FLMBYTE)(fwpGetCollation( ui16WpChr2, uiLanguage)); - - // Normal case, assume no diacritics set - - uiSubColBitPos++; - - // If first was upper, set one more upper bit. - - if (!uiUppercaseFlag) - { - ucCaseBits [(uiCaseBitPos + 7) >> 3] = 0; - if (charIsUpper( ui16WpChr)) - { - SET_BIT( ucCaseBits, uiCaseBitPos); - } - uiCaseBitPos++; - - // no need to reset the uiFlags - } - } - } - } - - // Check to see if uiColLen is at some overflow limit. - - if (uiColLen >= uiCharLimit || - uiColLen + BYTES_IN_BITS( uiSubColBitPos) + - BYTES_IN_BITS( uiCaseBitPos) >= uiTargetColLen) - { - - // We hit the maximum number of characters. - - if (pucStr < pucStrEnd) - { - bDataTruncated = TRUE; - } - break; - } - } - - // END OF WHILE LOOP - - if (puiCollationLen) - { - *puiCollationLen = uiColLen; - } - - // Add the first substring marker - also serves as making the string non-null. - - if (bFirstSubstring) - { - pucCollatedStr [uiColLen++] = COLL_FIRST_SUBSTRING; - } - - if (bDataTruncated) - { - pucCollatedStr[ uiColLen++ ] = COLL_TRUNCATED; - } - - // 10/20/98 - Add code to return NOTHING if no values found. - - if (!uiColLen && !uiSubColBitPos) - { - if (puiCaseLen) - { - *puiCaseLen = 0; - } - goto Exit; - } - - // Store extra zero bit in the sub-collation area for Hebrew/Arabic - - if (bHebrewArabic) - { - uiSubColBitPos++; - } - - // Done putting the string into 4 sections - build the COLLATED KEY - // Don't set uiUppercaseFlag earlier than here because SC_LOWER may be zero - - uiUppercaseFlag = (uiLanguage == GR_LANG) ? SC_LOWER : SC_UPPER; - - // The default terminating characters is (COLL_MARKER|SC_UPPER) - // Did we write anything to the subcollation area? - - if (uiFlags & HAD_SUB_COLLATION) - { - // Writes out a 0x7 - - pucCollatedStr [uiColLen++] = COLL_MARKER | SC_SUB_COL; - - // Move the sub-collation into the collating string - - uiLength = BYTES_IN_BITS( uiSubColBitPos); - f_memcpy( &pucCollatedStr[uiColLen], ucSubColBuf, uiLength); - uiColLen += uiLength; - } - - // Move the upper/lower case stuff - force bits for Greek ONLY - // This is such a small size that a memcpy is not worth it - - if (uiFlags & HAD_LOWER_CASE) - { - FLMUINT uiNumBytes = BYTES_IN_BITS( uiCaseBitPos); - FLMBYTE * pucCasePtr = ucCaseBits; - - // Output the 0x5 - - pucCollatedStr [uiColLen++] = (FLMBYTE)(COLL_MARKER | SC_MIXED); - if (puiCaseLen) - { - *puiCaseLen = uiNumBytes + 1; - } - - if (uiUppercaseFlag == SC_LOWER) - { - - // Negate case bits for languages (like GREEK) that sort - // upper case before lower case. - - while (uiNumBytes--) - { - pucCollatedStr [uiColLen++] = ~(*pucCasePtr++); - } - } - else - { - while (uiNumBytes--) - { - pucCollatedStr [uiColLen++] = *pucCasePtr++; - } - } - } - else - { - - // All characters are either upper or lower case, as determined - // by uiUppercaseFlag. - - pucCollatedStr [uiColLen++] = (FLMBYTE)(COLL_MARKER | uiUppercaseFlag); - if( puiCaseLen) - { - *puiCaseLen = 1; - } - } -Exit: - - // Set length return value. - - if( pbDataTruncated) - { - *pbDataTruncated = bDataTruncated; - } - - *puiCollatedStrLen = uiColLen; - return( rc); -} diff --git a/flaim/src/f_uncoll.cpp b/flaim/src/f_uncoll.cpp deleted file mode 100644 index 5805e4b..0000000 --- a/flaim/src/f_uncoll.cpp +++ /dev/null @@ -1,574 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Uncollation routines for converting from collated string to WP string. -// Tabs: 3 -// -// Copyright (c) 1992-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: f_uncoll.cpp 12245 2006-01-19 14:29:51 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**----------------------------------------- -*** External tables -*** Could be far in another data segment -***----------------------------------------*/ -/* From COLLATE1.C */ - -extern FLMUINT16 colToWPChr[]; /* Converts collated value to WP character */ -extern FLMBYTE ml1_COLtoD[]; /* Diacritic conversions */ - -extern FLMUINT16 HebArabColToWPChr[]; -extern FLMUINT16 ArabSubColToWPChr[]; - -/**----------------------------------------- -*** Local Static Routine Prototypes -***----------------------------------------*/ - -/**---------------------------------------------------------------- -*** The version using the table uses 34 ticks and 29 bytes ONLY -*** because the turbo optimizer uses register variables better. -*** The other version below uses 39 ticks and 33 bytes. -*** Macro not moved to other calls in f_tocoll or kycompnd because -*** these are rarely called areas right now. -***---------------------------------------------------------------*/ - - -FSTATIC FLMUINT FWWSGetColStr( /* Returns byte length of word string*/ - FLMBYTE * fColStr, - FLMUINT * fcStrLenRV, - FLMBYTE * wordStr, - FLMUINT fWPLang, - FLMBOOL * pbDataTruncated, - FLMBOOL * pbFirstSubstring); - -FSTATIC FLMUINT FWWSCmbSubColBuf( - FLMBYTE * wordStr, - FLMUINT * wdStrLenRV, - FLMBYTE * subColBuf, - FLMBOOL hebrewArabicFlag ); - -FSTATIC FLMUINT FWWSToMixed( - FLMBYTE * wordStr, - FLMUINT wdStrLen, - FLMBYTE * lowUpBitStr, - FLMUINT fWPLang ); - -/************************************************************************** -Desc: Get the Flaim collating string and convert back to a text string -Ret: Length of new wpStr -Notes: Allocates the area for the word string buffer if will be over 256. -***************************************************************************/ -FLMUINT FColStrToText( - FLMBYTE * fColStr, /* Points to the Flaim collated string */ - FLMUINT * fcStrLenRV, /* Length of the Flaim collated string */ - FLMBYTE * textStr, /* Output string to build - TEXT string */ - FLMUINT fWPLang, /* FLAIM WP language number */ - FLMBYTE * postBuf, /* Lower/upper POST buffer or NULL */ - FLMUINT * postBytesRV, /* Return next position to use in postBuf */ - FLMBOOL * pbDataTruncated, /* Sets to TRUE if data had been truncated */ - FLMBOOL * pbFirstSubstring) /* Sets to TRUE if first substring */ -{ -#define LOCAL_CHARS 150 - FLMBYTE wordStr[ LOCAL_CHARS * 2 + LOCAL_CHARS / 5 ]; // Sample + 20% - FLMBYTE * wsPtr = NULL; - FLMBYTE * wsAllocatedWsPtr = NULL; - FLMUINT wsLen; - FLMUINT textLen; - FLMBYTE * textPtr; - - if( *fcStrLenRV > LOCAL_CHARS ) /* If won't fit allocate 1280 */ - { - if( RC_BAD( f_alloc( MAX_KEY_SIZ * 2, &wsPtr))) - { - return( 0 ); - } - wsAllocatedWsPtr = wsPtr; - } - else - wsPtr = wordStr; - - if( (fWPLang >= FIRST_DBCS_LANG) && - (fWPLang <= LAST_DBCS_LANG)) - { - wsLen = AsiaConvertColStr( fColStr, fcStrLenRV, wsPtr, - pbDataTruncated, pbFirstSubstring ); - if( postBuf ) - { - FLMUINT postBytes = *postBytesRV + 2; /* Skip past marker */ - - /* may change wsLen */ - postBytes += AsiaParseCase( wsPtr, &wsLen, &postBuf[ postBytes]); - *postBytesRV = postBytes; - } - - } - else - { - wsLen = FWWSGetColStr( fColStr, fcStrLenRV, wsPtr, fWPLang, - pbDataTruncated, pbFirstSubstring ); - - /* If a post buffer is sent - turn unflagged chars to lower case */ - if( postBuf ) - { - FLMUINT postBytes = *postBytesRV; - /* Check if mixed case chars follow and always increment postBytes */ - if( postBuf[ postBytes++ ] == (COLL_MARKER | SC_MIXED)) - { - postBytes += FWWSToMixed( wsPtr, wsLen, - &postBuf[ postBytes ], fWPLang); - } - *postBytesRV = postBytes; - } - } - /**------------------------------------------- - *** Copy word string to TEXT string area - ***------------------------------------------*/ - - wsLen >>= 1; /* Convert # of bytes to # of words */ - textPtr = textStr; - - while( wsLen--) - { - register FLMBYTE ch, cSet; - - /* Put the character in a local variable for speed */ - ch = *wsPtr++; - cSet = *wsPtr++; - - if( (!cSet) && (ch <= 127)) - { - - /**----------------------------------------------------------- - *** Character set zero only needs one byte if the character - *** is <= 127. Otherwise, it is handled like all other - *** extended characters below. - ***----------------------------------------------------------*/ - - *textPtr++ = ch; - } - /**----------------------------------------------------- - *** If the character set is > 63 it takes three bytes - *** to store, otherwise only two bytes are needed. - ***----------------------------------------------------*/ - else if( cSet < 63) - { - *textPtr++ = (FLMBYTE)(CHAR_SET_CODE | cSet); - *textPtr++ = ch; - } - else if( cSet == 0xFF && ch == 0xFF) - { - *textPtr++ = UNICODE_CODE; - *textPtr++ = *(wsPtr+1); /* Character set */ - *textPtr++ = *wsPtr; /* Character */ - wsPtr += 2; - wsLen--; /* Skip past 4 bytes for UNICODE */ - } - else - { - *textPtr++ = EXT_CHAR_CODE; - *textPtr++ = cSet; - *textPtr++ = ch; - } - } - - textLen = (textPtr - textStr); /* Compute total length */ - - if( wsAllocatedWsPtr != NULL) - f_free( &wsAllocatedWsPtr); - - return( textLen); -} - -/***************************************************************************** -Desc: Get the Flaim collating string and convert back to a WP word string -Ret: Length of new WP word string -*****************************************************************************/ -FSTATIC FLMUINT FWWSGetColStr( - FLMBYTE * fColStr, /* Points to the Flaim collated string */ - FLMUINT * fcStrLenRV, /* Length of the Flaim collated string */ - FLMBYTE * wordStr, /* Output string to build - WP word string */ - FLMUINT fWPLang, /* FLAIM WP language number */ - FLMBOOL * pbDataTruncated, /* Set to TRUE if truncated */ - FLMBOOL * pbFirstSubstring) /* Sets to TRUE if first substring */ -{ - FLMBYTE * wsPtr = wordStr; /* Points to the word string data area */ - FLMUINT length = *fcStrLenRV;/* May optimize as a register */ - FLMUINT pos = 0; /* Position in fColStr[] */ - FLMUINT bitPos; /* Computed bit position */ - FLMUINT colChar; /* Not portable if a FLMBYTE value */ - FLMUINT wdStrLen; - FLMBOOL hebrewArabicFlag = 0;/* Set if hebrew/arabic language */ - - /** - *** WARNING: - *** The code is duplicated for performance reasons. - *** The US code below is much more optimized so - *** any changes must be done twice. - **/ - - - if( fWPLang != US_LANG) /* Code for NON-US languages */ - { - if( (fWPLang == AR_LANG ) || /* Arabic */ - (fWPLang == FA_LANG ) || /* Farsi - persian */ - (fWPLang == HE_LANG ) || /* Hebrew */ - (fWPLang == UR_LANG )) /* Urdu */ - hebrewArabicFlag++; /* Add sindhi, pashto, kurdish, malay*/ - - // MVSVISIT: will not work correctly on IBM390 - need to change toolkit tables. - while( length && (fColStr[pos] > MAX_COL_OPCODE)) - { - length--; - colChar = (FLMUINT) fColStr[ pos++ ]; - switch( colChar) - { - case COLS9+4: /* ch in spanish */ - case COLS9+11: /* ch in czech */ - /* Put the WP char in the word string */ - UW2FBA( (FLMUINT16) 'C', wsPtr ); - wsPtr += 2; - colChar = (FLMUINT) 'H'; - pos++; /* move past second duplicate char */ - break; - - case COLS9+17: /* ll in spanish */ - /* Put the WP char in the word string */ - UW2FBA( (FLMUINT16)'L', wsPtr ); - wsPtr += 2; - colChar = (FLMUINT)'L'; - pos++; /* move past duplicate character */ - break; - - case COLS0: /* Non collating character or OEM character */ - /* Actual character is in sub-collation area*/ - colChar = (FLMUINT) 0xFFFF; - break; - - default: - /* Watch out COLS10h has () around it for subtraction */ - if( hebrewArabicFlag && (colChar >= COLS10h)) - { - colChar = (colChar < COLS10a) /* Hebrew only? */ - ? (FLMUINT) (0x900 + (colChar - (COLS10h))) /* Hebrew */ - : (FLMUINT) (HebArabColToWPChr[ colChar - (COLS10a)]); /* Arabic */ - } - else - { - colChar = (FLMUINT) colToWPChr[ colChar - COLLS ]; - } - break; - } - UW2FBA( (FLMUINT16) colChar, wsPtr ); /* Put the WP char in the word string*/ - wsPtr += 2; - } /* end while */ - } /* end if */ - else /* US Sorting - optimized */ - { - while( length && (fColStr[pos] > MAX_COL_OPCODE)) - { - length--; - /* Move in the WP value given uppercase collated value */ - colChar = (FLMUINT) fColStr[ pos++ ]; - - if( colChar == COLS0) - { - colChar = (FLMUINT) 0xFFFF; - } - else - { - colChar = (FLMUINT) colToWPChr[ colChar - COLLS ]; - } - UW2FBA( (FLMUINT16) colChar, wsPtr ); /* Put the WP char in the word string */ - wsPtr += 2; - } - } - /* NULL Terminate the string */ - UW2FBA( (FLMUINT16)0, wsPtr); - wdStrLen = pos + pos; /* Multiply fcStrLen by 2 */ - - /**-------------------------------------------------------------------- - *** Parse through the sub-collation and case information. - *** Watch out for COMP POST indexes - don't have case info following. - *** Here are values for some of the codes: - *** [ 0x01] - end for fields - case info follows - for COMP POST ixs - *** [ 0x02] - compound marker - *** [ 0x03] - not really used at this time - *** [ 0x04] - case information is all uppercase (IS,DK,GR) - *** [ 0x05] - case bits follow - *** [ 0x06] - case information is all uppercase - *** [ 0x07] - beginning of sub-collation information - *** [ 0x08] - first substring field that is made - *** [ 0x09] - truncation marker for text and binary - *** - *** Below are some cases to consider... - *** - *** [ COLLATION][ 0x07 sub-collation][ 0x05 case info][ 0x02] - *** [ COLLATION][ 0x07 sub-collation][ 0x05 case info] - *** [ COLLATION][ 0x07 sub-collation][ 0x02] - *** [ COLLATION][ 0x07 sub-collation][ 0x01] - *** [ COLLATION][ 0x05 case info][ 0x02] - *** [ COLLATION][ 0x05 case info] - *** [ COLLATION][ 0x02] - *** [ COLLATION][ 0x01] - *** - *** In the future still want[ 0x06] to be compressed out for uppercase - *** only indexes. - ***-------------------------------------------------------------------*/ - - // Check first substring before truncated - if( length && fColStr[pos] == COLL_FIRST_SUBSTRING) - { - if( pbFirstSubstring) - *pbFirstSubstring = TRUE; // Don't need to initialize to FALSE. - length--; - pos++; - } - if( length && fColStr[pos] == COLL_TRUNCATED) - { - if( pbDataTruncated) - *pbDataTruncated = TRUE; // Don't need to initialize to FALSE. - length--; - pos++; - } - /**------------------------------ - *** Does sub-collation follow? - ***-----------------------------*/ - - /* Still more to process - first work on the sub-collation (diacritics) */ - /* Hebrew/Arabic may have empty collation area */ - if( length && (fColStr[pos] == (COLL_MARKER | SC_SUB_COL))) - { - FLMUINT tempLen; - /* Do another pass on the word string adding the diacritics */ - bitPos = FWWSCmbSubColBuf( wordStr, &wdStrLen, - &fColStr[++pos], - hebrewArabicFlag ); - - /* Move pos to next byte value */ - tempLen = BYTES_IN_BITS( bitPos ); - pos += tempLen; - length -= tempLen + 1; /* The 1 includes the 0x07 byte */ - } - - /**------------------------------- - *** Does the case info follow? - ***------------------------------*/ - - if( length && (fColStr[pos] > COMPOUND_MARKER)) - { - /**---------------------------------------------------- - *** Take care of the lower and upper case conversion - *** If mixed case then convert using case bits - ***---------------------------------------------------*/ - - if( fColStr[pos++] & SC_MIXED) /* Increment pos here! */ - { - /* Don't pre-increment pos on line below! */ - pos += FWWSToMixed( wordStr, wdStrLen, &fColStr[pos], fWPLang ); - } - /* else 0x04 or 0x06 - all characters already in uppercase */ - - } - *fcStrLenRV = pos; /* pos should be on the 0x01 or 0x02 flag */ - return( wdStrLen); /* Return the length of the word string */ -} - -/************************************************************************** -Desc: Combine the diacritic 5 bit values to an existing word string -Todo: May want to check fwpCh6Cmbcar() for CY return value -***************************************************************************/ -FSTATIC FLMUINT FWWSCmbSubColBuf( - FLMBYTE * wordStr, /* Existing word string to modify */ - FLMUINT * wdStrLenRV, /* Wordstring length in bytes */ - FLMBYTE * subColBuf, /* Diacritic values in 5 bit sets */ - FLMBOOL hebrewArabicFlag) /* Set if language is Hebrew or Arabic */ -{ - FLMUINT subColBitPos = 0; - FLMUINT numWords = *wdStrLenRV >> 1; - FLMUINT16 diac; - FLMUINT16 wpchar; - FLMUINT temp; - - /* For each word in the word string ... */ - while( numWords--) - { - /* label used for hebrew/arabic - additional subcollation can follow */ - /* This macro DOESN'T increment bitPos */ - if( TEST1BIT( subColBuf, subColBitPos)) - { - /**-------------------------------------------- - *** If "11110" - unmappable unicode char - 0xFFFF is before it - *** If "1110" then INDEX extended char is inserted - *** If "110" then extended char follows that replaces collation - *** If "10" then take next 5 bits which - *** contain the diacritic subcollation value. - ***-------------------------------------------*/ -after_last_character: - subColBitPos++; /* Eat the first 1 bit */ - if( ! TEST1BIT( subColBuf, subColBitPos)) - { - subColBitPos++; /* Eat the 0 bit */ - diac = (FLMUINT16)(GETnBITS( 5, subColBuf, subColBitPos)); - subColBitPos += 5; - - if( (wpchar = FB2UW( wordStr )) < 0x100) /* If not extended base..*/ - { - - /* Convert to WP diacritic and combine characters */ - fwpCh6Cmbcar( &wpchar, wpchar, (FLMUINT16) ml1_COLtoD[diac] ); - /* Even if cmbcar fails, wpchar is still set to a valid value */ - UW2FBA( wpchar, wordStr); - } - else if( (wpchar & 0xFF00) == 0x0D00) /* arabic? */ - { - wpchar = ArabSubColToWPChr[ diac ]; - UW2FBA( wpchar, wordStr); - } - /* else diacritic is extra info */ - /* cmbcar should not handle extended chars for this design */ - } - else /* "110" or "1110" or "11110" */ - { - subColBitPos++; /* Eat the 2nd '1' bit */ - if( TEST1BIT( subColBuf, subColBitPos)) /* Test the 3rd bit */ - { - /* 1110 - shift wpchars down 1 word and insert value below */ - subColBitPos++; /* Eat the 3rd '1' bit */ - *wdStrLenRV += 2; /* Return 2 more bytes */ - - if( TEST1BIT( subColBuf, subColBitPos )) /* Test 4th bit */ - { - /* Unconvertable UNICODE character */ - /* The format will be 4 bytes, 0xFF, 0xFF, 2 byte Unicode */ - - shiftN( wordStr, numWords + numWords + 4, 2 ); - subColBitPos++; /* Eat the 4th '1' bit */ - wordStr += 2; /* Skip the 0xFFFF for now */ - } - else - { - /* Move down 2 byte NULL and rest of the 2 byte characters */ - /* The extended character does not have a 0xFF col value */ - - shiftN( wordStr, numWords + numWords + 2, 2 ); - numWords++; /* Increment because inserted */ - /* fall through reading the actual charater value */ - } - } - subColBitPos++; /* Skip past the zero bit */ - subColBitPos = (subColBitPos + 7) & (~7); /*roundup to next byte*/ - temp = BYTES_IN_BITS( subColBitPos ); /* compute position */ - wordStr[1] = subColBuf[ temp ]; /* Character set */ - wordStr[0] = subColBuf[ temp + 1 ]; /* Character */ - - subColBitPos += 16; - } - } - else - subColBitPos++; - - wordStr += 2; /* Next WP character */ - } - if( hebrewArabicFlag ) - { - if( TEST1BIT( subColBuf, subColBitPos)) - { - /**-------------------------------------------------- - *** Hebrew/Arabic can have trailing accents that - *** don't have a matching collation value. - *** Keep looping in this case. - *** Note that subColBitPos isn't incremented above. - ***-------------------------------------------------*/ - numWords = 0; /* set so won't loop forever! */ - goto after_last_character; /* process trailing bit */ - } - subColBitPos++; /* Eat the last '0' bit */ - } - return( subColBitPos); -} - -/************************************************************************** -Desc: Convert the word string to lower case chars given low/upp bit string -Out: WP characters have modified to their original case -Ret: Number of bytes used in the lower/upper buffer -Notes: Only WP to lower case conversion is done here for each bit NOT set. -***************************************************************************/ -FSTATIC FLMUINT FWWSToMixed( - FLMBYTE * wordStr, /* Existing word string to modify */ - FLMUINT wdStrLen, /* Length of the wordstring in bytes */ - FLMBYTE * lowUpBitStr, /* Lower/upper case bit string */ - FLMUINT fWPLang) /*Visit: Scott */ -{ - FLMUINT numWords; - FLMUINT tempWord; - FLMBYTE tempByte = 0; - FLMBYTE maskByte; - FLMBYTE xorByte; /* Used to reverse GR, bits */ - - xorByte = (fWPLang == US_LANG ) /* Do most common compare first */ - ? (FLMBYTE)0 - : (fWPLang == GR_LANG) /* Greek has uppercase first */ - ? (FLMBYTE)0xFF - : (FLMBYTE)0 ; - - /* For each word in the word string ... */ - for( numWords = wdStrLen >> 1, /* Total number of words in word string */ - maskByte = 0; /* Force first time to get a byte */ - - numWords--; /* Test */ - - wordStr += 2, /* Next WP character - word */ - maskByte >>= 1 ) /* Next bit to mask and check */ - { - if( maskByte == 0) /* Time to get another byte */ - { - tempByte = xorByte ^ *lowUpBitStr++; - maskByte = 0x80; - } - - if( ( tempByte & maskByte) == 0) /* If lowercase conver - else is upper*/ - { - /* Convert to lower case - COLL -> WP is already in upper case */ - tempWord = (FLMUINT) FB2UW( wordStr ); - if( (tempWord >= ASCII_UPPER_A) && (tempWord <= ASCII_UPPER_Z)) /* yes */ - tempWord |= 0x20; - else - { - FLMBYTE charVal = (FLMBYTE)(tempWord & 0xFF); - FLMBYTE charSet = (FLMBYTE) (tempWord >> 8); - - /* check if charact within region of character set */ - if ( (( charSet == CHSMUL1) && /* Multinational 1 */ - ((charVal >= 26) && (charVal <= 241))) - ||(( charSet == CHSGREK) && /* Greek */ - ( charVal <= 69)) - ||(( charSet == CHSCYR) && /* Cyrillic */ - ( charVal <= 199)) - ) - { - tempWord |= 0x01; /* Set - don't increment */ - } - } - UW2FBA( (FLMUINT16) tempWord, wordStr ); - } - } - - numWords = wdStrLen >> 1; - return( BYTES_IN_BITS( numWords )); -} diff --git a/flaim/src/fbcd.cpp b/flaim/src/fbcd.cpp deleted file mode 100644 index 8dbdaa0..0000000 --- a/flaim/src/fbcd.cpp +++ /dev/null @@ -1,372 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Routines to handle BCD numbers. -// Tabs: 3 -// -// Copyright (c) 1999-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fbcd.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -// Static Data - -FLMBYTE ucMaxBcdINT32[ ] - = {0x21, 0x47, 0x48, 0x36, 0x47}; - -FLMBYTE ucMinBcdINT32[ ] - = {0xB2, 0x14, 0x74, 0x83, 0x64, 0x8F}; - -FLMBYTE ucMaxBcdUINT32[ ] - = {0x42, 0x94, 0x96, 0x72, 0x95}; - - -/**************************************************************************** -Desc: Given an unsigned number create the matching FLAIM-specific BCD - number. -Note: If terminating byte is half-full, low-nibble value is - undefined. Example: -125 creates B1-25-FX -Method: Using a MOD algorithm, stack BCD values -- popping to - destination reverses the order for correct final sequence -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmUINT2Storage( - FLMUINT uiNum, - FLMUINT * puiBufLength, // [IN] size of pBuf, must be atleast F_MAX_NUM_BUF - // [OUT] actual amount of pBuf used. - FLMBYTE * pBuf) -{ - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - - flmAssert( *puiBufLength >= F_MAX_NUM_BUF); - - /* push spare (undefined) nibble for possible half-used terminating byte */ - - pucNibStk = &ucNibStk[ 1]; - - /* push terminator nibble -- popped last */ - - *pucNibStk++ = 0x0F; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10); /* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - /* count: nibbleCount/2 & truncate */ - - *puiBufLength = ((pucNibStk - ucNibStk) >> 1); - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pBuf++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - return( FERR_OK); -} - -/**************************************************************************** -Desc: Given an signed number create the matching FLAIM-specific BCD - number. -Note: If terminating byte is half-full, low-nibble value is - undefined. Example: -125 creates B1-25-FX -Method: Using a MOD algorithm, stack BCD values -- popping to - destination reverses the order for correct final sequence -WARNING: -2,147,483,648 may yield different results on different platforms -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmINT2Storage( - FLMINT iNum, - FLMUINT * puiBufLength, // [IN] size of pBuf, must be atleast F_MAX_NUM_BUF - // [OUT] actual amount of pBuf used. - FLMBYTE * pBuf) -{ - FLMUINT uiNum; - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - FLMINT iNegFlag; - - flmAssert( *puiBufLength >= F_MAX_NUM_BUF); - - /* push spare (undefined) nibble for possible half-used terminating byte */ - - pucNibStk = &ucNibStk[ 1]; - - /* push terminator nibble -- popped last */ - - *pucNibStk++ = 0x0F; - - /* separate sign from magnituted; (FLMUINT)un = +/- n & flag */ - - uiNum = ((iNegFlag = iNum < 0) != 0) - ? -iNum - : iNum; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10); /* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - if( iNegFlag) - *pucNibStk++ = 0x0B; /* push sign nibble last */ - - /* Determine number of bytes required for BCD number */ - /* count: nibbleCount/2 & truncate */ - - *puiBufLength = ((pucNibStk - ucNibStk) >> 1); - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pBuf++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - return( FERR_OK); -} - -/**************************************************************************** -Desc: Returns a signed value from a BCD value. - The data may be a number type, or context type. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmStorage2INT( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, // Internal Storage Format - FLMINT * piNum) // [OUT] return value. -{ - RCODE rc = FERR_OK; - BCD_TYPE bcd; - - if( RC_OK(rc = flmBcd2Num( uiValueType, uiValueLength, pucValue, &bcd))) - { - if( bcd.bNegFlag) - { - *piNum = -((FLMINT)bcd.uiNum); - return( - (bcd.uiNibCnt < 11) || - (bcd.uiNibCnt == 11 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMinBcdINT32, 6) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_UNDERFLOW) - ); - } - else - { - *piNum = (FLMINT)bcd.uiNum; - return( - (bcd.uiNibCnt < 10) || - (bcd.uiNibCnt == 10 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdINT32, 5) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW) - ); - } - } - return( rc); -} - -/**************************************************************************** -Desc: Returns a unsigned value from a BCD value. - The data may be a number type, or context type. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmStorage2UINT( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, // Internal Storage Format - FLMUINT * puiNum) // [OUT] return value. -{ - RCODE rc = FERR_OK; - BCD_TYPE bcd; - - if( RC_OK(rc = flmBcd2Num( uiValueType, uiValueLength, pucValue, &bcd))) - { - *puiNum = bcd.uiNum; - - if( bcd.bNegFlag) - { - rc = RC_SET( FERR_CONV_NUM_UNDERFLOW); - } - else if( bcd.uiNibCnt < 10) - { - rc = FERR_OK; - } - else if( bcd.uiNibCnt == 10) - { - rc = (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdUINT32, 5) <= 0)) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - else - { - rc = RC_SET( FERR_CONV_NUM_OVERFLOW); - } - } - return( rc); -} - - -/**************************************************************************** -Desc: Returns a unsigned value from a BCD value. - The data may be a number type, or context type. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmStorage2UINT32( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, // Internal Storage Format - FLMUINT32 * pui32Num) // [OUT] return value. -{ - RCODE rc = FERR_OK; - BCD_TYPE bcd; - - if( RC_OK(rc = flmBcd2Num( uiValueType, uiValueLength, pucValue, &bcd))) - { - *pui32Num = (FLMUINT32)bcd.uiNum; - - if( bcd.bNegFlag) - { - rc = RC_SET( FERR_CONV_NUM_UNDERFLOW); - } - else if( bcd.uiNibCnt < 10) - { - rc = FERR_OK; - } - else if( bcd.uiNibCnt == 10) - { - rc = (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdUINT32, 5) <= 0)) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - else - { - rc = RC_SET( FERR_CONV_NUM_OVERFLOW); - } - } - return( rc); -} - - -/**************************************************************************** -Desc: Converts FT_NUMBER and FT_CONTEXT storage buffers to a number -****************************************************************************/ -RCODE flmBcd2Num( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, // Internal Storage Format - BCD_TYPE * bcd) -{ - if( pucValue == NULL) - return( RC_SET( FERR_CONV_NULL_SRC)); - - switch( uiValueType) - { - case FLM_NUMBER_TYPE : - { - FLMUINT uiTotalNum = 0; - FLMUINT uiByte; - FLMUINT uiNibCnt; - - bcd->pucPtr = pucValue; - - /* Get each nibble and use to create the number */ - - for( bcd->bNegFlag = (FLMBOOL)(uiNibCnt = ((*pucValue & 0xF0) == 0xB0) ? 1 : 0); - uiNibCnt <= FLM_MAX_NIB_CNT; - uiNibCnt++ ) - { - - uiByte = (uiNibCnt & 0x01) /* See if on ODD/low nibble */ - ? (FLMUINT)(0x0F & *pucValue++) /* Get low nibble, increment pucPtr */ - : (FLMUINT)(*pucValue >> 4); /* Get high nibble */ - - if( uiByte == 0x0F) /* See if at end of BCD number */ - break; /* break if nibble == 0x0F */ - /* don't count in uiNibCnt */ - - /* multiply by 10 and add n */ - /* NOTE: 10y = 8y + 2y = (y << 3) + (y << 1) */ - /* faster than using the long multiply (10 * y) */ - - uiTotalNum = (uiTotalNum << 3) + (uiTotalNum << 1) + uiByte; - } - - bcd->uiNibCnt = uiNibCnt; - bcd->uiNum = uiTotalNum; - break; - } - - case FLM_TEXT_TYPE : - { - FLMUINT uiNumber = 0; - - /* If it is a TEXT Value, convert to a numeric value */ - /* WARNING: The text is not null terminated. */ - while( uiValueLength--) - { - if( *pucValue < ASCII_ZERO || *pucValue > ASCII_NINE) - break; - uiNumber = (uiNumber * 10) + (*pucValue - ASCII_ZERO); - pucValue++; - } - bcd->uiNum = uiNumber; - bcd->uiNibCnt = 0; - bcd->bNegFlag = FALSE; - break; - } - - case FLM_CONTEXT_TYPE : - { - if( uiValueLength == sizeof( FLMUINT32)) - { - bcd->uiNum = (FLMUINT)( FB2UD( pucValue)); - - bcd->bNegFlag = 0; - /* Now set the uiNibCnt, the uiNibCnt will not be totally accurate, - but it's close enough to get the value out... */ - if( bcd->uiNum < FLM_MAX_UINT8) - bcd->uiNibCnt = 3; - else if( bcd->uiNum < FLM_MAX_UINT16) - bcd->uiNibCnt = 5; - else - bcd->uiNibCnt = 9; - } - break; - } - - default : - { - flmAssert( 0); - return( RC_SET( FERR_CONV_ILLEGAL)); - } - } - - return( FERR_OK); -} diff --git a/flaim/src/fbuff.h b/flaim/src/fbuff.h index 9e10d96..90b7fe8 100644 --- a/flaim/src/fbuff.h +++ b/flaim/src/fbuff.h @@ -220,6 +220,13 @@ public: } #endif +#ifdef FLM_LINUX + FINLINE struct aiocb * getAIOStruct( void) + { + return( &m_aio); + } +#endif + #ifdef FLM_NLM void signalComplete( RCODE rc); @@ -253,6 +260,9 @@ private: HANDLE m_FileHandle; OVERLAPPED m_Overlapped; #endif +#ifdef FLM_LINUX + struct aiocb m_aio; +#endif #ifdef FLM_NLM F_SEM m_hSem; #endif diff --git a/flaim/src/fcs.h b/flaim/src/fcs.h index dab18c2..ee973f0 100644 --- a/flaim/src/fcs.h +++ b/flaim/src/fcs.h @@ -768,8 +768,8 @@ protected: FLMBOOL m_bSendGedcom; FCS_DIS * m_pDIStream; FCS_DOS * m_pDOStream; - CS_CONTEXT_p m_pCSContext; // Used by FCL_WIRE - FDB_p m_pDb; // Used by FCL_WIRE + CS_CONTEXT * m_pCSContext; // Used by FCL_WIRE + FDB * m_pDb; // Used by FCL_WIRE void resetCommon( void); @@ -1130,12 +1130,12 @@ public: } FINLINE void setFDB( - FDB_p pDb) + FDB * pDb) { m_pDb = pDb; } - FINLINE FDB_p getFDB( void) + FINLINE FDB * getFDB( void) { return( m_pDb); } @@ -1164,7 +1164,9 @@ private: public: - FCL_WIRE( CS_CONTEXT_p pCSContext = NULL, FDB_p pDb = NULL); + FCL_WIRE( + CS_CONTEXT * pCSContext = NULL, + FDB * pDb = NULL); FINLINE virtual ~FCL_WIRE( void) { @@ -1200,9 +1202,9 @@ public: return( m_pNameTable); } - void setContext( CS_CONTEXT_p); + void setContext( CS_CONTEXT *); - FINLINE CS_CONTEXT_p getContext( void) + FINLINE CS_CONTEXT * getContext( void) { return( m_pCSContext); } @@ -1212,19 +1214,17 @@ public: #define FCS_BIOS_EOM_EVENT 0x0001 // End-Of-Message event class FCS_BIOS; -typedef FCS_BIOS * FCS_BIOS_p; -typedef struct FCSBIOSBlock * FCSBIOSBLOCK_p; -typedef struct FCSBIOSBlock +typedef struct FCSBIOSBLOCK { - FCSBIOSBLOCK_p pNextBlock; + FCSBIOSBLOCK * pNextBlock; FLMUINT uiCurrWriteOffset; FLMUINT uiCurrReadOffset; FLMBYTE * pucBlock; } FCSBIOSBLOCK; typedef RCODE (* FCS_BIOS_EVENT_HOOK)( - FCS_BIOS_p pStream, + FCS_BIOS * pStream, FLMUINT uiEvent, void * pvUserData); @@ -1791,7 +1791,7 @@ void fcsDecodeHttpString( char * pszSrc); RCODE flmStreamEventDispatcher( - FCS_BIOS_p pStream, + FCS_BIOS * pStream, FLMUINT uiEvent, void * pvUserData); diff --git a/flaim/src/fcs_bios.cpp b/flaim/src/fcs_bios.cpp deleted file mode 100644 index 863c892..0000000 --- a/flaim/src/fcs_bios.cpp +++ /dev/null @@ -1,297 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Class for a buffer stream for I/O operations. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_bios.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_BIOS::FCS_BIOS( void) -{ - GedPoolInit( &m_pool, (FCS_BIOS_BLOCK_SIZE + sizeof( FCSBIOSBLOCK)) * 2); - m_bMessageActive = FALSE; - m_pRootBlock = NULL; - m_pCurrWriteBlock = NULL; - m_pCurrReadBlock = NULL; - m_bAcceptingData = FALSE; - m_pEventHook = NULL; - m_pvUserData = 0; -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_BIOS::~FCS_BIOS() -{ - GedPoolFree( &m_pool); -} - -/**************************************************************************** -Desc: Clears all pending data -*****************************************************************************/ -RCODE FCS_BIOS::reset( void) -{ - return( close()); -} - -/**************************************************************************** -Desc: Flushes any pending data and closes the stream. -*****************************************************************************/ -RCODE FCS_BIOS::close( void) -{ - RCODE rc = FERR_OK; - - GedPoolReset( &m_pool, NULL); - m_bMessageActive = FALSE; - m_pRootBlock = NULL; - m_pCurrWriteBlock = NULL; - m_pCurrReadBlock = NULL; - m_bAcceptingData = FALSE; - - return( rc); -} - - -/**************************************************************************** -Desc: Writes the requested amount of data to the stream. -*****************************************************************************/ -RCODE FCS_BIOS::write( - FLMBYTE * pucData, - FLMUINT uiLength) -{ - FLMUINT uiCopySize; - FLMUINT uiDataPos = 0; - FCSBIOSBLOCK * pPrevBlock = NULL; - RCODE rc = FERR_OK; - - if( !m_bAcceptingData) - { - GedPoolReset( &m_pool, NULL); - m_pCurrWriteBlock = NULL; - m_pCurrReadBlock = NULL; - m_pRootBlock = NULL; - m_bAcceptingData = TRUE; - } - - while( uiLength) - { - if( !m_pCurrWriteBlock || - m_pCurrWriteBlock->uiCurrWriteOffset == FCS_BIOS_BLOCK_SIZE) - { - pPrevBlock = m_pCurrWriteBlock; - m_pCurrWriteBlock = - (FCSBIOSBLOCK *)GedPoolCalloc( &m_pool, sizeof( FCSBIOSBLOCK)); - if( !m_pCurrWriteBlock) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - m_pCurrWriteBlock->pucBlock = - (FLMBYTE *)GedPoolAlloc( &m_pool, FCS_BIOS_BLOCK_SIZE); - - if( !m_pCurrWriteBlock->pucBlock) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( pPrevBlock) - { - pPrevBlock->pNextBlock = m_pCurrWriteBlock; - } - else - { - m_pRootBlock = m_pCurrWriteBlock; - m_pCurrReadBlock = m_pCurrWriteBlock; - } - } - - uiCopySize = f_min( uiLength, - (FLMUINT)(FCS_BIOS_BLOCK_SIZE - - m_pCurrWriteBlock->uiCurrWriteOffset)); - - flmAssert( uiCopySize != 0); - - f_memcpy( &(m_pCurrWriteBlock->pucBlock[ - m_pCurrWriteBlock->uiCurrWriteOffset]), - &(pucData[ uiDataPos]), uiCopySize); - - m_pCurrWriteBlock->uiCurrWriteOffset += uiCopySize; - uiDataPos += uiCopySize; - uiLength -= uiCopySize; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Terminates the current message -*****************************************************************************/ -RCODE FCS_BIOS::endMessage( void) -{ - RCODE rc = FERR_OK; - - if( !m_bAcceptingData) - { - goto Exit; - } - - if( m_pEventHook) - { - if( RC_BAD( rc = m_pEventHook( this, - FCS_BIOS_EOM_EVENT, m_pvUserData))) - { - goto Exit; - } - } - -Exit: - - m_bAcceptingData = FALSE; - return( rc); -} - - -/**************************************************************************** -Desc: Reads the requested amount of data from the stream. -*****************************************************************************/ -RCODE FCS_BIOS::read( - FLMBYTE * pucData, - FLMUINT uiLength, - FLMUINT * puiBytesRead) -{ - FLMUINT uiCopySize; - FLMUINT uiDataPos = 0; - RCODE rc = FERR_OK; - - if( puiBytesRead) - { - *puiBytesRead = 0; - } - - if( m_bAcceptingData) - { - m_bAcceptingData = FALSE; - } - - while( uiLength) - { - if( m_pCurrReadBlock && - m_pCurrReadBlock->uiCurrReadOffset == m_pCurrReadBlock->uiCurrWriteOffset) - { - m_pCurrReadBlock = m_pCurrReadBlock->pNextBlock; - } - - if( !m_pCurrReadBlock) - { - GedPoolReset( &m_pool, NULL); - rc = RC_SET( FERR_EOF_HIT); - goto Exit; - } - - uiCopySize = f_min( uiLength, - m_pCurrReadBlock->uiCurrWriteOffset - m_pCurrReadBlock->uiCurrReadOffset); - - f_memcpy( &(pucData[ uiDataPos]), - &(m_pCurrReadBlock->pucBlock[ m_pCurrReadBlock->uiCurrReadOffset]), - uiCopySize); - - m_pCurrReadBlock->uiCurrReadOffset += uiCopySize; - uiDataPos += uiCopySize; - - if( puiBytesRead) - { - (*puiBytesRead) += uiCopySize; - } - uiLength -= uiCopySize; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FLMBOOL FCS_BIOS::isDataAvailable( void) -{ - if( m_bAcceptingData) - { - if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset) - { - return( TRUE); - } - } - else if( m_pCurrReadBlock && - ((m_pCurrReadBlock->uiCurrReadOffset < - m_pCurrReadBlock->uiCurrWriteOffset) || - (m_pCurrReadBlock->pNextBlock))) - { - return( TRUE); - } - - return( FALSE); -} - - -/**************************************************************************** -Desc: Returns the amount of data available for reading -*****************************************************************************/ -FLMUINT FCS_BIOS::getAvailable( void) -{ - FLMUINT uiAvail = 0; - FCSBIOSBlock * pBlk; - - if( m_bAcceptingData) - { - if( m_pRootBlock && m_pRootBlock->uiCurrWriteOffset) - { - pBlk = m_pRootBlock; - while( pBlk) - { - uiAvail += pBlk->uiCurrWriteOffset; - pBlk = pBlk->pNextBlock; - } - } - } - else if( m_pCurrReadBlock && - ((m_pCurrReadBlock->uiCurrReadOffset < - m_pCurrReadBlock->uiCurrWriteOffset) || - (m_pCurrReadBlock->pNextBlock))) - { - pBlk = m_pCurrReadBlock; - while( pBlk) - { - uiAvail += (pBlk->uiCurrWriteOffset - - pBlk->uiCurrReadOffset); - pBlk = pBlk->pNextBlock; - } - } - - return( uiAvail); -} diff --git a/flaim/src/fcs_dis.cpp b/flaim/src/fcs_dis.cpp deleted file mode 100644 index 9c87b34..0000000 --- a/flaim/src/fcs_dis.cpp +++ /dev/null @@ -1,1422 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Data input stream class. -// Tabs: 3 -// -// Copyright (c) 1998-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_dis.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -****************************************************************************/ -FCS_DIS::FCS_DIS( void) -{ - m_pIStream = NULL; - m_uiBOffset = m_uiBDataSize = 0; - m_bSetupCalled = FALSE; -} - -/**************************************************************************** -Desc: -****************************************************************************/ -FCS_DIS::~FCS_DIS( void) -{ - if( m_bSetupCalled) - { - (void)close(); - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::setup( - FCS_ISTM * pIStream) -{ - m_pIStream = pIStream; - m_bSetupCalled = TRUE; - - return( FERR_OK); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readByte( - FLMBYTE * pValue) -{ - return( read( pValue, 1, NULL)); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readShort( - FLMINT16 * pValue) -{ - FLMUINT16 ui16Value; - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL))) - { - ui16Value = flmBigEndianToUINT16( (FLMBYTE *)pValue); - *pValue = *((FLMINT16 *)&ui16Value); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readUShort( - FLMUINT16 * pValue) -{ - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 2, NULL))) - { - *pValue = flmBigEndianToUINT16( (FLMBYTE *)pValue); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readInt( - FLMINT32 * pValue) -{ - FLMUINT32 ui32Value; - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL))) - { - ui32Value = flmBigEndianToUINT32( (FLMBYTE *)pValue); - *pValue = *((FLMINT32 *)&ui32Value); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readUInt( - FLMUINT32 * pValue) -{ - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 4, NULL))) - { - *pValue = flmBigEndianToUINT32( (FLMBYTE *)pValue); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readInt64( - FLMINT64 * pValue) -{ - FLMUINT64 ui64Value; - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL))) - { - ui64Value = flmBigEndianToUINT64( (FLMBYTE *)pValue); - *pValue = *((FLMINT64 *)&ui64Value); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::readUInt64( - FLMUINT64 * pValue) -{ - RCODE rc; - - // Read the data. - - if( RC_OK( rc = read( (FLMBYTE *)pValue, 8, NULL))) - { - *pValue = flmBigEndianToUINT64( (FLMBYTE *)pValue); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE FCS_DIS::skip( - FLMUINT uiBytesToSkip) -{ - return( read( NULL, uiBytesToSkip, NULL)); -} - -/**************************************************************************** -Desc: Flushes any pending data and closes the DIS -****************************************************************************/ -RCODE FCS_DIS::close( void) -{ - RCODE rc = FERR_OK; - - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Terminate and flush. - */ - - if( RC_BAD( rc = endMessage())) - { - goto Exit; - } - - /* - Reset the member variables. - */ - - m_pIStream = NULL; - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Returns the state of the stream (open == TRUE, closed == FALSE) -****************************************************************************/ -FLMBOOL FCS_DIS::isOpen( void) -{ - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( m_pIStream && m_pIStream->isOpen()) - { - return( TRUE); - } - - return( FALSE); -} - -/**************************************************************************** -Desc: Flushes and terminates the current parent stream message -****************************************************************************/ -RCODE FCS_DIS::endMessage( void) -{ - RCODE rc = FERR_OK; - - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( !m_pIStream) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Flush any pending data. - */ - - if( RC_BAD( rc = flush())) - { - goto Exit; - } - - /* - Terminate the message. - */ - - if( RC_BAD( rc = m_pIStream->endMessage())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Flushes any pending data -****************************************************************************/ -RCODE FCS_DIS::flush( void) -{ - RCODE rc = FERR_OK; - - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( !m_pIStream) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Flush the passed-in input stream. - */ - - if( RC_BAD( rc = m_pIStream->flush())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Reads the specified number of bytes. -****************************************************************************/ -RCODE FCS_DIS::read( - FLMBYTE * pucData, - FLMUINT uiLength, - FLMUINT * puiBytesRead) -{ - FLMUINT uiCopySize; - FLMUINT uiReadLen; - FLMBYTE * pucPos = NULL; - RCODE rc = FERR_OK; - - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( !m_pIStream) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - if( puiBytesRead) - { - *puiBytesRead = uiLength; - } - - pucPos = pucData; - while( uiLength) - { - if( m_uiBOffset == m_uiBDataSize) - { - m_uiBOffset = m_uiBDataSize = 0; - - if( RC_BAD( rc = m_pIStream->read( m_pucBuffer, - FCS_DIS_BUFFER_SIZE, &uiReadLen))) - { - if( uiReadLen) - { - rc = FERR_OK; - } - else - { - goto Exit; - } - } - m_uiBDataSize = uiReadLen; - } - - uiCopySize = m_uiBDataSize - m_uiBOffset; - if( uiLength < uiCopySize) - { - uiCopySize = uiLength; - } - - if( pucPos) - { -#if defined( FLM_NLM) || defined( FLM_WIN) - if( uiCopySize == 1) - { - *pucPos = m_pucBuffer[ m_uiBOffset]; - } - else if( uiLength == 2) - { - *(FLMUINT16 *)pucPos = *((FLMUINT16 *)&m_pucBuffer[ m_uiBOffset]); - } - else if( uiLength == 4) - { - *(FLMUINT32 *)pucPos = *((FLMUINT32 *)&m_pucBuffer[ m_uiBOffset]); - } - else - { - f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize); - } -#else - f_memcpy( pucPos, &(m_pucBuffer[ m_uiBOffset]), uiCopySize); -#endif - pucPos += uiCopySize; - } - m_uiBOffset += uiCopySize; - uiLength -= uiCopySize; - } - -Exit: - - if( RC_OK( rc) && uiLength) - { - /* - Unable to satisfy the read request. - */ - - rc = RC_SET( FERR_EOF_HIT); - } - - if( puiBytesRead) - { - (*puiBytesRead) -= uiLength; - } - - return( rc); -} - - -/**************************************************************************** -Desc: Reads a binary token from the stream. The token is tagged with a - length. -****************************************************************************/ -RCODE FCS_DIS::readBinary( - POOL * pPool, - FLMBYTE ** ppValue, - FLMUINT * puiDataSize) -{ - FLMUINT16 ui16DataSize; - RCODE rc = FERR_OK; - - if( RC_BAD( rc = readUShort( &ui16DataSize))) - { - goto Exit; - } - - if( pPool) - { - /* - If the data size is non-zero, allocate a buffer and - read the entire binary value. - */ - - if( ui16DataSize) - { - if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui16DataSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = read( *ppValue, ui16DataSize, NULL))) - { - goto Exit; - } - } - else - { - *ppValue = NULL; - } - } - else - { - /* - The application is not interested in the value. Just skip the - to the end of the value. - */ - - if( RC_BAD( rc = skip( ui16DataSize))) - { - goto Exit; - } - } - -Exit: - - if( puiDataSize) - { - *puiDataSize = ui16DataSize; - } - - return( rc); -} - - -/**************************************************************************** -Desc: Reads a large binary token from the stream. The token is tagged with a - length. -****************************************************************************/ -RCODE FCS_DIS::readLargeBinary( - POOL * pPool, - FLMBYTE ** ppValue, - FLMUINT * puiDataSize) -{ - FLMUINT32 ui32DataSize; - RCODE rc = FERR_OK; - - if( RC_BAD( rc = readUInt( &ui32DataSize))) - { - goto Exit; - } - - if( pPool) - { - /* - If the data size is non-zero, allocate a buffer and - read the entire binary value. - */ - - if( ui32DataSize) - { - if( (*ppValue = (FLMBYTE *)GedPoolAlloc( pPool, ui32DataSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = read( *ppValue, ui32DataSize, NULL))) - { - goto Exit; - } - } - else - { - *ppValue = NULL; - } - } - else - { - /* - The application is not interested in the value. Just skip the - to the end of the value. - */ - - if( RC_BAD( rc = skip( ui32DataSize))) - { - goto Exit; - } - } - -Exit: - - if( puiDataSize) - { - *puiDataSize = (FLMUINT)ui32DataSize; - } - - return( rc); -} - - -/**************************************************************************** -Desc: Reads a UTF-8 string from the stream. -****************************************************************************/ -RCODE FCS_DIS::readUTF( - POOL * pPool, - FLMUNICODE ** ppValue) -{ - FLMBYTE ucByte1; - FLMBYTE ucByte2; - FLMBYTE ucByte3; - FLMBYTE ucLoByte; - FLMBYTE ucHiByte; - FLMUINT16 ui16UTFLen; - FLMUINT uiOffset = 0; - RCODE rc = FERR_OK; - - /* - Read the data. - */ - - if( RC_BAD( rc = readUShort( &ui16UTFLen))) - { - goto Exit; - } - - /* - Check the size of the UTF string. FLAIM does not support - strings that are larger than 32K characters. - */ - - if( ui16UTFLen >= 32767) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Allocate space for the string. - */ - - if( pPool) - { - *ppValue = (FLMUNICODE *)GedPoolAlloc( pPool, - (FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * (FLMUINT)(ui16UTFLen + 1))); - } - else if( ppValue) - { - *ppValue = NULL; - } - - while( ui16UTFLen) - { - /* - Read and decode the bytes. - */ - - if( RC_BAD( rc = read( &ucByte1, 1, NULL))) - { - goto Exit; - } - - if( (ucByte1 & 0xC0) != 0xC0) - { - ucHiByte = 0; - ucLoByte = ucByte1; - } - else - { - if( RC_BAD( rc = read( &ucByte2, 1, NULL))) - { - goto Exit; - } - - if( (ucByte1 & 0xE0) == 0xE0) - { - if( RC_BAD( rc = read( &ucByte3, 1, NULL))) - { - goto Exit; - } - - ucHiByte = - (FLMBYTE)(((ucByte1 & 0x0F) << 4) | ((ucByte2 & 0x3C) >> 2)); - ucLoByte = (FLMBYTE)(((ucByte2 & 0x03) << 6) | (ucByte3 & 0x3F)); - } - else - { - ucHiByte = (FLMBYTE)(((ucByte1 & 0x1C) >> 2)); - ucLoByte = (FLMBYTE)(((ucByte1 & 0x03) << 6) | (ucByte2 & 0x3F)); - } - } - - if( pPool) - { - (*ppValue)[ uiOffset] = - (FLMUNICODE)(((((FLMUNICODE)(ucHiByte)) << 8) | - ((FLMUNICODE)(ucLoByte)))); - } - - uiOffset++; - ui16UTFLen--; - } - - if( pPool) - { - (*ppValue)[ uiOffset] = 0; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Reads an Hierarchical Tagged Data record from the stream. -****************************************************************************/ -RCODE FCS_DIS::readHTD( - POOL * pPool, - FLMUINT uiContainer, - FLMUINT uiDrn, - NODE ** ppNode, - FlmRecord ** ppRecord) -{ - - FLMBYTE ucType; - FLMBYTE ucLevel = 0; - FLMBYTE ucPrevLevel = 0; - FLMBYTE ucDescriptor; - FLMBYTE ucFlags; - FLMUINT16 ui16Tag; - FLMBOOL bHasValue; - FLMBOOL bChild; - FLMBOOL bSibling; - FLMBOOL bLeftTruncated; - FLMBOOL bRightTruncated; - NODE * pRoot = NULL; - NODE * pNode = NULL; - NODE * pPrevNode = NULL; - void * pField = NULL; - void * pvMark = NULL; - RCODE rc = FERR_OK; - - if( pPool) - { - pvMark = GedPoolMark( pPool); - } - - for( ;;) - { - /* - Reset variables. - */ - - bChild = FALSE; - bSibling = FALSE; - - /* - Read the attribute's tag number. - */ - - if( RC_BAD( rc = readUShort( &ui16Tag))) - { - goto Exit; - } - - /* - A tag number of 0 indicates that the end of the HTD data - stream has been reached. - */ - - if( !ui16Tag) - { - break; - } - - /* - Read the attribute's descriptor. - */ - - if( RC_BAD(rc = read( &ucDescriptor, 1, NULL))) - { - goto Exit; - } - - /* - Set the flag indicating whether or not the - attribute has a value. - */ - - bHasValue = (FLMBOOL)((ucDescriptor & HTD_HAS_VALUE_FLAG) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - - /* - Set the value type. - */ - - ucType = (FLMBYTE)((ucDescriptor & HTD_VALUE_TYPE_MASK)); - - /* - Get the attribute's level. - */ - - switch( (ucDescriptor & HTD_LEVEL_MASK) >> HTD_LEVEL_POS) - { - case HTD_LEVEL_SIBLING: - { - bSibling = TRUE; - ucLevel = ucPrevLevel; - break; - } - - case HTD_LEVEL_CHILD: - { - if( ucLevel < 0xFF) - { - bChild = TRUE; - ucLevel = (FLMBYTE)(ucPrevLevel + 1); - } - else - { - rc = RC_SET( FERR_BAD_FIELD_LEVEL); - goto Exit; - } - break; - } - - case HTD_LEVEL_BACK: - { - if( ucLevel > 0) - { - ucLevel = (FLMBYTE)(ucPrevLevel - 1); - } - else - { - rc = RC_SET( FERR_BAD_FIELD_LEVEL); - goto Exit; - } - break; - } - - case HTD_LEVEL_BACK_X: - { - FLMBYTE ucLevelsBack; - - if( RC_BAD(rc = read( &ucLevelsBack, 1, NULL))) - { - goto Exit; - } - - if( ucPrevLevel >= ucLevelsBack) - { - ucLevel = (FLMBYTE)(ucPrevLevel - ucLevelsBack); - } - else - { - rc = RC_SET( FERR_BAD_FIELD_LEVEL); - goto Exit; - } - break; - } - } - - /* - Allocate the record object - */ - - if( ppRecord && ucLevel == 0) - { - if( *ppRecord) - { - if( (*ppRecord)->isReadOnly() || - (*ppRecord)->getRefCount() > 1) - { - (*ppRecord)->Release(); - - if( (*ppRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - else - { - // Reuse the existing FlmRecord object. - (*ppRecord)->clear(); - } - } - else - { - if( (*ppRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - (*ppRecord)->setContainerID( uiContainer); - (*ppRecord)->setID( uiDrn); - } - - /* - Allocate the attribute. - */ - - if( pPool && ppNode) - { - pNode = GedNodeMake( pPool, ui16Tag, &rc); - if( RC_BAD( rc)) - { - goto Exit; - } - } - - bLeftTruncated = FALSE; - bRightTruncated = FALSE; - - /* - Read the attribute's value. - */ - - switch( ucType) - { - case HTD_TYPE_UNICODE: - { - FLMUNICODE * pUTF; - - if( pNode) - { - GedValTypeSet( pNode, FLM_TEXT_TYPE); - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, FLM_TEXT_TYPE, &pField))) - { - goto Exit; - } - } - - if( !bHasValue) - { - break; - } - - /* - Read UNICODE text in UTF-8 format. - */ - - if( pPool) - { - if( RC_BAD( rc = readUTF( pPool, &pUTF))) - { - goto Exit; - } - - if( pNode) - { - if( RC_BAD( rc = GedPutUNICODE( pPool, pNode, pUTF))) - { - goto Exit; - } - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setUnicode( pField, pUTF))) - { - goto Exit; - } - } - } - else - { - if( RC_BAD( rc = readUTF( NULL, NULL))) - { - goto Exit; - } - } - break; - } - - case HTD_TYPE_UINT: - { - FLMUINT32 ui32Value; - - if( pNode) - { - GedValTypeSet( pNode, FLM_NUMBER_TYPE); - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, FLM_NUMBER_TYPE, &pField))) - { - goto Exit; - } - } - - if( !bHasValue) - { - break; - } - - /* - Read an unsigned 32-bit integer. - */ - - if( RC_BAD( rc = readUInt( &ui32Value))) - { - goto Exit; - } - - if( pNode) - { - if( RC_BAD( rc = GedPutUINT( pPool, pNode, ui32Value))) - { - goto Exit; - } - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setUINT( pField, ui32Value))) - { - goto Exit; - } - } - - break; - } - - case HTD_TYPE_INT: - { - FLMINT32 i32Value; - - if( pNode) - { - GedValTypeSet( pNode, FLM_NUMBER_TYPE); - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, FLM_NUMBER_TYPE, &pField))) - { - goto Exit; - } - } - - if( !bHasValue) - { - break; - } - - /* - Read a signed 32-bit integer. - */ - - if( RC_BAD( rc = readInt( &i32Value))) - { - goto Exit; - } - - if( pNode) - { - if( RC_BAD( rc = GedPutINT( pPool, pNode, i32Value))) - { - goto Exit; - } - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setINT( pField, i32Value))) - { - goto Exit; - } - } - - break; - } - - case HTD_TYPE_CONTEXT: - { - FLMUINT32 ui32Value; - - if( pNode) - { - GedValTypeSet( pNode, FLM_CONTEXT_TYPE); - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, FLM_CONTEXT_TYPE, &pField))) - { - goto Exit; - } - } - - if( !bHasValue) - { - break; - } - - /* - Read an unsigned 32-bit integer. - */ - - if( RC_BAD( rc = readUInt( &ui32Value))) - { - goto Exit; - } - - if( pNode) - { - if( RC_BAD( rc = GedPutRecPtr( pPool, pNode, ui32Value))) - { - goto Exit; - } - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setRecPointer( pField, ui32Value))) - { - goto Exit; - } - } - - break; - } - - case HTD_TYPE_BINARY: - { - FLMUINT16 ui16DataSize; - FLMBYTE * pucData = NULL; - - if( pNode) - { - GedValTypeSet( pNode, FLM_BINARY_TYPE); - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, FLM_BINARY_TYPE, &pField))) - { - goto Exit; - } - } - - if( !bHasValue) - { - break; - } - - /* - Read a binary data stream. - */ - - if( RC_BAD( rc = readUShort( &ui16DataSize))) - { - goto Exit; - } - - if( pPool) - { - if( pNode) - { - if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode, - FLM_BINARY_TYPE, ui16DataSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - else if( ppRecord) - { - if( RC_BAD(rc = (*ppRecord)->allocStorageSpace( pField, - FLM_BINARY_TYPE, ui16DataSize, 0, 0, 0, &pucData, NULL))) - { - goto Exit; - } - } - - if( RC_BAD( rc = read( pucData, ui16DataSize, NULL))) - { - goto Exit; - } - - if( pNode) - { - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize))) - { - goto Exit; - } - } - } - } - else - { - if( RC_BAD( rc = skip( ui16DataSize))) - { - goto Exit; - } - } - break; - } - - case HTD_TYPE_DATE: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - case HTD_TYPE_GEDCOM: - { - FLMBYTE ucGedType; - FLMUINT16 ui16DataSize; - FLMBYTE * pucData = NULL; - - /* - Read the GEDCOM data type and flags - */ - - if( RC_BAD( rc = read( &ucGedType, 1, NULL))) - { - goto Exit; - } - ucFlags = ucGedType & 0xF0; - ucGedType &= 0x0F; - - if( ucFlags & 0x10) - { - bLeftTruncated = TRUE; - } - - if( ucFlags & 0x20) - { - bRightTruncated = TRUE; - } - - if( ucGedType != FLM_TEXT_TYPE && - ucGedType != FLM_NUMBER_TYPE && - ucGedType != FLM_BINARY_TYPE && - ucGedType != FLM_BLOB_TYPE && - ucGedType != FLM_CONTEXT_TYPE) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - if( pNode) - { - GedValTypeSet( pNode, ucGedType); - if( bLeftTruncated) - { - GedSetLeftTruncated( pNode); - } - - if( bRightTruncated) - { - GedSetRightTruncated( pNode); - } - } - - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->insertLast( ucLevel, - ui16Tag, ucGedType, &pField))) - { - goto Exit; - } - - if( bLeftTruncated) - { - (*ppRecord)->setLeftTruncated( pField, TRUE); - } - - if( bRightTruncated) - { - (*ppRecord)->setRightTruncated( pField, TRUE); - } - } - - if( !bHasValue) - { - break; - } - - /* - Read the data size. - */ - - if( RC_BAD( rc = readUShort( &ui16DataSize))) - { - goto Exit; - } - - /* - Read the data value. - */ - - if( pPool) - { - if( pNode) - { - if( (pucData = (FLMBYTE *)GedAllocSpace( pPool, pNode, - ucGedType, ui16DataSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - else if( ppRecord) - { - if (RC_BAD( rc = (*ppRecord)->allocStorageSpace( pField, - ucGedType, ui16DataSize, 0, 0, 0, &pucData, NULL))) - { - goto Exit; - } - } - - if( RC_BAD( rc = read( pucData, ui16DataSize, NULL))) - { - goto Exit; - } - - if( pNode) - { - if( ppRecord) - { - if( RC_BAD( rc = (*ppRecord)->setBinary( pField, pucData, ui16DataSize))) - { - goto Exit; - } - } - } - } - else - { - if( RC_BAD( rc = skip( ui16DataSize))) - { - goto Exit; - } - } - break; - } - - default: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - - /* - Set the truncation flags - */ - - if( ucType != HTD_TYPE_GEDCOM) - { - if( pNode) - { - if( bLeftTruncated) - { - GedSetLeftTruncated( pNode); - } - - if( bRightTruncated) - { - GedSetRightTruncated( pNode); - } - } - else if( pField) - { - if( bLeftTruncated) - { - (*ppRecord)->setLeftTruncated( pField, TRUE); - } - - if( bRightTruncated) - { - (*ppRecord)->setRightTruncated( pField, TRUE); - } - } - } - - /* - Graft the attribute into the tree. - */ - - if( pNode) - { - if( pRoot == NULL) - { - pRoot = pNode; - } - else - { - if( bSibling) - { - pPrevNode->next = pNode; - pNode->prior = pPrevNode; - GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode)); - } - else if( bChild) - { - pPrevNode->next = pNode; - pNode->prior = pPrevNode; - GedNodeLevelSet( pNode, GedNodeLevel( pPrevNode) + 1); - } - else - { - pPrevNode->next = pNode; - pNode->prior = pPrevNode; - GedNodeLevelSet( pNode, ucLevel); - } - } - } - - ucPrevLevel = ucLevel; - pPrevNode = pNode; - - /* - Reset the pool if a GEDCOM record is not - going to be returned. - */ - - if( pPool && !ppNode) - { - GedPoolReset( pPool, pvMark); - } - } - -Exit: - - if( RC_OK( rc)) - { - if( ppNode) - { - *ppNode = pRoot; - } - } - else - { - if( ppRecord && *ppRecord) - { - (*ppRecord)->Release(); - } - } - - if( pPool && !ppNode) - { - GedPoolReset( pPool, pvMark); - } - - return( rc); -} diff --git a/flaim/src/fcs_dos.cpp b/flaim/src/fcs_dos.cpp deleted file mode 100644 index 1a6d918..0000000 --- a/flaim/src/fcs_dos.cpp +++ /dev/null @@ -1,898 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Data output stream class. -// Tabs: 3 -// -// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_dos.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -****************************************************************************/ -FCS_DOS::FCS_DOS( void) -{ - m_pOStream = NULL; - m_uiBOffset = 0; - GedPoolInit( &m_tmpPool, 512); - m_bSetupCalled = FALSE; -} - - -/**************************************************************************** -Desc: -****************************************************************************/ -FCS_DOS::~FCS_DOS( void) -{ - if( m_bSetupCalled) - { - (void)close(); - } - GedPoolFree( &m_tmpPool); -} - -/**************************************************************************** -Desc: Writes a specified number of bytes from a buffer to the output - stream. -****************************************************************************/ -RCODE FCS_DOS::write( - FLMBYTE * pucData, - FLMUINT uiLength) -{ - RCODE rc = FERR_OK; - - /* - Verify that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Write the data. - */ - -Retry_Write: - - if( FCS_DOS_BUFFER_SIZE - m_uiBOffset >= uiLength) - { -#if defined( FLM_NLM) || defined( FLM_WIN) - if( uiLength == 1) - { - m_pucBuffer[ m_uiBOffset] = *pucData; - m_uiBOffset++; - } - else if( uiLength == 2) - { - *(FLMUINT16 *)&(m_pucBuffer[ m_uiBOffset]) = *((FLMUINT16 *)pucData); - m_uiBOffset += 2; - } - else if( uiLength == 4) - { - *(FLMUINT32 *)&(m_pucBuffer[ m_uiBOffset]) = *((FLMUINT32 *)pucData); - m_uiBOffset += 4; - } - else - { - f_memcpy( &(m_pucBuffer[ m_uiBOffset]), pucData, uiLength); - m_uiBOffset += uiLength; - } -#else - f_memcpy( &(m_pucBuffer[ m_uiBOffset]), pucData, uiLength); - m_uiBOffset += uiLength; -#endif - } - else - { - if( m_uiBOffset > 0) - { - if( RC_BAD( rc = flush())) - { - goto Exit; - } - } - - if( uiLength <= FCS_DOS_BUFFER_SIZE) - { - goto Retry_Write; - } - - if( RC_BAD( rc = m_pOStream->write( pucData, uiLength))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Writes a UNICODE string to the stream in the UTF-8 format. -****************************************************************************/ -RCODE FCS_DOS::writeUTF( - FLMUNICODE * puzValue) -{ - FLMUINT uiUTFLen; - FLMUNICODE * puzTmp; - RCODE rc = FERR_OK; - - /* - Verify that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Verify pValue is valid. - */ - - flmAssert( puzValue != NULL); - - /* - Determine the size of the string. - */ - - uiUTFLen = 0; - puzTmp = puzValue; - while( *puzTmp) - { - uiUTFLen++; - puzTmp++; - } - - if( RC_BAD( rc = writeUShort( (FLMUINT16)uiUTFLen))) - { - goto Exit; - } - - puzTmp = puzValue; - while( *puzTmp) - { - if( *puzTmp <= 0x007F) - { - if( RC_BAD( rc = writeByte( (FLMBYTE)(*puzTmp)))) - { - goto Exit; - } - } - else if( *puzTmp >= 0x0080 && *puzTmp <= 0x07FF) - { - if( RC_BAD( rc = writeUShort((FLMUINT16) - ((((FLMUINT16)(0xC0 | (FLMBYTE)((*puzTmp & 0x07C0) >> 6))) << 8) | - (FLMUINT16)(0x80 | (FLMBYTE)(*puzTmp & 0x003F)))))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = writeUShort((FLMUINT16) - ((((FLMUINT16)(0xE0 | (FLMBYTE)((*puzTmp & 0xF000) >> 12))) << 8) | - (FLMUINT16)(0x80 | (FLMBYTE)((*puzTmp & 0x0FC0) >> 6)))))) - { - goto Exit; - } - - if( RC_BAD( rc = writeByte( (0x80 | (FLMBYTE)(*puzTmp & 0x003F))))) - { - goto Exit; - } - } - - puzTmp++; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Writes a binary token (including length) to the stream. -****************************************************************************/ -RCODE FCS_DOS::writeBinary( - FLMBYTE * pucValue, - FLMUINT uiSize) -{ - RCODE rc = FERR_OK; - - flmAssert( uiSize <= 0x0000FFFF); - - if( RC_BAD( rc = writeUShort( (FLMUINT16)uiSize))) - { - goto Exit; - } - - if( uiSize) - { - if( RC_BAD( rc = write( pucValue, uiSize))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Writes a large binary token (including length) to the stream. -****************************************************************************/ -RCODE FCS_DOS::writeLargeBinary( - FLMBYTE * pucValue, - FLMUINT uiSize) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiSize))) - { - goto Exit; - } - - if( uiSize) - { - if( RC_BAD( rc = write( pucValue, uiSize))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Writes a Hierarchical Tagged Data record to the stream. -****************************************************************************/ -RCODE FCS_DOS::writeHTD( - NODE * pHTD, - FlmRecord * pRecord, - FLMBOOL bSendForest, - FLMBOOL bSendAsGedcom) -{ - FLMUINT uiPrevLevel = 0; - FLMUINT uiLevelsBack = 0; - FLMUINT uiDescriptor = 0; - FLMUINT uiCurLevel = 0; - FLMUINT uiCurValType = 0; - FLMUINT uiCurDataLen = 0; - FLMBOOL bLeftTruncated; - FLMBOOL bRightTruncated; - FLMBYTE * pucCurData = NULL; - FLMBYTE pucTmpBuf[ 32]; - void * pvMark = GedPoolMark( &m_tmpPool); - NODE * pCurNode = NULL; - void * pCurField = NULL; - RCODE rc = FERR_OK; - - /* - Verify that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Set the current node or field - */ - - if( pHTD) - { - pCurNode = pHTD; - } - else - { - pCurField = pRecord->root(); - } - - while( pCurNode || pCurField) - { - /* - See if we are done sending the tree/forest. - */ - - if( pCurNode) - { - if( !bSendForest && (pCurNode != pHTD) && - (GedNodeLevel( pCurNode) == GedNodeLevel( pHTD))) - { - break; - } - } - - /* - Output the attribute's tag number. - */ - - if( pCurNode) - { - flmUINT16ToBigEndian( (FLMUINT16)GedTagNum( pCurNode), pucTmpBuf); - } - else if( pCurField) - { - flmUINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pCurField), pucTmpBuf); - } - - if( RC_BAD( rc = write( pucTmpBuf, 2))) - { - goto Exit; - } - - /* - Setup the attribute's descriptor. - */ - - uiDescriptor = 0; - uiLevelsBack = 0; - - if( pCurNode) - { - uiCurLevel = GedNodeLevel( pCurNode); - } - else - { - uiCurLevel = pRecord->getLevel( pCurField); - } - - if( uiCurLevel == uiPrevLevel) - { - (void)(uiDescriptor |= (HTD_LEVEL_SIBLING << HTD_LEVEL_POS)); - } - else if( uiCurLevel == uiPrevLevel + 1) - { - uiDescriptor |= (HTD_LEVEL_CHILD << HTD_LEVEL_POS); - } - else if( uiCurLevel == uiPrevLevel - 1) - { - uiDescriptor |= (HTD_LEVEL_BACK << HTD_LEVEL_POS); - } - else if( uiCurLevel < uiPrevLevel) - { - uiDescriptor |= (HTD_LEVEL_BACK_X << HTD_LEVEL_POS); - uiLevelsBack = uiPrevLevel - uiCurLevel; - } - else - { - flmAssert( 0); - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - if( pCurNode) - { - uiCurDataLen = GedValLen( pCurNode); - uiCurValType = GedValType( pCurNode) & 0x0F; - bLeftTruncated = GedIsLeftTruncated( pCurNode); - bRightTruncated = GedIsRightTruncated( pCurNode); - pucCurData = (FLMBYTE *)GedValPtr( pCurNode); - } - else - { - uiCurDataLen = pRecord->getDataLength( pCurField); - uiCurValType = (FLMUINT)pRecord->getDataType( pCurField); - bLeftTruncated = pRecord->isLeftTruncated( pCurField); - bRightTruncated = pRecord->isRightTruncated( pCurField); - pucCurData = (FLMBYTE *)(pRecord->getDataPtr( pCurField)); - } - - if( uiCurDataLen) - { - uiDescriptor |= HTD_HAS_VALUE_FLAG; - } - - if( bSendAsGedcom) - { - uiDescriptor |= HTD_TYPE_GEDCOM; - } - else - { - switch( uiCurValType) - { - case FLM_TEXT_TYPE: - { - uiDescriptor |= HTD_TYPE_UNICODE; - break; - } - - case FLM_NUMBER_TYPE: - { - /* - To save conversion time, cheat to determine if - the number is negative. - */ - - if( ((*pucCurData & 0xF0) == 0xB0)) - { - uiDescriptor |= HTD_TYPE_INT; - } - else - { - uiDescriptor |= HTD_TYPE_UINT; - } - break; - } - - case FLM_CONTEXT_TYPE: - { - uiDescriptor |= HTD_TYPE_CONTEXT; - break; - } - - case FLM_BINARY_TYPE: - { - uiDescriptor |= HTD_TYPE_BINARY; - break; - } - - default: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - } - - /* - Output the attribute's descriptor. - */ - - pucTmpBuf[ 0] = (FLMBYTE)uiDescriptor; - if( RC_BAD( rc = write( pucTmpBuf, 1))) - { - goto Exit; - } - - /* - Output the "levels back" value (if available). - */ - - if( uiLevelsBack) - { - flmAssert( uiLevelsBack <= 0xFF); - pucTmpBuf[ 0] = (FLMBYTE)uiLevelsBack; - if( RC_BAD( rc = write( pucTmpBuf, 1))) - { - goto Exit; - } - } - - /* - Output the attribute's value. - */ - - if( bSendAsGedcom) - { - /* - Output the GEDCOM data type and flags - */ - - pucTmpBuf[ 0] = (FLMBYTE)uiCurValType; - if( bLeftTruncated) - { - pucTmpBuf[ 0] |= 0x10; - } - - if( bRightTruncated) - { - pucTmpBuf[ 0] |= 0x20; - } - - if( RC_BAD( rc = write( pucTmpBuf, 1))) - { - goto Exit; - } - - if( uiCurDataLen) - { - /* - Output the data size. - */ - flmAssert( uiCurDataLen <= 0x0000FFFF); - - flmUINT16ToBigEndian( (FLMUINT16)uiCurDataLen, pucTmpBuf); - if( RC_BAD( rc = write( pucTmpBuf, 2))) - { - goto Exit; - } - - /* - Send the data. - */ - - if( RC_BAD( rc = write( pucCurData, uiCurDataLen))) - { - goto Exit; - } - } - } - else - { - /* - Send the value. - */ - - switch( uiCurValType) - { - case FLM_TEXT_TYPE: - { - /* - Extract the value. - */ - - if( uiCurDataLen) - { - FLMUINT uiBufSize; - FLMUNICODE * puzValue; - - /* - Reset the temporary pool. - */ - - GedPoolReset( &m_tmpPool, pvMark); - if( uiCurDataLen <= 32751) - { - /* - Allocate a buffer that is twice the size of the - attribute's value length. This is necessary because the - UNICODE conversion will may double the size of the - attribute's value. A "safety" zone of 32 bytes is added - to the buffer size to allow for strings that may require - more than 2x the attribute's size and to account for - null-termination bytes. - */ - - uiBufSize = (2 * uiCurDataLen) + 32; - } - else - { - /* - Allocate a full 64K. - */ - - uiBufSize = 65535; - } - - if( (puzValue = (FLMUNICODE *)GedPoolAlloc( &m_tmpPool, - uiBufSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Extract UNICODE from the attribute. - */ - - if( (pCurNode && RC_BAD( rc = GedGetUNICODE( pCurNode, puzValue, &uiBufSize))) || - (pCurField && RC_BAD( rc = pRecord->getUnicode( pCurField, puzValue, &uiBufSize)))) - { - if( rc == FERR_CONV_DEST_OVERFLOW) - { - /* - Since we did not correctly guess the buffer size, - try again. This time, take the slow (but safe) - approach of calculating the size of the UNICODE string. - */ - - if( (pCurNode && RC_BAD( rc = GedGetUNICODE( pCurNode, NULL, &uiBufSize))) || - (pCurField && RC_BAD( rc = pRecord->getUnicodeLength( pCurField, &uiBufSize)))) - { - goto Exit; - } - - /* - Add two bytes to account for null-termination. - */ - - uiBufSize += 2; - - /* - Reset the pool to clear the prior allocation. - */ - - GedPoolReset( &m_tmpPool, pvMark); - - /* - Allocate the new buffer. - */ - - if( (puzValue = (FLMUNICODE *)GedPoolAlloc( &m_tmpPool, - uiBufSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Extract the UNICODE string. - */ - - if( (pCurNode && RC_BAD( rc = GedGetUNICODE( - pCurNode, puzValue, &uiBufSize))) || - (pCurField && RC_BAD( rc = pRecord->getUnicode( - pCurField, puzValue, &uiBufSize)))) - { - goto Exit; - } - } - else - { - goto Exit; - } - } - - /* - Write the attribute's value. - */ - - if( RC_BAD( rc = writeUTF( puzValue))) - { - goto Exit; - } - } - - break; - } - - case FLM_NUMBER_TYPE: - { - if( uiCurDataLen) - { - if( uiDescriptor & HTD_TYPE_INT) - { - /* - Since the number is negative, extract and send it - as a signed 32-bit value. - */ - - FLMINT iValue; - - if( (pCurNode && RC_BAD( rc = GedGetINT( pCurNode, &iValue))) || - (pCurField && RC_BAD( rc = pRecord->getINT( pCurField, &iValue)))) - { - goto Exit; - } - - /* - Write the value. - */ - - if( RC_BAD( rc = writeInt32( (FLMINT32)iValue))) - { - goto Exit; - } - } - else - { - /* - The number is non-negative - */ - - FLMUINT uiValue; - - if( (pCurNode && RC_BAD( rc = GedGetUINT( pCurNode, &uiValue))) || - (pCurField && RC_BAD( rc = pRecord->getUINT( pCurField, &uiValue)))) - { - goto Exit; - } - - /* - Write the value. - */ - - if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiValue))) - { - goto Exit; - } - } - } - break; - } - - case FLM_CONTEXT_TYPE: - { - /* - Extract the value. - */ - - if( uiCurDataLen) - { - /* - The context node has a DRN value associated with - it. Send the value as an unsigned 32-bit number. - */ - - FLMUINT uiDrn; - - if( (pCurNode && RC_BAD( rc = GedGetRecPtr( pCurNode, &uiDrn))) || - (pCurField && RC_BAD( rc = pRecord->getUINT( pCurField, &uiDrn)))) - { - goto Exit; - } - - if( RC_BAD( rc = writeUInt32( (FLMUINT32)uiDrn))) - { - goto Exit; - } - } - break; - } - - case FLM_BINARY_TYPE: - { - /* - Extract the value. - */ - - if( uiCurDataLen) - { - if( RC_BAD( rc = writeUShort( (FLMUINT16)uiCurDataLen))) - { - goto Exit; - } - - if( RC_BAD( rc = write( pucCurData, uiCurDataLen))) - { - goto Exit; - } - } - break; - } - - default: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - } - - uiPrevLevel = uiCurLevel; - if( pCurNode) - { - pCurNode = GedNodeNext( pCurNode); - } - else - { - pCurField = pRecord->next( pCurField); - } - } - - /* - Write a zero tag to indicate the end of the transmission. - */ - - if( RC_BAD( rc = writeUShort( 0))) - { - goto Exit; - } - -Exit: - - GedPoolReset( &m_tmpPool, pvMark); - return( rc); -} - - -/**************************************************************************** -Desc: Flushes any pending data and closes the stream. -****************************************************************************/ -RCODE FCS_DOS::close( void) -{ - RCODE rc = FERR_OK; - - /* - Verify that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Flush and terminate any pending message. - */ - - if( RC_BAD( rc = endMessage())) - { - goto Exit; - } - - - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Flushes pending data. -****************************************************************************/ -RCODE FCS_DOS::flush( void) -{ - /* - Verify that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Flush the output buffer. - */ - - if( m_uiBOffset > 0) - { - m_pOStream->write( m_pucBuffer, m_uiBOffset); - m_uiBOffset = 0; - } - - /* - Flush the parent stream. - */ - - return( m_pOStream->flush()); -} - - -/**************************************************************************** -Desc: Flushes and terminates the current parent stream message -****************************************************************************/ -RCODE FCS_DOS::endMessage( void) -{ - RCODE rc = FERR_OK; - - /* - Verify that Setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( !m_pOStream) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Flush any pending data. - */ - - if( RC_BAD( rc = flush())) - { - goto Exit; - } - - /* - Terminate the message. - */ - - if( RC_BAD( rc = m_pOStream->endMessage())) - { - goto Exit; - } - -Exit: - - return( rc); -} diff --git a/flaim/src/fcs_fis.cpp b/flaim/src/fcs_fis.cpp deleted file mode 100644 index 5767cbd..0000000 --- a/flaim/src/fcs_fis.cpp +++ /dev/null @@ -1,224 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: File input stream class. -// Tabs: 3 -// -// Copyright (c) 2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_fis.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_FIS::FCS_FIS( void) -{ - m_pFileHdl = NULL; - m_pucBufPos = NULL; - m_pucBuffer = NULL; - m_uiFileOffset = 0; - m_uiBlockSize = 0; - m_uiBlockEnd = 0; -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_FIS::~FCS_FIS( void) -{ - if( m_pFileHdl) - { - m_pFileHdl->Release(); - } - - if( m_pucBuffer) - { - f_free( &m_pucBuffer); - } -} - -/**************************************************************************** -Desc: Configures the input stream for use -*****************************************************************************/ -RCODE FCS_FIS::setup( - const char * pszFilePath, - FLMUINT uiBlockSize) -{ - RCODE rc = FERR_OK; - - flmAssert( uiBlockSize); - - if( RC_BAD( rc = close())) - { - goto Exit; - } - - if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( pszFilePath, - F_IO_RDONLY | F_IO_SH_DENYNONE, &m_pFileHdl))) - { - goto Exit; - } - - m_uiBlockSize = uiBlockSize; - if( RC_BAD( rc = f_alloc( m_uiBlockSize, &m_pucBuffer))) - { - goto Exit; - } - m_pucBufPos = m_pucBuffer; - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Closes the input stream and frees any resources -*****************************************************************************/ -RCODE FCS_FIS::close( void) -{ - if( m_pFileHdl) - { - m_pFileHdl->Close(); - m_pFileHdl->Release(); - m_pFileHdl = NULL; - } - - if( m_pucBuffer) - { - f_free( &m_pucBuffer); - } - - return( FERR_OK); -} - -/**************************************************************************** -Desc: Reads the requested amount of data from the stream. -*****************************************************************************/ -RCODE FCS_FIS::read( - FLMBYTE * pucData, - FLMUINT uiLength, - FLMUINT * puiBytesRead) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesRead = 0; - FLMUINT uiMaxSize; - - if( puiBytesRead) - { - *puiBytesRead = 0; - } - - if( !m_pFileHdl) - { - rc = RC_SET( FERR_READING_FILE); - goto Exit; - } - - while( uiLength) - { - uiMaxSize = m_uiBlockEnd - (FLMUINT)(m_pucBufPos - m_pucBuffer); - - if( !uiMaxSize) - { - if( RC_BAD( rc = getNextPacket())) - { - goto Exit; - } - } - else if( uiLength <= uiMaxSize) - { - f_memcpy( pucData, m_pucBufPos, uiLength); - m_pucBufPos += uiLength; - uiBytesRead += uiLength; - uiLength = 0; - } - else - { - f_memcpy( pucData, m_pucBufPos, uiMaxSize); - m_pucBufPos += uiMaxSize; - pucData += uiMaxSize; - uiLength -= uiMaxSize; - uiBytesRead += uiMaxSize; - } - } - -Exit: - - if( puiBytesRead) - { - *puiBytesRead = uiBytesRead; - } - - return( rc); -} - -/**************************************************************************** -Desc: Flushes any pending data. -*****************************************************************************/ -RCODE FCS_FIS::flush( void) -{ - return( FERR_OK); -} - -/**************************************************************************** -Desc: Flushes any pending data. -*****************************************************************************/ -RCODE FCS_FIS::endMessage( void) -{ - return( FERR_OK); -} - -/**************************************************************************** -Desc: Returns TRUE if the stream is open -*****************************************************************************/ -FLMBOOL FCS_FIS::isOpen( void) -{ - return( TRUE); -} - -/**************************************************************************** -Desc: Reads the next block from the file -*****************************************************************************/ -RCODE FCS_FIS::getNextPacket( void) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = m_pFileHdl->Read( m_uiFileOffset, m_uiBlockSize, - m_pucBuffer, &m_uiBlockEnd))) - { - if( rc == FERR_IO_END_OF_FILE) - { - if( !m_uiBlockEnd) - { - goto Exit; - } - else - { - rc = FERR_OK; - } - } - } - - m_uiFileOffset += m_uiBlockEnd; - m_pucBufPos = m_pucBuffer; - -Exit: - - return( rc); -} diff --git a/flaim/src/fcs_ipis.cpp b/flaim/src/fcs_ipis.cpp deleted file mode 100644 index f852790..0000000 --- a/flaim/src/fcs_ipis.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: TCP/IP input stream class. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_ipis.cpp 12251 2006-01-19 14:33:30 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: Constructor -*****************************************************************************/ -FCS_IPIS::FCS_IPIS( FCS_TCP * pTcpObj) -{ - m_pTcpObj = pTcpObj; - m_pucBufPos = m_pucBuffer; - m_bStreamInvalid = FALSE; - m_bMessageActive = FALSE; - m_bGotLastPacket = FALSE; - m_uiPacketSize = 0; -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_IPIS::~FCS_IPIS( void) -{ - (void)close(); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FLMBOOL FCS_IPIS::isOpen( void) -{ - return( TRUE); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -RCODE FCS_IPIS::close( void) -{ - (void)endMessage(); - m_bStreamInvalid = FALSE; - return( FERR_OK); -} - -/**************************************************************************** -Desc: Reads the requested amount of data from the stream. -*****************************************************************************/ -RCODE FCS_IPIS::read( - FLMBYTE * pucData, - FLMUINT uiLength, - FLMUINT * puiBytesRead) -{ - FLMUINT uiBytesRead = 0; - FLMUINT uiMaxSize; - RCODE rc = FERR_OK; - - if( puiBytesRead) - { - *puiBytesRead = 0; - } - - if( !m_bStreamInvalid) - { - while( uiLength) - { - uiMaxSize = m_uiPacketSize - (FLMUINT)(m_pucBufPos - m_pucBuffer); - - if( !uiMaxSize) - { - if( RC_BAD( rc = getNextPacket())) - { - goto Exit; - } - } - else if( uiLength <= uiMaxSize) - { - f_memcpy( pucData, m_pucBufPos, uiLength); - m_pucBufPos += uiLength; - uiBytesRead += uiLength; - uiLength = 0; - } - else - { - f_memcpy( pucData, m_pucBufPos, uiMaxSize); - m_pucBufPos += uiMaxSize; - pucData += uiMaxSize; - uiLength -= uiMaxSize; - uiBytesRead += uiMaxSize; - } - } - } - else - { - rc = RC_SET( FERR_READING_FILE); - } - -Exit: - - if( puiBytesRead) - { - *puiBytesRead = uiBytesRead; - } - - return( rc); -} - -/**************************************************************************** -Desc: Flushes any pending data. -*****************************************************************************/ -RCODE FCS_IPIS::flush( void) -{ - RCODE rc = FERR_OK; - - if( !m_bMessageActive) - { - goto Exit; - } - - for( ;;) - { - if( RC_BAD( rc = getNextPacket())) - { - if( rc == FERR_EOF_HIT) - { - rc = FERR_OK; - } - goto Exit; - } - } - -Exit: - - m_pucBufPos = m_pucBuffer; - return( rc); -} - - -/**************************************************************************** -Desc: Flushes any pending data. -*****************************************************************************/ -RCODE FCS_IPIS::endMessage( void) -{ - RCODE rc = FERR_OK; - - if( !m_bMessageActive) - { - goto Exit; - } - - if( RC_BAD( rc = flush())) - { - goto Exit; - } - -Exit: - - m_bMessageActive = FALSE; - m_bGotLastPacket = FALSE; - return( rc); -} - - -/**************************************************************************** -Desc: Reads the next packet off the wire. -*****************************************************************************/ -RCODE FCS_IPIS::getNextPacket( void) -{ - FLMBYTE pucDescriptor[ 2]; - FLMUINT uiDescriptor; - FLMUINT uiActualCnt = 0; - RCODE rc = FERR_OK; - - if( !m_bStreamInvalid) - { - if( !m_bMessageActive) - { - m_bMessageActive = TRUE; - } - - if( m_bGotLastPacket) - { - rc = RC_SET( FERR_EOF_HIT); - goto Exit; - } - - if( RC_BAD( rc = m_pTcpObj->readAll( pucDescriptor, - 2, &uiActualCnt))) - { - goto Exit; - } - - uiDescriptor = flmBigEndianToUINT16( pucDescriptor); - m_uiPacketSize = uiDescriptor & 0x7FFF; - - if( uiDescriptor & 0x8000) - { - m_bGotLastPacket = TRUE; - } - - if( m_uiPacketSize > FCS_IPIS_BUFFER_SIZE) - { - m_uiPacketSize = 0; - rc = RC_SET( FERR_READING_FILE); - goto Exit; - } - - if( m_uiPacketSize > 0) - { - if( RC_BAD( rc = m_pTcpObj->readAll( m_pucBuffer, - m_uiPacketSize, &uiActualCnt))) - { - goto Exit; - } - } - else - { - if( m_bGotLastPacket) - { - rc = RC_SET( FERR_EOF_HIT); - } - else - { - rc = RC_SET( FERR_READING_FILE); - } - goto Exit; - } - - m_pucBufPos = m_pucBuffer; - } - else - { - rc = RC_SET( FERR_READING_FILE); - } - -Exit: - - if( RC_BAD( rc) && rc != FERR_EOF_HIT) - { - m_bStreamInvalid = TRUE; - } - - return( rc); -} diff --git a/flaim/src/fcs_ipos.cpp b/flaim/src/fcs_ipos.cpp deleted file mode 100644 index 5d518ec..0000000 --- a/flaim/src/fcs_ipos.cpp +++ /dev/null @@ -1,176 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: TCP/IP output stream class. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_ipos.cpp 12251 2006-01-19 14:33:30 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_IPOS::FCS_IPOS( FCS_TCP * pTcpObj) -{ - m_pTcpObj = pTcpObj; - m_pucBufPos = &(m_pucBuffer[ 2]); - m_bOpen = TRUE; - m_bMessageActive = FALSE; -} - - -/**************************************************************************** -Desc: Flushes any pending data and closes the stream. -*****************************************************************************/ -RCODE FCS_IPOS::close( void) -{ - RCODE rc = FERR_OK; - - if( m_bOpen) - { - rc = endMessage(); - m_bOpen = FALSE; - } - - return( rc); -} - - -/**************************************************************************** -Desc: Writes the requested amount of data to the stream. -*****************************************************************************/ -RCODE FCS_IPOS::write( - FLMBYTE * pucData, - FLMUINT uiLength) -{ - FLMUINT uiMaxSize; - RCODE rc = FERR_OK; - - if( !uiLength) - { - goto Exit; - } - - if( m_bOpen) - { - while( uiLength) - { - uiMaxSize = - (FLMUINT)(FCS_IPOS_BUFFER_SIZE - (m_pucBufPos - m_pucBuffer)); - - if( !uiMaxSize) - { - if( RC_BAD( rc = flush())) - { - goto Exit; - } - } - else if( uiLength <= uiMaxSize) - { - f_memcpy( m_pucBufPos, pucData, uiLength); - m_pucBufPos += uiLength; - uiLength = 0; - } - else - { - f_memcpy( m_pucBufPos, pucData, uiMaxSize); - m_pucBufPos += uiMaxSize; - pucData += uiMaxSize; - uiLength -= uiMaxSize; - if( RC_BAD( rc = flush())) - { - goto Exit; - } - } - } - m_bMessageActive = TRUE; - } - else - { - rc = RC_SET( FERR_WRITING_FILE); - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Flushes any pending data and optionally ends the current message. -*****************************************************************************/ -RCODE FCS_IPOS::_flush( - FLMBOOL bEndMessage) -{ - FLMUINT uiActualCnt; - FLMUINT uiLength; - FLMUINT uiDescriptor; - RCODE rc = FERR_OK; - - if( (uiLength = (FLMUINT)(m_pucBufPos - m_pucBuffer)) != 0) - { - uiDescriptor = uiLength - 2; - if( bEndMessage) - { - uiDescriptor |= 0x8000; - } - - if( uiDescriptor) - { - flmUINT16ToBigEndian( (FLMUINT16)uiDescriptor, m_pucBuffer); - - if( RC_BAD( rc = m_pTcpObj->write( m_pucBuffer, - uiLength, &uiActualCnt))) - { - goto Exit; - } - } - } - -Exit: - - m_pucBufPos = &(m_pucBuffer[ 2]); - return( rc); -} - - -/**************************************************************************** -Desc: Terminates the current message -*****************************************************************************/ -RCODE FCS_IPOS::endMessage( void) -{ - RCODE rc = FERR_OK; - - - if( !m_bMessageActive) - { - goto Exit; - } - - if( RC_BAD( rc = _flush( TRUE))) - { - goto Exit; - } - -Exit: - - m_bMessageActive = FALSE; - return( rc); -} diff --git a/flaim/src/fcs_tcp.cpp b/flaim/src/fcs_tcp.cpp deleted file mode 100644 index e557823..0000000 --- a/flaim/src/fcs_tcp.cpp +++ /dev/null @@ -1,960 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: TCP/IP networking. -// Tabs: 3 -// -// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_tcp.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -// These must be defined BEFORE any includes. Unfortunately, this -// also means that we can't use our FLM_HPUX define because it hasn't -// been set yet... - -#if defined( __hpux) || defined( hpux) - #define _XOPEN_SOURCE_EXTENDED 1 - #define _INCLUDE_HPUX_SOURCE -#endif - -#include "flaimsys.h" - -#if defined( FLM_NLM) && !defined ( __MWERKS__) - // Disable errors for "expression for 'while' is always false" - // Needed for FD_SET macro - #pragma warning 555 9 -#endif - -#ifdef FLM_WIN - #pragma warning(disable : 4127) // conditional expression is constant (from FD_SET()) -#endif - -/******************************************************************** -Desc: Constructor -*********************************************************************/ -FCS_TCP::FCS_TCP( void) -{ - m_pszIp[ 0] = '\0'; - m_pszName[ 0] = '\0'; - m_pszPeerIp[ 0] = '\0'; - m_pszPeerName[ 0] = '\0'; - m_uiIOTimeout = 10; - m_iSocket = INVALID_SOCKET; - m_ulRemoteAddr = 0; - m_bInitialized = FALSE; - m_bConnected = FALSE; - -#ifndef FLM_UNIX - if( !WSAStartup( MAKEWORD(2, 0), &m_wsaData)) - { - m_bInitialized = TRUE; - } -#endif -} - - -/******************************************************************** -Desc: Destructor -*********************************************************************/ -FCS_TCP::~FCS_TCP( void ) -{ - if( m_bConnected) - { - close(); - } - -#ifndef FLM_UNIX - if( m_bInitialized) - { - WSACleanup(); - } -#endif -} - -/******************************************************************** -Desc: Gets information about the local host machine. -*********************************************************************/ -RCODE FCS_TCP::_GetLocalInfo( void) -{ - struct hostent * pHostEnt; - FLMUINT32 ui32IPAddr; - RCODE rc = FERR_OK; - - m_pszIp[ 0] = '\0'; - m_pszName[ 0] = '\0'; - - if( m_pszName[ 0] == '\0') - { - if( gethostname( m_pszName, (unsigned)sizeof( m_pszName))) - { - rc = RC_SET( FERR_SVR_SOCK_FAIL); - goto Exit; - } - } - - if( m_pszIp[ 0] == '\0' && - (pHostEnt = gethostbyname( m_pszName)) != NULL) - { - ui32IPAddr = (FLMUINT32)(*((unsigned long *)pHostEnt->h_addr)); - if( ui32IPAddr != (FLMUINT32)-1) - { - struct in_addr InAddr; - - InAddr.s_addr = ui32IPAddr; - f_strcpy( m_pszIp, inet_ntoa( InAddr)); - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Gets information about the remote machine. -*********************************************************************/ -RCODE FCS_TCP::_GetRemoteInfo( void) -{ - struct sockaddr_in SockAddrIn; - char * InetAddr = NULL; - struct hostent * HostsName; - RCODE rc = FERR_OK; - - m_pszPeerIp[ 0] = '\0'; - m_pszPeerName[ 0] = '\0'; - - SockAddrIn.sin_addr.s_addr = (unsigned)m_ulRemoteAddr; - - /* - inet_ntoa() - converts a 32-bit value in in_addr format into an ASCII - string representing the address in dotted notation. - VISIT: - NetWare: Macro in arpa/inet.h. "Apps with multiple threads should use - NWinet_ntoa instead of inet_ntoa. Then we can get rid of the semaphore! - */ - - InetAddr = inet_ntoa( SockAddrIn.sin_addr ); - f_strcpy( m_pszPeerIp, InetAddr ); - - /* - Try to get the peer's host name by looking up his IP - address. If found, copy IP Host name "BEVIS@NOVELL.COM" to TCPInfo - otherwise, use his IP address as IP name. - VISIT: - Netware: "If your app has multiple threads, use either NWgethostbyaddr - or NetDBgethostbyaddr(). This does the blocking? This may be done - already in netdb.h - it is hard to tell. - */ - - HostsName = gethostbyaddr( (char *)&SockAddrIn.sin_addr.s_addr, - (unsigned)sizeof( unsigned long), AF_INET ); - - if( HostsName != NULL) - { - f_strcpy( m_pszPeerName, (char*) HostsName->h_name ); - } - else - { - if (!InetAddr) - { - InetAddr = inet_ntoa( SockAddrIn.sin_addr); - } - f_strcpy( m_pszPeerName, InetAddr ); - } - - return( rc); -} - -/******************************************************************** -Desc: Tests for socket data readiness -*********************************************************************/ -RCODE FCS_TCP::_SocketPeek( - FLMINT iTimeoutVal, - FLMBOOL bPeekRead - ) -{ - struct timeval TimeOut; - int iMaxDescs; - fd_set GenDescriptors; - fd_set * DescrRead; - fd_set * DescrWrt; - RCODE rc = FERR_OK; - - if( m_iSocket != INVALID_SOCKET) - { - FD_ZERO( &GenDescriptors ); - FD_SET( m_iSocket, &GenDescriptors ); - - iMaxDescs = (int)(m_iSocket + 1); - DescrRead = bPeekRead ? &GenDescriptors : NULL; - DescrWrt = bPeekRead ? NULL : &GenDescriptors; - - TimeOut.tv_sec = (long)iTimeoutVal; - TimeOut.tv_usec = (long)0; - - if( select( iMaxDescs, DescrRead, DescrWrt, NULL, &TimeOut) < 0 ) - { - rc = RC_SET( FERR_SVR_SELECT_ERR); - goto Exit; - } - else - { - if( !FD_ISSET( m_iSocket, &GenDescriptors)) - { - rc = bPeekRead - ? RC_SET( FERR_SVR_READ_TIMEOUT) - : RC_SET( FERR_SVR_WRT_TIMEOUT); - } - } - } - else - { - rc = RC_SET( FERR_SVR_CONNECT_FAIL); - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Writes data to the connection. -*********************************************************************/ -RCODE FCS_TCP::write( - FLMBYTE * pucDataBuffer, - FLMUINT uiDataCnt, - FLMUINT * puiWrtCnt) -{ - FLMUINT uiPartialCnt; - FLMUINT uiToWrite; - FLMUINT uiHaveWritten = 0; - RCODE rc = FERR_OK; - - if( m_iSocket == INVALID_SOCKET) - { - rc = RC_SET( FERR_SVR_CONNECT_FAIL); - } - - uiToWrite = uiDataCnt; - *puiWrtCnt = 0; - while( uiToWrite > 0) - { - /* The internal write call checks the arguments. */ - - if( RC_BAD( rc = _write( pucDataBuffer, - uiToWrite, &uiPartialCnt))) - { - goto Exit; - } - - pucDataBuffer += uiPartialCnt; - uiHaveWritten += uiPartialCnt; - uiToWrite = (FLMUINT)(uiDataCnt - uiHaveWritten); - *puiWrtCnt = uiHaveWritten; - } - -Exit: - - return( rc); -} - - -RCODE FCS_TCP::_write( - FLMBYTE * pucBuffer, - FLMUINT uiDataCnt, - FLMUINT *puiWrtCnt) -{ - FLMINT iRetryCount = 0; - FLMINT iWrtCnt = 0; - RCODE rc = FERR_OK; - - flmAssert( m_iSocket != INVALID_SOCKET && pucBuffer && uiDataCnt); - -Retry: - - *puiWrtCnt = 0; - if ( RC_OK( rc = _SocketPeek( m_uiIOTimeout, FALSE))) - { - iWrtCnt = send( m_iSocket, (char *)pucBuffer, (int)uiDataCnt, 0 ); - switch ( iWrtCnt ) - { - case -1: - *puiWrtCnt = 0; - rc = RC_SET( FERR_SVR_WRT_FAIL); - break; - - case 0: - rc = RC_SET( FERR_SVR_DISCONNECT); - break; - - default: - *puiWrtCnt = (FLMUINT)iWrtCnt; - break; - } - } - - if( RC_BAD( rc) && rc != FERR_SVR_WRT_TIMEOUT) - { -#ifndef FLM_UNIX - FLMINT iSockErr = WSAGetLastError(); -#else - FLMINT iSockErr = errno; -#endif - -#if defined( FLM_WIN) || defined( FLM_NLM) - if( iSockErr == WSAECONNABORTED) -#else - if( iSockErr == ECONNABORTED) -#endif - { - rc = RC_SET( FERR_SVR_DISCONNECT); - } -#if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEWOULDBLOCK && iRetryCount < 5) -#else - else if( iSockErr == EWOULDBLOCK && iRetryCount < 5) -#endif - { - iRetryCount++; - f_sleep( (FLMUINT)(100 * iRetryCount)); - goto Retry; - } - } - - return( rc); -} - -/******************************************************************** -Desc: Reads data from the connection -*********************************************************************/ -RCODE FCS_TCP::read( - FLMBYTE * pucBuffer, - FLMUINT uiDataCnt, - FLMUINT * puiReadCnt) -{ - FLMINT iReadCnt = 0; - RCODE rc = FERR_OK; - - flmAssert( m_bConnected && pucBuffer && uiDataCnt); - - if( RC_OK( rc = _SocketPeek( m_uiIOTimeout, TRUE))) - { - iReadCnt = (FLMINT)recv( m_iSocket, - (char *)pucBuffer, (int)uiDataCnt, 0); - switch ( iReadCnt) - { - case -1: - iReadCnt = 0; -#if defined( FLM_WIN) || defined( FLM_NLM) - if ( WSAGetLastError() == WSAECONNRESET) -#else - if( errno == ECONNRESET) -#endif - { - rc = RC_SET( FERR_SVR_DISCONNECT); - } - else - { - rc = RC_SET( FERR_SVR_READ_FAIL); - } - break; - - case 0: - rc = RC_SET( FERR_SVR_DISCONNECT); - break; - - default: - break; - } - } - - if( puiReadCnt) - { - *puiReadCnt = (FLMUINT)iReadCnt; - } - - return( rc); -} - -/******************************************************************** -Desc: Reads data from the connection - Timeout valkue is zero, no error - is generated if timeout occurs. -*********************************************************************/ -RCODE FCS_TCP::readNoWait( - FLMBYTE * pucBuffer, - FLMUINT uiDataCnt, - FLMUINT * puiReadCnt) -{ - FLMINT iReadCnt = 0; - RCODE rc = FERR_OK; - - flmAssert( m_bConnected && pucBuffer && uiDataCnt); - - if( puiReadCnt) - { - *puiReadCnt = 0; - } - - if( RC_OK( rc = _SocketPeek( (FLMUINT)0, TRUE))) - { - iReadCnt = recv( m_iSocket, (char *)pucBuffer, (int)uiDataCnt, 0); - switch ( iReadCnt) - { - case -1: - *puiReadCnt = 0; -#if defined( FLM_WIN) || defined( FLM_NLM) - if ( WSAGetLastError() == WSAECONNRESET) -#else - if( errno == ECONNRESET) -#endif - { - rc = RC_SET( FERR_SVR_DISCONNECT); - } - else - { - rc = RC_SET( FERR_SVR_READ_FAIL); - } - goto Exit; - - case 0: - rc = RC_SET( FERR_SVR_DISCONNECT); - goto Exit; - - default: - break; - } - } - else if (rc == FERR_SVR_READ_TIMEOUT) - { - rc = FERR_OK; - } - - if( puiReadCnt) - { - *puiReadCnt = (FLMUINT)iReadCnt; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Reads data and does not return until all requested data has - been read or a timeout error has been encountered. -*********************************************************************/ -RCODE FCS_TCP::readAll( - FLMBYTE * pucBuffer, - FLMUINT uiDataCnt, - FLMUINT * puiReadCnt) -{ - FLMUINT uiToRead = 0; - FLMUINT uiHaveRead = 0; - FLMUINT uiPartialCnt; - RCODE rc = FERR_OK; - - flmAssert( m_bConnected && pucBuffer && uiDataCnt); - - uiToRead = uiDataCnt; - while( uiToRead) - { - if( RC_BAD( rc = read( pucBuffer, uiToRead, &uiPartialCnt))) - { - goto Exit; - } - - pucBuffer += uiPartialCnt; - uiHaveRead += uiPartialCnt; - uiToRead = (FLMUINT)(uiDataCnt - uiHaveRead); - - if( puiReadCnt) - { - *puiReadCnt = uiHaveRead; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Enables or disables Nagle's algorithm -*********************************************************************/ -RCODE FCS_TCP::setTcpDelay( - FLMBOOL bOn) -{ - RCODE rc = FERR_OK; - - int iOn; - - if( m_iSocket != INVALID_SOCKET) - { - iOn = bOn ? 1 : 0; - - if( (setsockopt( m_iSocket, IPPROTO_TCP, TCP_NODELAY, (char *)&iOn, - (unsigned)sizeof( iOn) )) < 0) - { - rc = RC_SET( FERR_SVR_SOCKOPT_FAIL); - goto Exit; - } - } - else - { - rc = RC_SET( FERR_SVR_ALREADY_CLOSED); - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Closes any open connections -*********************************************************************/ -void FCS_TCP::close( - FLMBOOL bForce) -{ - if( m_iSocket == INVALID_SOCKET) - { - goto Exit; - } - -#ifdef FLM_NLM - F_UNREFERENCED_PARM( bForce); -#else - if( !bForce) - { - char ucTmpBuf[ 128]; - struct timeval tv; - fd_set fds; - fd_set fds_read; - fd_set fds_err; - - // Close our half of the connection - - shutdown( m_iSocket, 1); - - // Set up to wait for readable data on the socket - - FD_ZERO( &fds); - FD_SET( m_iSocket, &fds); - - tv.tv_sec = 10; - tv.tv_usec = 0; - - fds_read = fds; - fds_err = fds; - - // Wait for data or an error - - while( select( m_iSocket + 1, &fds_read, NULL, &fds_err, &tv) > 0) - { - if( recv( m_iSocket, ucTmpBuf, sizeof( ucTmpBuf), 0) <= 0) - { - break; - } - fds_read = fds; - fds_err = fds; - } - - shutdown( m_iSocket, 2); - } -#endif - -#ifndef FLM_UNIX - closesocket( m_iSocket); -#else - ::close( m_iSocket); -#endif - -Exit: - - m_iSocket = INVALID_SOCKET; - m_bConnected = FALSE; -} - -/******************************************************************** -Desc: Creates a client object -*********************************************************************/ -FCS_TCP_CLIENT::FCS_TCP_CLIENT( void) : FCS_TCP() -{ - m_bConnected = FALSE; -} - -/******************************************************************** -Desc: Closes any connections and frees client resources -*********************************************************************/ -FCS_TCP_CLIENT::~FCS_TCP_CLIENT( void ) -{ - (void)close(); -} - -/******************************************************************** -Desc: Opens a new connection -*********************************************************************/ -RCODE FCS_TCP_CLIENT::openConnection( - const char * pucHostName, - FLMUINT uiPort, - FLMUINT uiConnectTimeout, - FLMUINT uiDataTimeout) -{ - FLMINT iSockErr; - FLMINT iTries; - FLMINT iMaxTries = 5; - struct sockaddr_in address; - struct hostent * pHostEntry; - unsigned long ulIPAddr; - RCODE rc = FERR_OK; - - flmAssert( !m_bConnected); - m_iSocket = INVALID_SOCKET; - - if( pucHostName && pucHostName[ 0] != '\0') - { - ulIPAddr = inet_addr( (char *)pucHostName); - if( ulIPAddr == (unsigned long)INADDR_NONE) - { - pHostEntry = gethostbyname( (char *)pucHostName); - - if( !pHostEntry) - { - rc = RC_SET( FERR_SVR_NOIP_ADDR); - goto Exit; - } - else - { - ulIPAddr = *((unsigned long *)pHostEntry->h_addr); - } - - } - } - else - { - ulIPAddr = inet_addr( (char *)"127.0.0.1"); - } - - /******************************************************/ - /* Fill in the Socket structure with family type */ - /******************************************************/ - - f_memset( (char*)&address, 0, sizeof( struct sockaddr_in)); - address.sin_family = AF_INET; - address.sin_addr.s_addr = (unsigned)ulIPAddr; - address.sin_port = htons( (unsigned short)uiPort); - - /* - Allocate a socket, then attempt to connect to it! - */ - - if( (m_iSocket = socket( AF_INET, - SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) - { - rc = RC_SET( FERR_SVR_SOCK_FAIL); - goto Exit; - } - - /******************************************************/ - /* Now attempt to connect with the specified */ - /* partner host, time-out if connection */ - /* doesn't complete within alloted time */ - /******************************************************/ -#ifdef FLM_WIN - /* - ** - */ - if ( uiConnectTimeout ) - { - if ( uiConnectTimeout < 5 ) - { - iMaxTries = (iMaxTries * uiConnectTimeout) / 5; - uiConnectTimeout = 5; - } - } - else - { - iMaxTries = 1; - } -#endif - - for( iTries = 0; iTries < iMaxTries; iTries++ ) - { - iSockErr = 0; - if( connect( m_iSocket, (struct sockaddr *)(void *)&address, - (unsigned)sizeof(struct sockaddr)) >= 0) - { - /* SUCCESS! */ - break; - } - - #ifndef FLM_UNIX - iSockErr = WSAGetLastError(); - #else - iSockErr = errno; - #endif - -#ifdef FLM_WIN - /* - In WIN, we sometimes get WSAEINVAL when, if we keep - trying, we will eventually connect. Therefore, - here we'll treat WSAEINVAL as EINPROGRESS. - */ - - if( iSockErr == WSAEINVAL) - { -#ifndef FLM_UNIX - closesocket( m_iSocket); -#else - ::close( m_iSocket); -#endif - if( (m_iSocket = socket( AF_INET, - SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) - { - rc = RC_SET( FERR_SVR_SOCK_FAIL); - goto Exit; - } -#if defined( FLM_WIN) || defined( FLM_NLM) - iSockErr = WSAEINPROGRESS; -#else - iSockErr = EINPROGRESS; -#endif - continue; - } -#endif - -#if defined( FLM_WIN) || defined( FLM_NLM) - if( iSockErr == WSAEISCONN ) -#else - if( iSockErr == EISCONN ) -#endif - { - break; - } -#if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEWOULDBLOCK) -#else - else if( iSockErr == EWOULDBLOCK) -#endif - { - /* - ** Let's wait a split second to give the connection - ** request a chance. - */ - - f_sleep( 100 ); - continue; - } -#if defined( FLM_WIN) || defined( FLM_NLM) - else if( iSockErr == WSAEINPROGRESS) -#else - else if( iSockErr == EINPROGRESS) -#endif - { - if( RC_OK( rc = _SocketPeek( uiConnectTimeout, FALSE))) - { - /* - ** Let's wait a split second to give the connection - ** request a chance. - */ - - f_sleep( 100 ); - continue; - } - } - rc = RC_SET( FERR_SVR_CONNECT_FAIL); - } - - if( RC_BAD( rc)) - { - if( m_iSocket != INVALID_SOCKET) - { -#ifndef FLM_UNIX - closesocket( m_iSocket); -#else - ::close( m_iSocket); -#endif - m_iSocket = INVALID_SOCKET; - } - goto Exit; - } - - m_uiIOTimeout = uiDataTimeout; - - setTcpDelay( TRUE); - m_bConnected = TRUE; - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Constructor -*********************************************************************/ -FCS_TCP_SERVER::FCS_TCP_SERVER( void) : FCS_TCP() -{ - m_bBound = FALSE; -} - -/******************************************************************** -Desc: Destructor -*********************************************************************/ -FCS_TCP_SERVER::~FCS_TCP_SERVER( void) -{ - if( m_bBound) - { - close( TRUE); - } -} - -/******************************************************************** -Desc: Bind to a port prior to listening for connections -*********************************************************************/ -RCODE FCS_TCP_SERVER::bind( - FLMUINT uiBindPort, - FLMBYTE * pucBindAddr) -{ - struct sockaddr_in address; - RCODE rc = FERR_OK; - - if( m_bBound) - { - rc = RC_SET( FERR_SVR_SOCK_FAIL); - goto Exit; - } - - if( (m_iSocket = socket( AF_INET, - SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET) - { - rc = RC_SET( FERR_SVR_SOCK_FAIL); - goto Exit; - } - - f_memset( &address, 0, sizeof( address)); - address.sin_family = AF_INET; - if( !pucBindAddr) - { - address.sin_addr.s_addr = htonl( INADDR_ANY); - } - else - { - address.sin_addr.s_addr = inet_addr( (char *)pucBindAddr); - } - address.sin_port = htons( (unsigned short)uiBindPort); - - // Bind to the address+port - - if( ::bind( m_iSocket, (struct sockaddr *)(void *)&address, - (unsigned)sizeof( address)) != 0) - { - rc = RC_SET( FERR_SVR_BIND_FAIL); - goto Exit; - } - - /* - ** Bind succeeded, - ** listen() prepares a socket to accept a connection and specifies a - ** queue limit for incoming connections. The accept() accepts the connection. - ** Listen returns immediatly. - - ** Duane: Note for NetWare I spoke with Sravan Vadlakonda in San Jose, - ** Netware allows 32 not 5 as the max. We set this high because the - ** nonpreemptive nature of NLMs means we might not get back to this - ** thread in time to accept all of the pending connections. As of - ** Aug 97 the tcpip.nlm displays an error when we don't clean the q - ** of pending connections fast enough. - */ - -#ifdef FLM_NLM - if( listen( m_iSocket, 32 ) < 0) -#endif - { - if( listen( m_iSocket, 5 ) < 0) - { - rc = RC_SET( FERR_SVR_LISTEN_FAIL); - goto Exit; - } - } - - /* - Disable the packet send delay. - */ - - setTcpDelay( TRUE); - m_bBound = TRUE; - -Exit: - - if( RC_BAD( rc) && m_iSocket != INVALID_SOCKET) - { -#ifndef FLM_UNIX - closesocket( m_iSocket); -#else - ::close( m_iSocket); -#endif - m_iSocket = INVALID_SOCKET; - } - - return( rc); -} - -/******************************************************************** -Desc: Wait for and accept a client connection -*********************************************************************/ -RCODE FCS_TCP_SERVER::connectClient( - FCS_TCP * pClient, - FLMINT uiConnectTimeout, - FLMINT uiDataTimeout) -{ - SOCKET iSocket; -#if defined( FLM_UNIX) - socklen_t iAddrLen; -#else - int iAddrLen; -#endif - struct sockaddr_in address; - RCODE rc = FERR_OK; - - if( !m_bBound) - { - rc = RC_SET( FERR_SVR_BIND_FAIL); - goto Exit; - } - - if( RC_BAD( rc = _SocketPeek( uiConnectTimeout, TRUE))) - { - goto Exit; - } - - iAddrLen = (int)sizeof( struct sockaddr); - if( (iSocket = accept( m_iSocket, - (struct sockaddr *)(void *)&address, &iAddrLen)) == INVALID_SOCKET) - { - rc = RC_SET( FERR_SVR_ACCEPT_FAIL); - goto Exit; - } - - pClient->m_ulRemoteAddr = address.sin_addr.s_addr; - pClient->m_iSocket = iSocket; - pClient->m_bConnected = TRUE; - pClient->m_uiIOTimeout = uiDataTimeout; - pClient->setTcpDelay( TRUE); - -Exit: - - return( rc); -} diff --git a/flaim/src/fcs_util.cpp b/flaim/src/fcs_util.cpp deleted file mode 100644 index 5230b71..0000000 --- a/flaim/src/fcs_util.cpp +++ /dev/null @@ -1,2458 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Server utility routines. -// Tabs: 3 -// -// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_util.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC FLMBOOL flmGetNextHexPacketSlot( - FLMBYTE * pucUsedMap, - FLMUINT uiMapSize, - f_randomGenerator * pRandGen, - FLMUINT * puiSlot); - -FSTATIC RCODE flmGetNextHexPacketBytes( - FLMBYTE * pucUsedMap, - FLMUINT uiMapSize, - FLMBYTE * pucPacket, - f_randomGenerator * pRandGen, - FLMBYTE * pucBuf, - FLMUINT uiCount); - -/**************************************************************************** -Desc: Converts a UNICODE string consisting of 7-bit ASCII characters to - a native string. -*****************************************************************************/ -RCODE fcsConvertUnicodeToNative( - POOL * pPool, - const FLMUNICODE * puzUnicode, - char ** ppucNative) -{ - RCODE rc = FERR_OK; - char * pucDest = NULL; - FLMUINT uiCount; - - uiCount = 0; - while( puzUnicode[ uiCount]) - { - if( puzUnicode[ uiCount] > 0x007F) - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - uiCount++; - } - - if( (pucDest = (char *)GedPoolAlloc( pPool, - (FLMUINT)(uiCount + 1))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - uiCount = 0; - while( puzUnicode[ uiCount]) - { - pucDest[ uiCount] = f_tonative( (FLMBYTE)puzUnicode[ uiCount]); - uiCount++; - } - - pucDest[ uiCount] = '\0'; - -Exit: - - *ppucNative = pucDest; - return( rc); -} - - -/**************************************************************************** -Desc: Converts a native string to a double-byte UNICODE string. -*****************************************************************************/ -RCODE fcsConvertNativeToUnicode( - POOL * pPool, - const char * pszNative, - FLMUNICODE ** ppuzUnicode) -{ - RCODE rc = FERR_OK; - FLMUNICODE * puzDest; - FLMUINT uiCount; - - uiCount = f_strlen( pszNative); - - if( (puzDest = (FLMUNICODE *)GedPoolAlloc( pPool, - (FLMUINT)((FLMUINT)sizeof( FLMUNICODE) * - (FLMUINT)(uiCount + 1)))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - uiCount = 0; - while( pszNative[ uiCount]) - { - puzDest[ uiCount] = (FLMUNICODE)f_toascii( pszNative[ uiCount]); - uiCount++; - } - - puzDest[ uiCount] = 0; - -Exit: - - *ppuzUnicode = puzDest; - return( rc); -} - - -/**************************************************************************** -Desc: Initializes members of a CREATE_OPTS structure to their default values -*****************************************************************************/ -void fcsInitCreateOpts( - CREATE_OPTS * pCreateOptsRV) -{ - /* - Initialize the CREATE_OPTS structure to its default values. - */ - - f_memset( pCreateOptsRV, 0, sizeof( CREATE_OPTS)); - - pCreateOptsRV->uiBlockSize = DEFAULT_BLKSIZ; - pCreateOptsRV->uiMinRflFileSize = DEFAULT_MIN_RFL_FILE_SIZE; - pCreateOptsRV->uiMaxRflFileSize = DEFAULT_MAX_RFL_FILE_SIZE; - pCreateOptsRV->bKeepRflFiles = DEFAULT_KEEP_RFL_FILES_FLAG; - pCreateOptsRV->bLogAbortedTransToRfl = DEFAULT_LOG_ABORTED_TRANS_FLAG; - pCreateOptsRV->uiDefaultLanguage = DEFAULT_LANG; - pCreateOptsRV->uiVersionNum = FLM_CURRENT_VERSION_NUM; -} - -/**************************************************************************** -Desc: Converts a CHECKPOINT_INFO structure to an HTD tree -*****************************************************************************/ -RCODE fcsBuildCheckpointInfo( - CHECKPOINT_INFO * pChkptInfo, - POOL * pPool, - NODE ** ppTree) -{ - NODE * pRootNd = NULL; - void * pMark = GedPoolMark( pPool); - FLMUINT uiTmp; - RCODE rc = FERR_OK; - - *ppTree = NULL; - - /* - Build the root node of the tree. - */ - - if( (pRootNd = GedNodeMake( pPool, FCS_CPI_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - /* - Add fields to the tree. - */ - - if( pChkptInfo->bRunning) - { - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_RUNNING, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiRunningTime) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_START_TIME, (void *)&pChkptInfo->uiRunningTime, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->bForcingCheckpoint) - { - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_FORCING_CP, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiForceCheckpointRunningTime) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_FORCE_CP_START_TIME, - (void *)&pChkptInfo->uiForceCheckpointRunningTime, - 4, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->iForceCheckpointReason) - { - uiTmp = pChkptInfo->iForceCheckpointReason; - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_FORCE_CP_REASON, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->bWritingDataBlocks) - { - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_WRITING_DATA_BLOCKS, (void *)&uiTmp, - 4, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiLogBlocksWritten) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_LOG_BLOCKS_WRITTEN, - (void *)&pChkptInfo->uiLogBlocksWritten, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiDataBlocksWritten) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_DATA_BLOCKS_WRITTEN, - (void *)&pChkptInfo->uiDataBlocksWritten, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiDirtyCacheBytes) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_DIRTY_CACHE_BYTES, - (void *)&pChkptInfo->uiDirtyCacheBytes, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiBlockSize) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_BLOCK_SIZE, (void *)&pChkptInfo->uiBlockSize, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pChkptInfo->uiWaitTruncateTime) - { - if( RC_BAD( rc = gedAddField( pPool, pRootNd, - FCS_CPI_WAIT_TRUNC_TIME, (void *)&pChkptInfo->uiWaitTruncateTime, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - *ppTree = pRootNd; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Converts a LOCK_USER structure (or list of structures) to an HTD tree -*****************************************************************************/ -RCODE fcsBuildLockUser( - LOCK_USER * pLockUser, - FLMBOOL bList, - POOL * pPool, - NODE ** ppTree) -{ - NODE * pRootNd = NULL; - NODE * pContextNd = NULL; - void * pMark = GedPoolMark( pPool); - RCODE rc = FERR_OK; - - *ppTree = NULL; - - if( !pLockUser) - { - goto Exit; - } - - /* - Add fields to the tree. - */ - - for( ;;) - { - if( (pContextNd = GedNodeMake( pPool, FCS_LUSR_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_LUSR_THREAD_ID, (void *)&pLockUser->uiThreadId, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_LUSR_TIME, (void *)&pLockUser->uiTime, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( pRootNd == NULL) - { - pRootNd = pContextNd; - } - else - { - GedSibGraft( pRootNd, pContextNd, GED_LAST); - } - - if( !bList) - { - break; - } - - pLockUser++; - if( !pLockUser->uiTime) - { - // Hit the last item in the list - break; - } - } - - *ppTree = pRootNd; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Converts an HTD tree to a LOCK_USER structure (or list of structures) -*****************************************************************************/ -RCODE fcsExtractLockUser( - NODE * pTree, - FLMBOOL bExtractAsList, - void * pvLockUser) -{ - NODE * pTmpNd; - FLMUINT uiItemCount = 0; - FLMUINT fieldPath[ 8]; - LOCK_USER * pLockUser = NULL; - FLMUINT uiLoop; - RCODE rc = FERR_OK; - - if( !pTree) - { - if( bExtractAsList) - { - *((LOCK_USER **)pvLockUser) = NULL; - } - else - { - f_memset( (LOCK_USER *)pvLockUser, 0, sizeof( LOCK_USER)); - } - goto Exit; - } - - if( bExtractAsList) - { - pTmpNd = pTree; - while( pTmpNd != NULL) - { - if( GedTagNum( pTmpNd) == FCS_LUSR_CONTEXT) - { - uiItemCount++; - } - pTmpNd = pTmpNd->next; - } - - if( RC_BAD( rc = f_alloc( - sizeof( LOCK_USER) * (uiItemCount + 1), &pLockUser))) - { - goto Exit; - } - - *((LOCK_USER **)pvLockUser) = pLockUser; - } - else - { - pLockUser = (LOCK_USER *)pvLockUser; - f_memset( pLockUser, 0, sizeof( LOCK_USER)); - uiItemCount = 1; - } - - /* - Parse the tree and extract the values. - */ - - for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++) - { - fieldPath[ 0] = FCS_LUSR_CONTEXT; - fieldPath[ 1] = FCS_LUSR_THREAD_ID; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiThreadId); - } - - fieldPath[ 0] = FCS_LUSR_CONTEXT; - fieldPath[ 1] = FCS_LUSR_TIME; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pLockUser[ uiLoop].uiTime); - } - - pTree = GedSibNext( pTree); - } - - if( bExtractAsList) - { - f_memset( &(pLockUser[ uiItemCount]), 0, sizeof( LOCK_USER)); - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Extracts a CHECKPOINT_INFO structure from an HTD tree. -*****************************************************************************/ -RCODE fcsExtractCheckpointInfo( - NODE * pTree, - CHECKPOINT_INFO * pChkptInfo) -{ - NODE * pTmpNd; - FLMUINT fieldPath[ 8]; - FLMUINT uiTmp; - RCODE rc = FERR_OK; - - /* - Initialize the structure - */ - - f_memset( pChkptInfo, 0, sizeof( CHECKPOINT_INFO)); - - /* - Parse the tree and extract the values. - */ - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_RUNNING; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - pChkptInfo->bRunning = uiTmp ? TRUE : FALSE; - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_START_TIME; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiRunningTime); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_FORCING_CP; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - pChkptInfo->bForcingCheckpoint = uiTmp ? TRUE : FALSE; - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_FORCE_CP_START_TIME; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiForceCheckpointRunningTime); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_FORCE_CP_REASON; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetINT( pTmpNd, &pChkptInfo->iForceCheckpointReason); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_WRITING_DATA_BLOCKS; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - pChkptInfo->bWritingDataBlocks = uiTmp ? TRUE : FALSE; - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_LOG_BLOCKS_WRITTEN; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiLogBlocksWritten); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_DATA_BLOCKS_WRITTEN; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiDataBlocksWritten); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_DIRTY_CACHE_BYTES; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiDirtyCacheBytes); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_BLOCK_SIZE; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiBlockSize); - } - - fieldPath[ 0] = FCS_CPI_CONTEXT; - fieldPath[ 1] = FCS_CPI_WAIT_TRUNC_TIME; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pChkptInfo->uiWaitTruncateTime); - } - - return( rc); -} - -/**************************************************************************** -Desc: Translates a FLAIM query operator to a c/s query operator -*****************************************************************************/ -RCODE fcsTranslateQFlmToQCSOp( - QTYPES eFlmOp, - FLMUINT * puiCSOp) -{ - RCODE rc = FERR_OK; - - switch( eFlmOp) - { - case FLM_AND_OP: - *puiCSOp = FCS_ITERATOR_AND_OP; - break; - case FLM_OR_OP: - *puiCSOp = FCS_ITERATOR_OR_OP; - break; - case FLM_NOT_OP: - *puiCSOp = FCS_ITERATOR_NOT_OP; - break; - case FLM_EQ_OP: - *puiCSOp = FCS_ITERATOR_EQ_OP; - break; - case FLM_MATCH_OP: - *puiCSOp = FCS_ITERATOR_MATCH_OP; - break; - case FLM_MATCH_BEGIN_OP: - *puiCSOp = FCS_ITERATOR_MATCH_BEGIN_OP; - break; - case FLM_CONTAINS_OP: - *puiCSOp = FCS_ITERATOR_CONTAINS_OP; - break; - case FLM_NE_OP: - *puiCSOp = FCS_ITERATOR_NE_OP; - break; - case FLM_LT_OP: - *puiCSOp = FCS_ITERATOR_LT_OP; - break; - case FLM_LE_OP: - *puiCSOp = FCS_ITERATOR_LE_OP; - break; - case FLM_GT_OP: - *puiCSOp = FCS_ITERATOR_GT_OP; - break; - case FLM_GE_OP: - *puiCSOp = FCS_ITERATOR_GE_OP; - break; - case FLM_BITAND_OP: - *puiCSOp = FCS_ITERATOR_BITAND_OP; - break; - case FLM_BITOR_OP: - *puiCSOp = FCS_ITERATOR_BITOR_OP; - break; - case FLM_BITXOR_OP: - *puiCSOp = FCS_ITERATOR_BITXOR_OP; - break; - case FLM_MULT_OP: - *puiCSOp = FCS_ITERATOR_MULT_OP; - break; - case FLM_DIV_OP: - *puiCSOp = FCS_ITERATOR_DIV_OP; - break; - case FLM_MOD_OP: - *puiCSOp = FCS_ITERATOR_MOD_OP; - break; - case FLM_PLUS_OP: - *puiCSOp = FCS_ITERATOR_PLUS_OP; - break; - case FLM_MINUS_OP: - *puiCSOp = FCS_ITERATOR_MINUS_OP; - break; - case FLM_NEG_OP: - *puiCSOp = FCS_ITERATOR_NEG_OP; - break; - case FLM_LPAREN_OP: - *puiCSOp = FCS_ITERATOR_LPAREN_OP; - break; - case FLM_RPAREN_OP: - *puiCSOp = FCS_ITERATOR_RPAREN_OP; - break; - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - break; - } - - return( rc); -} - -/**************************************************************************** -Desc: Translates a FLAIM query operator to a c/s query operator -*****************************************************************************/ -RCODE fcsTranslateQCSToQFlmOp( - FLMUINT uiCSOp, - QTYPES * peFlmOp) -{ - RCODE rc = FERR_OK; - - switch( uiCSOp) - { - case FCS_ITERATOR_AND_OP: - *peFlmOp = FLM_AND_OP; - break; - case FCS_ITERATOR_OR_OP: - *peFlmOp = FLM_OR_OP; - break; - case FCS_ITERATOR_NOT_OP: - *peFlmOp = FLM_NOT_OP; - break; - case FCS_ITERATOR_EQ_OP: - *peFlmOp = FLM_EQ_OP; - break; - case FCS_ITERATOR_MATCH_OP: - *peFlmOp = FLM_MATCH_OP; - break; - case FCS_ITERATOR_MATCH_BEGIN_OP: - *peFlmOp = FLM_MATCH_BEGIN_OP; - break; - case FCS_ITERATOR_CONTAINS_OP: - *peFlmOp = FLM_CONTAINS_OP; - break; - case FCS_ITERATOR_NE_OP: - *peFlmOp = FLM_NE_OP; - break; - case FCS_ITERATOR_LT_OP: - *peFlmOp = FLM_LT_OP; - break; - case FCS_ITERATOR_LE_OP: - *peFlmOp = FLM_LE_OP; - break; - case FCS_ITERATOR_GT_OP: - *peFlmOp = FLM_GT_OP; - break; - case FCS_ITERATOR_GE_OP: - *peFlmOp = FLM_GE_OP; - break; - case FCS_ITERATOR_BITAND_OP: - *peFlmOp = FLM_BITAND_OP; - break; - case FCS_ITERATOR_BITOR_OP: - *peFlmOp = FLM_BITOR_OP; - break; - case FCS_ITERATOR_BITXOR_OP: - *peFlmOp = FLM_BITXOR_OP; - break; - case FCS_ITERATOR_MULT_OP: - *peFlmOp = FLM_MULT_OP; - break; - case FCS_ITERATOR_DIV_OP: - *peFlmOp = FLM_DIV_OP; - break; - case FCS_ITERATOR_MOD_OP: - *peFlmOp = FLM_MOD_OP; - break; - case FCS_ITERATOR_PLUS_OP: - *peFlmOp = FLM_PLUS_OP; - break; - case FCS_ITERATOR_MINUS_OP: - *peFlmOp = FLM_MINUS_OP; - break; - case FCS_ITERATOR_NEG_OP: - *peFlmOp = FLM_NEG_OP; - break; - case FCS_ITERATOR_LPAREN_OP: - *peFlmOp = FLM_LPAREN_OP; - break; - case FCS_ITERATOR_RPAREN_OP: - *peFlmOp = FLM_RPAREN_OP; - break; - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - break; - } - - return( rc); -} - -/**************************************************************************** -Desc: Converts an FINDEX_STATUS structure to an HTD tree -*****************************************************************************/ -RCODE fcsBuildIndexStatus( - FINDEX_STATUS * pIndexStatus, - POOL * pPool, - NODE ** ppTree) -{ - NODE * pContextNd = NULL; - void * pMark = GedPoolMark( pPool); - FLMUINT uiTmp; - RCODE rc = FERR_OK; - - *ppTree = NULL; - - if( !pIndexStatus) - { - goto Exit; - } - - /* - Add fields to the tree. - */ - - if( (pContextNd = GedNodeMake( pPool, FCS_IXSTAT_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - if( pIndexStatus->uiIndexNum) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_INDEX_NUM, (void *)&pIndexStatus->uiIndexNum, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pIndexStatus->uiStartTime) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_START_TIME, (void *)&pIndexStatus->uiStartTime, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - // Send the "auto-online" flag for backwards compatibility - - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_AUTO_ONLINE, - (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - // Send the priority (high) for backwards compatibility - - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_PRIORITY, - (void *)&uiTmp, 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - // Set the suspended time field (for backwards compatibility) - // if the index is suspended - - if( pIndexStatus->bSuspended) - { - f_timeGetSeconds( &uiTmp); - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_SUSPEND_TIME, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pIndexStatus->uiLastRecordIdIndexed) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_LAST_REC_INDEXED, - (void *)&pIndexStatus->uiLastRecordIdIndexed, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pIndexStatus->uiKeysProcessed) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_KEYS_PROCESSED, - (void *)&pIndexStatus->uiKeysProcessed, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pIndexStatus->uiRecordsProcessed) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_RECS_PROCESSED, - (void *)&pIndexStatus->uiRecordsProcessed, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pIndexStatus->bSuspended) - { - uiTmp = (FLMUINT)pIndexStatus->bSuspended; - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_IXSTAT_STATE, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - *ppTree = pContextNd; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - -/**************************************************************************** -Desc: Extracts an FINDEX_STATUS structure from an HTD tree. -*****************************************************************************/ -RCODE fcsExtractIndexStatus( - NODE * pTree, - FINDEX_STATUS * pIndexStatus) -{ - NODE * pTmpNd; - FLMUINT fieldPath[ 8]; - RCODE rc = FERR_OK; - - /* - Initialize the structure - */ - - f_memset( pIndexStatus, 0, sizeof( FINDEX_STATUS)); - - /* - Make sure pTree is non-null - */ - - if( !pTree) - { - goto Exit; - } - - /* - Parse the tree and extract the values. - */ - - fieldPath[ 0] = FCS_IXSTAT_CONTEXT; - fieldPath[ 1] = FCS_IXSTAT_INDEX_NUM; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pIndexStatus->uiIndexNum); - } - - fieldPath[ 1] = FCS_IXSTAT_START_TIME; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pIndexStatus->uiStartTime); - } - - fieldPath[ 1] = FCS_IXSTAT_LAST_REC_INDEXED; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pIndexStatus->uiLastRecordIdIndexed); - } - - fieldPath[ 1] = FCS_IXSTAT_KEYS_PROCESSED; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pIndexStatus->uiKeysProcessed); - } - - fieldPath[ 1] = FCS_IXSTAT_RECS_PROCESSED; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pIndexStatus->uiRecordsProcessed); - } - - fieldPath[ 1] = FCS_IXSTAT_STATE; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - FLMUINT uiTmp; - (void)GedGetUINT( pTmpNd, &uiTmp); - pIndexStatus->bSuspended = uiTmp ? TRUE : FALSE; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Converts an FLM_MEM_INFO structure to an HTD tree -*****************************************************************************/ -RCODE fcsBuildMemInfo( - FLM_MEM_INFO * pMemInfo, - POOL * pPool, - NODE ** ppTree) -{ - FLMUINT uiTmp; - NODE * pContextNd = NULL; - NODE * pSubContext = NULL; - void * pMark = GedPoolMark( pPool); - FLM_CACHE_USAGE * pUsage; - RCODE rc = FERR_OK; - - *ppTree = NULL; - - if( !pMemInfo) - { - goto Exit; - } - - /* - Add fields to the tree. - */ - - if( (pContextNd = GedNodeMake( pPool, - FCS_MEMINFO_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - if( pMemInfo->bDynamicCacheAdjust) - { - uiTmp = 1; - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_MEMINFO_DYNA_CACHE_ADJ, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pMemInfo->uiCacheAdjustPercent) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_MEMINFO_CACHE_ADJ_PERCENT, - (void *)&pMemInfo->uiCacheAdjustPercent, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pMemInfo->uiCacheAdjustMin) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_MEMINFO_CACHE_ADJ_MIN, - (void *)&pMemInfo->uiCacheAdjustMin, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pMemInfo->uiCacheAdjustMax) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_MEMINFO_CACHE_ADJ_MAX, - (void *)&pMemInfo->uiCacheAdjustMax, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pMemInfo->uiCacheAdjustMinToLeave) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE, - (void *)&pMemInfo->uiCacheAdjustMinToLeave, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - pUsage = &pMemInfo->RecordCache; - if( (pSubContext = GedNodeMake( pPool, - FCS_MEMINFO_RECORD_CACHE, &rc)) == NULL) - { - goto Exit; - } - -add_usage: - - if( pUsage->uiMaxBytes) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_MAX_BYTES, - (void *)&pUsage->uiMaxBytes, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiCount) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_COUNT, - (void *)&pUsage->uiCount, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiOldVerCount) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_OLD_VER_COUNT, - (void *)&pUsage->uiOldVerCount, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiTotalBytesAllocated) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_TOTAL_BYTES_ALLOC, - (void *)&pUsage->uiTotalBytesAllocated, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiOldVerBytes) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_OLD_VER_BYTES, - (void *)&pUsage->uiOldVerBytes, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiCacheHits) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_CACHE_HITS, - (void *)&pUsage->uiCacheHits, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiCacheHitLooks) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_CACHE_HIT_LOOKS, - (void *)&pUsage->uiCacheHitLooks, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiCacheFaults) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_CACHE_FAULTS, - (void *)&pUsage->uiCacheFaults, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pUsage->uiCacheFaultLooks) - { - if( RC_BAD( rc = gedAddField( pPool, pSubContext, - FCS_MEMINFO_CACHE_FAULT_LOOKS, - (void *)&pUsage->uiCacheFaultLooks, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( GedChild( pSubContext)) - { - GedChildGraft( pContextNd, pSubContext, GED_LAST); - } - - if( pUsage != &pMemInfo->BlockCache) - { - pUsage = &pMemInfo->BlockCache; - if( (pSubContext = GedNodeMake( pPool, - FCS_MEMINFO_BLOCK_CACHE, &rc)) == NULL) - { - goto Exit; - } - goto add_usage; - } - - *ppTree = pContextNd; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - -/**************************************************************************** -Desc: Extracts a FLM_MEM_INFO structure from an HTD tree. -*****************************************************************************/ -RCODE fcsExtractMemInfo( - NODE * pTree, - FLM_MEM_INFO * pMemInfo) -{ - NODE * pTmpNd; - FLMUINT fieldPath[ 8]; - FLMUINT uiTmp; - FLM_CACHE_USAGE * pUsage; - FLMUINT uiUsageTag; - RCODE rc = FERR_OK; - - /* - Initialize the structure - */ - - f_memset( pMemInfo, 0, sizeof( FLM_MEM_INFO)); - - /* - Make sure pTree is non-null - */ - - if( !pTree) - { - goto Exit; - } - - /* - Parse the tree and extract the values. - */ - - fieldPath[ 0] = FCS_MEMINFO_CONTEXT; - fieldPath[ 1] = FCS_MEMINFO_DYNA_CACHE_ADJ; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - pMemInfo->bDynamicCacheAdjust = (FLMBOOL)(uiTmp ? TRUE : FALSE); - } - - fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_PERCENT; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustPercent); - } - - fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMin); - } - - fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MAX; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMax); - } - - fieldPath[ 1] = FCS_MEMINFO_CACHE_ADJ_MIN_LEAVE; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pMemInfo->uiCacheAdjustMinToLeave); - } - - pUsage = &pMemInfo->RecordCache; - uiUsageTag = FCS_MEMINFO_RECORD_CACHE; - -get_usage: - - fieldPath[ 0] = FCS_MEMINFO_CONTEXT; - fieldPath[ 1] = uiUsageTag; - fieldPath[ 2] = FCS_MEMINFO_MAX_BYTES; - fieldPath[ 3] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiMaxBytes); - } - - fieldPath[ 2] = FCS_MEMINFO_COUNT; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiCount); - } - - fieldPath[ 2] = FCS_MEMINFO_OLD_VER_COUNT; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiOldVerCount); - } - - fieldPath[ 2] = FCS_MEMINFO_TOTAL_BYTES_ALLOC; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiTotalBytesAllocated); - } - - fieldPath[ 2] = FCS_MEMINFO_OLD_VER_BYTES; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiOldVerBytes); - } - - fieldPath[ 2] = FCS_MEMINFO_CACHE_HITS; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiCacheHits); - } - - fieldPath[ 2] = FCS_MEMINFO_CACHE_HIT_LOOKS; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiCacheHitLooks); - } - - fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULTS; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaults); - } - - fieldPath[ 2] = FCS_MEMINFO_CACHE_FAULT_LOOKS; - if( (pTmpNd = GedPathFind( GED_TREE, pTree, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pUsage->uiCacheFaultLooks); - } - - if( pUsage != &pMemInfo->BlockCache) - { - pUsage = &pMemInfo->BlockCache; - uiUsageTag = FCS_MEMINFO_BLOCK_CACHE; - goto get_usage; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Builds a GEDCOM tree containing information on all FLAIM threads -*****************************************************************************/ -RCODE fcsBuildThreadInfo( - POOL * pPool, - NODE ** ppTree) -{ - NODE * pContextNd = NULL; - NODE * pRootNd = NULL; - void * pMark = GedPoolMark( pPool); - F_THREAD_INFO * pThreadInfo = NULL; - FLMUINT uiNumThreads; - FLMUINT uiLoop; - RCODE rc = FERR_OK; - - *ppTree = NULL; - - // Query FLAIM for available threads - - if( RC_BAD( rc = FlmGetThreadInfo( pPool, &pThreadInfo, &uiNumThreads))) - { - goto Exit; - } - - if( (pRootNd = GedNodeMake( pPool, - FCS_THREAD_INFO_ROOT, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = GedPutRecPtr( pPool, pRootNd, uiNumThreads))) - { - goto Exit; - } - - for( uiLoop = 0; uiLoop < uiNumThreads; uiLoop++) - { - // Add fields to the tree. - - if( (pContextNd = GedNodeMake( pPool, - FCS_THREAD_INFO_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - GedChildGraft( pRootNd, pContextNd, GED_LAST); - - if( pThreadInfo->uiThreadId) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_THREAD_ID, (void *)&pThreadInfo->uiThreadId, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pThreadInfo->uiThreadGroup) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_THREAD_GROUP, (void *)&pThreadInfo->uiThreadGroup, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pThreadInfo->uiAppId) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_APP_ID, (void *)&pThreadInfo->uiAppId, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pThreadInfo->uiStartTime) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_START_TIME, (void *)&pThreadInfo->uiStartTime, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - } - - if( pThreadInfo->pszThreadName) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_THREAD_NAME, (void *)pThreadInfo->pszThreadName, - 0, FLM_TEXT_TYPE))) - { - goto Exit; - } - } - - if( pThreadInfo->pszThreadStatus) - { - if( RC_BAD( rc = gedAddField( pPool, pContextNd, - FCS_THREADINFO_THREAD_STATUS, (void *)pThreadInfo->pszThreadStatus, - 0, FLM_TEXT_TYPE))) - { - goto Exit; - } - } - - pThreadInfo++; - } - - *ppTree = pRootNd; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - -/**************************************************************************** -Desc: Extracts a list of F_THREAD_INFO structure from an HTD tree. -*****************************************************************************/ -RCODE fcsExtractThreadInfo( - NODE * pTree, - POOL * pPool, - F_THREAD_INFO ** ppThreadInfo, - FLMUINT * puiNumThreads) -{ - NODE * pTmpNd; - NODE * pContextNd; - void * pMark = GedPoolMark( pPool); - FLMUINT uiTmp; - F_THREAD_INFO * pThreadInfo; - F_THREAD_INFO * pCurThread; - FLMUINT uiNumThreads; - FLMUINT uiLoop; - RCODE rc = FERR_OK; - - *ppThreadInfo = NULL; - *puiNumThreads = 0; - - if( GedTagNum( pTree) != FCS_THREAD_INFO_ROOT) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - if( RC_BAD( rc = GedGetUINT( pTree, &uiNumThreads))) - { - goto Exit; - } - - if( !uiNumThreads) - { - goto Exit; - } - - if( (pThreadInfo = (F_THREAD_INFO *)GedPoolCalloc( pPool, - uiNumThreads * sizeof( F_THREAD_INFO))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( (pContextNd = GedFind( 1, pTree, - FCS_THREAD_INFO_CONTEXT, 1)) == NULL) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - for( uiLoop = 0, pCurThread = pThreadInfo; - uiLoop < uiNumThreads; - uiLoop++, pCurThread++) - { - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_THREAD_ID, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pCurThread->uiThreadId); - } - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_THREAD_GROUP, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pCurThread->uiThreadGroup); - } - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_APP_ID, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pCurThread->uiAppId); - } - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_START_TIME, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &pCurThread->uiStartTime); - } - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_THREAD_NAME, 1)) != NULL) - { - if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp))) - { - goto Exit; - } - - if( uiTmp) - { - uiTmp++; - if( (pCurThread->pszThreadName = (char *)GedPoolAlloc( - pPool, uiTmp)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - if( RC_BAD( rc = GedGetNATIVE( pTmpNd, - pCurThread->pszThreadName, &uiTmp))) - { - goto Exit; - } - } - - if( (pTmpNd = GedFind( 1, pContextNd, - FCS_THREADINFO_THREAD_STATUS, 1)) != NULL) - { - if( RC_BAD( rc = GedGetNATIVE( pTmpNd, NULL, &uiTmp))) - { - goto Exit; - } - - if( uiTmp) - { - uiTmp++; - if( (pCurThread->pszThreadStatus = (char *)GedPoolAlloc( - pPool, uiTmp)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - if( RC_BAD( rc = GedGetNATIVE( pTmpNd, - pCurThread->pszThreadStatus, &uiTmp))) - { - goto Exit; - } - } - - if( (pContextNd = GedSibNext( pContextNd)) != NULL) - { - if( GedTagNum( pContextNd) != FCS_THREAD_INFO_CONTEXT) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - } - - *ppThreadInfo = pThreadInfo; - *puiNumThreads = uiNumThreads; - -Exit: - - if( RC_BAD( rc)) - { - GedPoolReset( pPool, pMark); - } - - return( rc); -} - -/**************************************************************************** -Desc: Reads a block from a remote database -*****************************************************************************/ -RCODE fcsGetBlock( - HFDB hDb, - FLMUINT uiAddress, - FLMUINT uiMinTransId, - FLMUINT * puiCount, - FLMUINT * puiBlocksExamined, - FLMUINT * puiNextBlkAddr, - FLMUINT uiFlags, - FLMBYTE * pucBlock) -{ - FDB * pDb = (FDB *)hDb; - RCODE rc = FERR_OK; - - flmAssert( IsInCSMode( hDb)); - - fdbInitCS( pDb); - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_BLOCK))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_ADDRESS, uiAddress))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TRANSACTION_ID, - uiMinTransId))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_COUNT, *puiCount))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiFlags))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - if( rc != FERR_IO_END_OF_FILE) - { - goto Exit; - } - } - - *puiBlocksExamined = (FLMUINT)Wire.getNumber2(); - *puiCount = (FLMUINT)Wire.getCount(); - *puiNextBlkAddr = Wire.getAddress(); - if( *puiCount) - { - f_memcpy( pucBlock, Wire.getBlock(), Wire.getBlockSize()); - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - -Exit: - - fdbExit( pDb); - return( rc); -} - -/**************************************************************************** -Desc: Instructs the server to generate a serial number -*****************************************************************************/ -RCODE fcsCreateSerialNumber( - void * pvCSContext, - FLMBYTE * pucSerialNum) -{ - RCODE rc = FERR_OK; - CS_CONTEXT * pCSContext = (CS_CONTEXT *)pvCSContext; - FCL_WIRE Wire( pCSContext); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_MISC, FCS_OP_CREATE_SERIAL_NUM))) - { - goto Exit; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - if( !Wire.getSerialNum()) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - f_memcpy( pucSerialNum, Wire.getSerialNum(), F_SERIAL_NUM_SIZE); - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sets or clears the backup active flag for the database -Note: This should only be called internally from the backup routines. -*****************************************************************************/ -RCODE fcsSetBackupActiveFlag( - HFDB hDb, - FLMBOOL bBackupActive) -{ - FDB * pDb = (FDB *)hDb; - RCODE rc = FERR_OK; - - flmAssert( IsInCSMode( hDb)); - - fdbInitCS( pDb); - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DB_SET_BACKUP_FLAG))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_BOOLEAN, bBackupActive))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - -Exit: - - fdbExit( pDb); - return( rc); -} - -/**************************************************************************** -Desc: Commits an update transaction and updates the log header. -Note: This should only be called internally from the backup routines. -*****************************************************************************/ -RCODE fcsDbTransCommitEx( - HFDB hDb, - FLMBOOL bForceCheckpoint, - FLMBYTE * pucLogHdr) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bInitializedFdb = FALSE; - - if( IsInCSMode( hDb)) - { - fdbInitCS( pDb); - bInitializedFdb = TRUE; - FCL_WIRE Wire( pDb->pCSContext, pDb); - - if (!pDb->pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - } - else - { - rc = Wire.doTransOp( - FCS_OP_TRANSACTION_COMMIT_EX, 0, 0, 0, - pucLogHdr, bForceCheckpoint); - } - } - else - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - -Exit: - - if( bInitializedFdb) - { - fdbExit( pDb); - } - - return( rc); -} - -/**************************************************************************** -Desc: Generates a hex-encoded, obfuscated string consisting of characters - 0-9, A-F from the passed-in data buffer. -*****************************************************************************/ -RCODE flmGenerateHexPacket( - FLMBYTE * pucData, - FLMUINT uiDataSize, - FLMBYTE ** ppucPacket) -{ - FLMUINT32 * pui32CRCTbl = NULL; - FLMBYTE * pucBinPacket = NULL; - FLMBYTE * pucHexPacket = NULL; - FLMBYTE * pucUsedMap = NULL; - FLMUINT32 ui32Tmp; - FLMUINT uiLoop; - FLMUINT uiSlot = 0; - FLMBYTE ucTmp[ 32]; - FLMUINT uiBinPacketSize; - FLMBOOL bTmp; - f_randomGenerator randGen; - RCODE rc = FERR_OK; - - // Determine the packet size. Make the minimum packet size 128 bytes - // to account for the 64-byte "header" and for the overhead of the - // CRC bytes, etc. Round the packet size up to the nearest 64-byte - // boundary after adding on the data size. - - uiBinPacketSize = 128 + uiDataSize; - if( (uiBinPacketSize % 64) != 0) - { - uiBinPacketSize += (64 - (uiBinPacketSize % 64)); - } - - // Allocate buffers for building the packet - - if( RC_BAD( rc = f_alloc( uiBinPacketSize, &pucBinPacket))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( uiBinPacketSize, &pucUsedMap))) - { - goto Exit; - } - - // First 64-bytes of the packet are reserved as a header - - f_memset( pucUsedMap, 0xFF, 64); - - // Initialize the CRC table. - - if( RC_BAD( rc = f_initCRCTable( &pui32CRCTbl))) - { - goto Exit; - } - - // Initialize the random number generator and seed with the current - // time. - - f_randomize( &randGen); - - // Fill the packet with random "noise" - - for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop += 4) - { - ui32Tmp = f_randomLong( &randGen); - UD2FBA( ui32Tmp, &pucBinPacket[ uiLoop]); - } - - for( uiLoop = 0; uiLoop < 512; uiLoop++) - { - ui32Tmp = f_randomLong( &randGen); - UD2FBA( ui32Tmp, &pucBinPacket[ f_randomChoice( - &randGen, 1, (int)(uiBinPacketSize / 4)) - 1]); - } - - // Determine a new random seed based on bytes in the - // packet header - - if( (ui32Tmp = (FLMUINT32)FB2UD( &pucBinPacket[ - f_randomChoice( &randGen, 1, 61) - 1])) == 0) - { - ui32Tmp = 1; - } - - f_randomSetSeed( &randGen, ui32Tmp); - - // Use the CRC of the header and the also first four bytes - // of the header as an 8-byte validation signature. This will - // be needed to decode the packet. - - // Initialize the CRC to 0xFFFFFFFF and then compute the 1's - // complement of the returned CRC. This implements the - // "standard" CRC used by PKZIP, etc. - - ui32Tmp = 0xFFFFFFFF; - f_updateCRC( pui32CRCTbl, pucBinPacket, 64, &ui32Tmp); - ui32Tmp = ~ui32Tmp; - UD2FBA( ui32Tmp, &ucTmp[ 0]); - f_memcpy( &ucTmp[ 4], pucBinPacket, 4); - - for( uiLoop = 0; uiLoop < 8; uiLoop++) - { - bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, - &randGen, &uiSlot); - - flmAssert( bTmp); - pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; - } - - // Encode the data size - - UD2FBA( uiDataSize, &ucTmp[ 0]); - for( uiLoop = 0; uiLoop < 4; uiLoop++) - { - bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, - &randGen, &uiSlot); - - flmAssert( bTmp); - pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; - } - - // Randomly dispurse the data throughout the buffer. Obfuscate the - // data using the first 64-bytes of the buffer. - - for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++) - { - bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, - &randGen, &uiSlot); - - flmAssert( bTmp); - pucBinPacket[ uiSlot] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64]; - } - - // Calculate and encode the data CRC - - ui32Tmp = 0xFFFFFFFF; - f_updateCRC( pui32CRCTbl, pucData, uiDataSize, &ui32Tmp); - ui32Tmp = ~ui32Tmp; - UD2FBA( ui32Tmp, &ucTmp[ 0]); - - for( uiLoop = 0; uiLoop < 4; uiLoop++) - { - bTmp = flmGetNextHexPacketSlot( pucUsedMap, uiBinPacketSize, - &randGen, &uiSlot); - - flmAssert( bTmp); - pucBinPacket[ uiSlot] = ucTmp[ uiLoop]; - } - - // Hex encode the binary packet - - if( RC_BAD( rc = f_alloc( - (uiBinPacketSize * 2) + 1, &pucHexPacket))) - { - goto Exit; - } - - for( uiLoop = 0; uiLoop < uiBinPacketSize; uiLoop++) - { - FLMBYTE ucLowNibble = pucBinPacket[ uiLoop] & 0x0F; - FLMBYTE ucHighNibble = (pucBinPacket[ uiLoop] & 0xF0) >> 4; - - pucHexPacket[ uiLoop << 1] = (ucHighNibble <= 9 - ? (ucHighNibble + '0') - : ((ucHighNibble - 0xA) + 'A')); - - pucHexPacket[ (uiLoop << 1) + 1] = (ucLowNibble <= 9 - ? (ucLowNibble + '0') - : ((ucLowNibble - 0xA) + 'A')); - } - - pucHexPacket[ uiBinPacketSize * 2] = 0; - *ppucPacket = pucHexPacket; - pucHexPacket = NULL; - -Exit: - - if( pui32CRCTbl) - { - f_freeCRCTable( &pui32CRCTbl); - } - - if( pucUsedMap) - { - f_free( &pucUsedMap); - } - - if( pucBinPacket) - { - f_free( &pucBinPacket); - } - - if( pucHexPacket) - { - f_free( &pucHexPacket); - } - - return( rc); -} - -/**************************************************************************** -Desc: Extracts a data buffer from the passed-in hex-encoded, obfuscated - string. -*****************************************************************************/ -RCODE flmExtractHexPacketData( - FLMBYTE * pucPacket, - FLMBYTE ** ppucData, - FLMUINT * puiDataSize) -{ - FLMUINT32 * pui32CRCTbl = NULL; - FLMBYTE * pucUsedMap = NULL; - FLMBYTE * pucData = NULL; - FLMBYTE * pucBinPacket = NULL; - FLMBYTE * pucTmp; - FLMUINT32 ui32Tmp; - FLMUINT32 ui32FirstCRC; - FLMUINT32 ui32Seed; - FLMUINT uiPacketSize; - FLMUINT uiLoop; - FLMUINT uiDataSize; - FLMBYTE ucTmp[ 32]; - FLMBYTE ucVal = 0; - FLMBOOL bValid; - f_randomGenerator randGen; - RCODE rc = FERR_OK; - - // Determine the packet size, ignoring all characters except 0-9, A-F - - uiPacketSize = 0; - pucTmp = pucPacket; - while( *pucTmp) - { - if( (*pucTmp >= '0' && *pucTmp <= '9') || - (*pucTmp >= 'A' && *pucTmp <= 'F')) - { - uiPacketSize++; - } - pucTmp++; - } - - if( uiPacketSize & 0x00000001 || - (uiPacketSize % 4) != 0 || uiPacketSize < 128) - { - rc = RC_SET( FERR_INVALID_CRC); - goto Exit; - } - - // Get the actual size of the decoded binary data by dividing - // the packet size by 2 - - uiPacketSize >>= 1; - - // Allocate a buffer and convert the data from hex ASCII to binary - - if( RC_BAD( rc = f_calloc( - uiPacketSize, &pucBinPacket))) - { - goto Exit; - } - - uiLoop = 0; - pucTmp = pucPacket; - while( *pucTmp) - { - bValid = FALSE; - if( *pucTmp >= '0' && *pucTmp <= '9') - { - ucVal = *pucTmp - '0'; - bValid = TRUE; - } - else if( *pucTmp >= 'A' && *pucTmp <= 'F') - { - ucVal = (*pucTmp - 'A') + 0x0A; - bValid = TRUE; - } - - if( bValid) - { - if( (uiLoop & 0x00000001) == 0) - { - ucVal <<= 4; - } - pucBinPacket[ uiLoop >> 1] |= ucVal; - uiLoop++; - } - - pucTmp++; - } - - // Allocate the data map - - if( RC_BAD( rc = f_calloc( uiPacketSize, &pucUsedMap))) - { - goto Exit; - } - - // First 64-bytes of the packet are reserved - - f_memset( pucUsedMap, 0xFF, 64); - - // Initialize the CRC table - - if( RC_BAD( rc = f_initCRCTable( &pui32CRCTbl))) - { - goto Exit; - } - - // Determine the CRC of the 1st 64-bytes - - ui32FirstCRC = 0xFFFFFFFF; - f_updateCRC( pui32CRCTbl, pucBinPacket, 64, &ui32FirstCRC); - ui32FirstCRC = ~ui32FirstCRC; - - // Search for the random seed within the first 64 bytes - - ui32Seed = 0; - for( uiLoop = 0; uiLoop < 61; uiLoop++) - { - ui32Tmp = FB2UD( &pucBinPacket[ uiLoop]); - f_randomSetSeed( &randGen, ui32Tmp); - - if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, - pucBinPacket, &randGen, ucTmp, 8))) - { - goto Exit; - } - - if( FB2UD( &ucTmp[ 0]) == ui32FirstCRC && - f_memcmp( &ucTmp[ 4], &pucBinPacket[ 0], 4) == 0) - { - ui32Seed = ui32Tmp; - break; - } - - // Reset the "used" map - f_memset( pucUsedMap, 0, uiPacketSize); - f_memset( pucUsedMap, 0xFF, 64); - } - - if( !ui32Seed) - { - rc = RC_SET( FERR_INVALID_CRC); - goto Exit; - } - - // Get the data size - - if( RC_BAD( rc = flmGetNextHexPacketBytes( pucUsedMap, uiPacketSize, - pucBinPacket, &randGen, ucTmp, 4))) - { - goto Exit; - } - - uiDataSize = (FLMUINT)FB2UD( &ucTmp[ 0]); - if( uiDataSize > uiPacketSize) - { - rc = RC_SET( FERR_INVALID_CRC); - goto Exit; - } - - // Allocate space for the data - - if( RC_BAD( rc = f_alloc( uiDataSize, &pucData))) - { - goto Exit; - } - - // Get the data - - if( RC_BAD( rc = flmGetNextHexPacketBytes( - pucUsedMap, uiPacketSize, - pucBinPacket, &randGen, pucData, uiDataSize))) - { - goto Exit; - } - - // Un-obfuscate the data - - for( uiLoop = 0; uiLoop < uiDataSize; uiLoop++) - { - pucData[ uiLoop] = pucData[ uiLoop] ^ pucBinPacket[ uiLoop % 64]; - } - - // Get the data CRC - - if( RC_BAD( rc = flmGetNextHexPacketBytes( - pucUsedMap, uiPacketSize, - pucBinPacket, &randGen, ucTmp, 4))) - { - goto Exit; - } - - // Verify the data CRC - - ui32Tmp = 0xFFFFFFFF; - f_updateCRC( pui32CRCTbl, pucData, uiDataSize, &ui32Tmp); - ui32Tmp = ~ui32Tmp; - - if( ui32Tmp != FB2UD( &ucTmp[ 0])) - { - rc = RC_SET( FERR_INVALID_CRC); - goto Exit; - } - - *ppucData = pucData; - pucData = NULL; - *puiDataSize = uiDataSize; - -Exit: - - if( pui32CRCTbl) - { - f_freeCRCTable( &pui32CRCTbl); - } - - if( pucUsedMap) - { - f_free( &pucUsedMap); - } - - if( pucData) - { - f_free( &pucData); - } - - if( pucBinPacket) - { - f_free( &pucBinPacket); - } - - return( rc); -} - -/**************************************************************************** -Desc: Used by flmGenerateHexPacket to find an unused byte in the packet -*****************************************************************************/ -FSTATIC FLMBOOL flmGetNextHexPacketSlot( - FLMBYTE * pucUsedMap, - FLMUINT uiMapSize, - f_randomGenerator * pRandGen, - FLMUINT * puiSlot) -{ - FLMUINT uiLoop; - FLMUINT uiSlot = 0; - FLMBOOL bFound = FALSE; - - for( uiLoop = 0; uiLoop < 100; uiLoop++) - { - uiSlot = ((FLMUINT)f_randomLong( pRandGen)) % uiMapSize; - if( !pucUsedMap[ uiSlot]) - { - bFound = TRUE; - goto Exit; - } - } - - // Scan the table from the top to find an empty slot - - for( uiSlot = 0; uiSlot < uiMapSize; uiSlot++) - { - if( !pucUsedMap[ uiSlot]) - { - bFound = TRUE; - goto Exit; - } - } - -Exit: - - if( bFound) - { - flmAssert( uiSlot < uiMapSize); - *puiSlot = uiSlot; - pucUsedMap[ uiSlot] = 0xFF; - } - - return( bFound); -} - -/**************************************************************************** -Desc: Used by flmExtractHexPacket to get the next N bytes of data from the - packet. -*****************************************************************************/ -FSTATIC RCODE flmGetNextHexPacketBytes( - FLMBYTE * pucUsedMap, - FLMUINT uiMapSize, - FLMBYTE * pucPacket, - f_randomGenerator * pRandGen, - FLMBYTE * pucBuf, - FLMUINT uiCount) -{ - FLMUINT uiSlot; - FLMUINT uiLoop; - RCODE rc = FERR_OK; - - for( uiLoop = 0; uiLoop < uiCount; uiLoop++) - { - if( !flmGetNextHexPacketSlot( pucUsedMap, uiMapSize, - pRandGen, &uiSlot)) - { - rc = RC_SET( FERR_INVALID_CRC); - goto Exit; - } - - pucBuf[ uiLoop] = pucPacket[ uiSlot]; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Decodes a string containing %XX sequences and does it in place. - Typically, this data comes from an HTML form. -****************************************************************************/ -void fcsDecodeHttpString( - char * pszSrc) -{ - char * pszDest; - - pszDest = pszSrc; - while( *pszSrc) - { - if( *pszSrc == '%') - { - pszSrc++; - if( f_isHexChar( pszSrc[ 0]) && f_isHexChar( pszSrc[ 1])) - { - *pszDest = (f_getHexVal( pszSrc[ 0]) << 4) | - f_getHexVal( pszSrc[ 1]); - - pszSrc += 2; - pszDest++; - continue; - } - } - else if( *pszSrc == '+') - { - *pszDest = ' '; - pszSrc++; - pszDest++; - continue; - } - - if( pszSrc != pszDest) - { - *pszDest = *pszSrc; - } - pszSrc++; - pszDest++; - } - - *pszDest = 0; -} diff --git a/flaim/src/fcs_wire.cpp b/flaim/src/fcs_wire.cpp deleted file mode 100644 index 517efbf..0000000 --- a/flaim/src/fcs_wire.cpp +++ /dev/null @@ -1,2444 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Wire class. Routines to read and parse an entire client request or -// server response. -// Tabs: 3 -// -// Copyright (c) 1998-2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fcs_wire.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_WIRE::FCS_WIRE( FCS_DIS * pDIStream, FCS_DOS * pDOStream) -{ - GedPoolInit( &m_pool, 2048); - m_pPool = &m_pool; - m_pDIStream = pDIStream; - m_pDOStream = pDOStream; - m_pRecord = NULL; - m_pFromKey = NULL; - m_pUntilKey = NULL; - m_bSendGedcom = FALSE; - (void)resetCommon(); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCS_WIRE::~FCS_WIRE( void) -{ - if( m_pRecord) - { - m_pRecord->Release(); - m_pRecord = NULL; - } - - if( m_pFromKey) - { - m_pFromKey->Release(); - m_pFromKey = NULL; - } - - if( m_pUntilKey) - { - m_pUntilKey->Release(); - m_pUntilKey = NULL; - } - - GedPoolFree( &m_pool); -} - -/**************************************************************************** -Desc: Resets all member variables to their default / initial values. -*****************************************************************************/ -void FCS_WIRE::resetCommon( void) -{ - if( m_pRecord) - { - m_pRecord->Release(); - m_pRecord = NULL; - } - - if( m_pFromKey) - { - m_pFromKey->Release(); - m_pFromKey = NULL; - } - - if( m_pUntilKey) - { - m_pUntilKey->Release(); - m_pUntilKey = NULL; - } - - m_uiClass = 0; - m_uiOp = 0; - m_uiRCode = 0; - m_uiDrn = 0; - m_uiTransType = FLM_READ_TRANS; - m_ui64Count = 0; - m_uiItemId = 0; - m_uiIndexId = 0; - m_puzItemName = NULL; - m_pHTD = NULL; - m_uiSessionId = FCS_INVALID_ID; - m_uiSessionCookie = 0; - m_uiContainer = FLM_DATA_CONTAINER; - m_uiTransId = FCS_INVALID_ID; - m_uiIteratorId = FCS_INVALID_ID; - m_puzFilePath = NULL; - m_puzFilePath2 = NULL; - m_puzFilePath3 = NULL; - m_pucBlock = NULL; - m_pucSerialNum = NULL; - m_uiBlockSize = 0; - m_bIncludesAsync = FALSE; - fcsInitCreateOpts( &m_CreateOpts); - GedPoolReset( m_pPool, NULL); - m_bFlag = FALSE; - m_ui64Number1 = 0; - m_ui64Number2 = 0; - m_ui64Number3 = 0; - m_uiAddress = 0; - m_uiFlags = 0; - m_uiFlaimVersion = 0; - m_i64SignedValue = 0; - m_pCSContext = NULL; - m_pDb = NULL; -} - -/**************************************************************************** -Desc: Reads the class and opcode for a client request or server response. -*****************************************************************************/ -RCODE FCS_WIRE::readOpcode( void) -{ - FLMBYTE ucClass; - FLMBYTE ucOp; - RCODE rc = FERR_OK; - - /* - Read the opcode. - */ - - if( RC_BAD( rc = m_pDIStream->read( &ucClass, 1, NULL))) - { - goto Exit; - } - m_uiClass = ucClass; - - if( RC_BAD( rc = m_pDIStream->read( &ucOp, 1, NULL))) - { - goto Exit; - } - m_uiOp = ucOp; - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Reads a client request or server response and sets the appropriate - member variable values. -*****************************************************************************/ -RCODE FCS_WIRE::readCommon( - FLMUINT * puiTagRV, - FLMBOOL * pbEndRV) -{ - FLMUINT16 ui16Tmp; - FLMUINT uiTag = 0; - RCODE rc = FERR_OK; - - /* - Initialize return variables. - */ - - *pbEndRV = FALSE; - - /* - Read the tag. - */ - - if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Tmp))) - { - goto Exit; - } - uiTag = ui16Tmp; - - /* - Read the request / response values. - */ - - switch( (uiTag & WIRE_VALUE_TAG_MASK)) - { - case WIRE_VALUE_RCODE: - { - rc = readNumber( uiTag, &m_uiRCode); - uiTag = 0; - break; - } - - case WIRE_VALUE_SESSION_ID: - { - rc = readNumber( uiTag, &m_uiSessionId); - uiTag = 0; - break; - } - - case WIRE_VALUE_SESSION_COOKIE: - { - rc = readNumber( uiTag, &m_uiSessionCookie); - uiTag = 0; - break; - } - - case WIRE_VALUE_CONTAINER_ID: - { - rc = readNumber( uiTag, &m_uiContainer); - uiTag = 0; - break; - } - - case WIRE_VALUE_COUNT: - { - rc = readNumber( uiTag, NULL, NULL, &m_ui64Count); - uiTag = 0; - break; - } - - case WIRE_VALUE_DRN: - { - rc = readNumber( uiTag, &m_uiDrn); - uiTag = 0; - break; - } - - case WIRE_VALUE_INDEX_ID: - { - rc = readNumber( uiTag, &m_uiIndexId); - uiTag = 0; - break; - } - - case WIRE_VALUE_HTD: - { - rc = m_pDIStream->readHTD( m_pPool, 0, 0, &m_pHTD, NULL); - uiTag = 0; - break; - } - - case WIRE_VALUE_RECORD: - { - FlmRecord * pRecord = m_pRecord; - if( RC_OK( rc = receiveRecord( &pRecord))) - { - if( m_pRecord != pRecord) - { - if( m_pRecord) - { - m_pRecord->Release(); - } - m_pRecord = pRecord; - } - } - - uiTag = 0; - break; - } - - case WIRE_VALUE_FROM_KEY: - { - FlmRecord * pFromKey = m_pFromKey; - if( RC_OK( rc = receiveRecord( &pFromKey))) - { - if( m_pFromKey != pFromKey) - { - if( m_pFromKey) - { - m_pFromKey->Release(); - } - m_pFromKey = pFromKey; - } - } - - uiTag = 0; - break; - } - - case WIRE_VALUE_UNTIL_KEY: - { - FlmRecord * pUntilKey = m_pUntilKey; - if( RC_OK( rc = receiveRecord( &pUntilKey))) - { - if( m_pUntilKey != pUntilKey) - { - if( m_pUntilKey) - { - m_pUntilKey->Release(); - } - m_pUntilKey = pUntilKey; - } - } - - uiTag = 0; - break; - } - - case WIRE_VALUE_CREATE_OPTS: - { - rc = receiveCreateOpts(); - uiTag = 0; - break; - } - - case WIRE_VALUE_ITERATOR_ID: - { - rc = readNumber( uiTag, &m_uiIteratorId); - uiTag = 0; - break; - } - - case WIRE_VALUE_TRANSACTION_TYPE: - { - rc = readNumber( uiTag, &m_uiTransType); - uiTag = 0; - break; - } - - case WIRE_VALUE_TRANSACTION_ID: - { - rc = readNumber( uiTag, &m_uiTransId); - uiTag = 0; - break; - } - - case WIRE_VALUE_ITEM_NAME: - { - rc = m_pDIStream->readUTF( m_pPool, &m_puzItemName); - uiTag = 0; - break; - } - - case WIRE_VALUE_ITEM_ID: - { - rc = readNumber( uiTag, &m_uiItemId); - uiTag = 0; - break; - } - - case WIRE_VALUE_BOOLEAN: - { - FLMUINT uiTmp; - - if( RC_OK( rc = readNumber( uiTag, &uiTmp))) - { - m_bFlag = (FLMBOOL)((uiTmp) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); - } - uiTag = 0; - break; - } - - case WIRE_VALUE_NUMBER1: - { - /* - General-purpose number value - */ - - rc = readNumber( uiTag, NULL, NULL, &m_ui64Number1); - uiTag = 0; - break; - } - - case WIRE_VALUE_NUMBER2: - { - /* - General-purpose number value - */ - - rc = readNumber( uiTag, NULL, NULL, &m_ui64Number2); - uiTag = 0; - break; - } - - case WIRE_VALUE_NUMBER3: - { - /* - General-purpose number value - */ - - rc = readNumber( uiTag, NULL, NULL, &m_ui64Number3); - uiTag = 0; - break; - } - - case WIRE_VALUE_ADDRESS: - { - /* - Block address, etc. - */ - - rc = readNumber( uiTag, &m_uiAddress); - uiTag = 0; - break; - } - - case WIRE_VALUE_SIGNED_NUMBER: - { - /* - General-purpose signed number value - */ - - rc = readNumber( uiTag, NULL, NULL, NULL, &m_i64SignedValue); - uiTag = 0; - break; - } - - case WIRE_VALUE_FILE_PATH: - { - rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath); - uiTag = 0; - break; - } - - case WIRE_VALUE_FILE_PATH_2: - { - rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath2); - uiTag = 0; - break; - } - - case WIRE_VALUE_FILE_PATH_3: - { - rc = m_pDIStream->readUTF( m_pPool, &m_puzFilePath3); - uiTag = 0; - break; - } - - case WIRE_VALUE_BLOCK: - { - rc = m_pDIStream->readLargeBinary( m_pPool, - &m_pucBlock, &m_uiBlockSize); - uiTag = 0; - break; - } - - case WIRE_VALUE_SERIAL_NUM: - { - FLMUINT uiSerialLen; - - if( RC_BAD( rc = m_pDIStream->readBinary( m_pPool, - &m_pucSerialNum, &uiSerialLen))) - { - goto Exit; - } - - if( uiSerialLen != F_SERIAL_NUM_SIZE) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Exit; - } - - uiTag = 0; - break; - } - - case WIRE_VALUE_START_ASYNC: - { - /* - Asynchronous data follows. - */ - - m_bIncludesAsync = TRUE; - *pbEndRV = TRUE; - uiTag = 0; - break; - } - - case WIRE_VALUE_FLAGS: - { - rc = readNumber( uiTag, &m_uiFlags); - uiTag = 0; - break; - } - - case WIRE_VALUE_FLAIM_VERSION: - { - /* - FLAIM code version - */ - - rc = readNumber( uiTag, &m_uiFlaimVersion); - uiTag = 0; - break; - } - - case WIRE_VALUE_TERMINATE: - { - /* - No more parameters. End the incomming message. - */ - - rc = m_pDIStream->endMessage(); - *pbEndRV = TRUE; - uiTag = 0; - break; - } - - default: - { - break; - } - } - -Exit: - - *puiTagRV = uiTag; - return( rc); -} - -/**************************************************************************** -Desc: Copies the internal CREATE_OPTS structure into a user-supplied location -*****************************************************************************/ -void FCS_WIRE::copyCreateOpts( - CREATE_OPTS * pCreateOptsRV) -{ - f_memcpy( pCreateOptsRV, &m_CreateOpts, sizeof( CREATE_OPTS)); -} - -/**************************************************************************** -Desc: Reads a numeric value from the specified data input stream. -*****************************************************************************/ -RCODE FCS_WIRE::readNumber( - FLMUINT uiTag, - FLMUINT * puiNumber, - FLMINT * piNumber, - FLMUINT64 * pui64Number, - FLMINT64 * pi64Number) -{ - - RCODE rc = FERR_OK; - - /* - Sanity check. - */ - - flmAssert( !(puiNumber && piNumber)); - - /* - Read the number of bytes specified by the - value's tag. - */ - - switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >> - WIRE_VALUE_TYPE_START_BIT)) - { - case WIRE_VALUE_TYPE_GEN_0: - { - if( puiNumber) - { - *puiNumber = 0; - } - else if( piNumber) - { - *piNumber = 0; - } - else if( pui64Number) - { - *pui64Number = 0; - } - else if( pi64Number) - { - *pi64Number = 0; - } - break; - } - - case WIRE_VALUE_TYPE_GEN_1: - { - FLMBYTE ucValue; - - if( RC_BAD( rc = m_pDIStream->read( &ucValue, 1, NULL))) - { - goto Exit; - } - - if( puiNumber) - { - *puiNumber = (FLMUINT)ucValue; - } - else if( piNumber) - { - *piNumber = (FLMINT)*((FLMINT8 *)&ucValue); - } - else if( pui64Number) - { - *pui64Number = (FLMUINT64)ucValue; - } - else if( pi64Number) - { - *pi64Number = (FLMINT64)*((FLMINT8 *)&ucValue); - } - break; - } - - case WIRE_VALUE_TYPE_GEN_2: - { - if( puiNumber || pui64Number) - { - FLMUINT16 ui16Value; - - if( RC_BAD( rc = m_pDIStream->readUShort( &ui16Value))) - { - goto Exit; - } - - if( puiNumber) - { - *puiNumber = (FLMUINT)ui16Value; - } - else if( pui64Number) - { - *pui64Number = (FLMUINT64)ui16Value; - } - } - else if( piNumber || pi64Number) - { - FLMINT16 i16Value; - - if( RC_BAD( rc = m_pDIStream->readShort( &i16Value))) - { - goto Exit; - } - - if( piNumber) - { - *piNumber = (FLMINT)i16Value; - } - else if( pi64Number) - { - *pi64Number = (FLMINT)i16Value; - } - } - break; - } - - case WIRE_VALUE_TYPE_GEN_4: - { - if( puiNumber || pui64Number) - { - FLMUINT32 ui32Value; - - if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Value))) - { - goto Exit; - } - - if( puiNumber) - { - *puiNumber = (FLMUINT)ui32Value; - } - else if( pui64Number) - { - *pui64Number = (FLMUINT64)ui32Value; - } - } - else if( piNumber || pi64Number) - { - FLMINT32 i32Value; - - if( RC_BAD( rc = m_pDIStream->readInt( &i32Value))) - { - goto Exit; - } - - if( piNumber) - { - *piNumber = (FLMINT)i32Value; - } - else if( pi64Number) - { - *pi64Number = (FLMINT64)i32Value; - } - } - break; - } - - case WIRE_VALUE_TYPE_GEN_8: - { - if( puiNumber || piNumber) - { - rc = RC_SET( FERR_CONV_NUM_OVERFLOW); - } - else - { - if( pui64Number) - { - if( RC_BAD( rc = m_pDIStream->readUInt64( pui64Number))) - { - goto Exit; - } - } - else if( pi64Number) - { - if( RC_BAD( rc = m_pDIStream->readInt64( pi64Number))) - { - goto Exit; - } - } - else - { - flmAssert( 0); - rc = RC_SET( FERR_INVALID_PARM); - goto Exit; - } - } - break; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Writes an unsigned number to the specified data output stream. -*****************************************************************************/ -RCODE FCS_WIRE::writeUnsignedNumber( - FLMUINT uiTag, - FLMUINT64 ui64Number) -{ - RCODE rc = FERR_OK; - - if( ui64Number <= (FLMUINT64)0x000000FF) - { - uiTag |= WIRE_VALUE_TYPE_GEN_1 << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeByte( (FLMBYTE)ui64Number))) - { - goto Exit; - } - } - else if( ui64Number <= (FLMUINT64)0x0000FFFF) - { - uiTag |= WIRE_VALUE_TYPE_GEN_2 << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)ui64Number))) - { - goto Exit; - } - } - else if( ui64Number <= (FLMUINT64)0xFFFFFFFF) - { - uiTag |= WIRE_VALUE_TYPE_GEN_4 << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeUInt32( (FLMUINT32)ui64Number))) - { - goto Exit; - } - } - else - { - uiTag |= WIRE_VALUE_TYPE_GEN_8 << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeUInt64( ui64Number))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Writes a signed number to the specified data output stream. -*****************************************************************************/ -RCODE FCS_WIRE::writeSignedNumber( - FLMUINT uiTag, - FLMINT64 i64Number) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = writeUnsignedNumber( uiTag, (FLMUINT64)i64Number))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Skips a parameter or return value in the data stream -*****************************************************************************/ -RCODE FCS_WIRE::skipValue( - FLMUINT uiTag) -{ - RCODE rc = FERR_OK; - - switch( ((uiTag & WIRE_VALUE_TYPE_MASK) >> - WIRE_VALUE_TYPE_START_BIT)) - { - case WIRE_VALUE_TYPE_GEN_0: - { - break; - } - - case WIRE_VALUE_TYPE_GEN_1: - { - if( RC_BAD( rc = m_pDIStream->skip( 1))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_GEN_2: - { - if( RC_BAD( rc = m_pDIStream->skip( 2))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_GEN_4: - { - if( RC_BAD( rc = m_pDIStream->skip( 4))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_GEN_8: - { - if( RC_BAD( rc = m_pDIStream->skip( 8))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_BINARY: - { - if( RC_BAD( rc = m_pDIStream->readBinary( NULL, NULL, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_LARGE_BINARY: - { - if( RC_BAD( rc = m_pDIStream->readLargeBinary( NULL, NULL, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_HTD: - { - if( RC_BAD( rc = m_pDIStream->readHTD( NULL, 0, 0, NULL, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE_RECORD: - { - if( RC_BAD( rc = receiveRecord( NULL))) - { - goto Exit; - } - } - - case WIRE_VALUE_TYPE_UTF: - { - if( RC_BAD( rc = m_pDIStream->readUTF( NULL, NULL))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Sends an opcode to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendOpcode( - FLMUINT uiClass, - FLMUINT uiOp) -{ - FLMBYTE ucClass = (FLMBYTE)uiClass; - FLMBYTE ucOp = (FLMBYTE)uiOp; - RCODE rc = FERR_OK; - - if( RC_BAD( rc = m_pDOStream->write( &ucClass, 1))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->write( &ucOp, 1))) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendTerminate( void) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = m_pDOStream->writeUShort( 0))) - { - goto Exit; - } - - /* - Terminate the stream message. - */ - - if( RC_BAD( rc = m_pDOStream->endMessage())) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendNumber( - FLMUINT uiTag, - FLMUINT64 ui64Value, - FLMINT64 i64Value) -{ - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_AREA_ID: - case WIRE_VALUE_OP_SEQ_NUM: - case WIRE_VALUE_FLAGS: - case WIRE_VALUE_CLIENT_VERSION: - case WIRE_VALUE_SESSION_ID: - case WIRE_VALUE_SESSION_COOKIE: - case WIRE_VALUE_CONTAINER_ID: - case WIRE_VALUE_INDEX_ID: - case WIRE_VALUE_ITEM_ID: - case WIRE_VALUE_TRANSACTION_ID: - case WIRE_VALUE_TRANSACTION_TYPE: - case WIRE_VALUE_DRN: - case WIRE_VALUE_COUNT: - case WIRE_VALUE_AUTOTRANS: - case WIRE_VALUE_MAX_LOCK_WAIT: - case WIRE_VALUE_RECORD_COUNT: - case WIRE_VALUE_BOOLEAN: - case WIRE_VALUE_ITERATOR_ID: - case WIRE_VALUE_SHARED_DICT_ID: - case WIRE_VALUE_PARENT_DICT_ID: - case WIRE_VALUE_TYPE: - case WIRE_VALUE_NUMBER1: - case WIRE_VALUE_NUMBER2: - case WIRE_VALUE_NUMBER3: - case WIRE_VALUE_ADDRESS: - case WIRE_VALUE_FLAIM_VERSION: - { - if( RC_BAD( rc = writeUnsignedNumber( uiTag, ui64Value))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_SIGNED_NUMBER: - { - if( RC_BAD( rc = writeSignedNumber( uiTag, i64Value))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendBinary( - FLMUINT uiTag, - FLMBYTE * pData, - FLMUINT uiLength) -{ - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_PASSWORD: - case WIRE_VALUE_SERIAL_NUM: - { - uiTag |= WIRE_VALUE_TYPE_BINARY << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeBinary( pData, uiLength))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_BLOCK: - { - uiTag |= WIRE_VALUE_TYPE_LARGE_BINARY << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeLargeBinary( pData, uiLength))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a record -*****************************************************************************/ -RCODE FCS_WIRE::sendRecord( - FLMUINT uiTag, - FlmRecord * pRecord) -{ -#define RECORD_OUTPUT_BUFFER_SIZE 64 - FLMBYTE pucBuffer[ RECORD_OUTPUT_BUFFER_SIZE]; - FLMBYTE * pucBufPos; - FLMBYTE ucDescriptor; - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_RECORD: - case WIRE_VALUE_FROM_KEY: - case WIRE_VALUE_UNTIL_KEY: - { - uiTag |= WIRE_VALUE_TYPE_RECORD << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - /* - The format of a record is (X = 1 bit): - - X X XXXXXX 0-64 bytes HTD - RESERVED HTD_FOLLOWS ID_LENGTH ID_VALUE TREE (optional) - - This sequence can repeat, terminating with a 0 byte. - */ - - ucDescriptor = 0; - pucBufPos = pucBuffer; - ucDescriptor |= (FLMBYTE)RECORD_HAS_HTD_FLAG; - - /* - Output the descriptor. - */ - - ucDescriptor |= (FLMBYTE)RECORD_ID_SIZE; - - *pucBufPos = ucDescriptor; - pucBufPos++; - - /* - Output the ID. Current format of a record ID is: - - 4-byte container ID, 4-byte DRN - */ - - flmUINT32ToBigEndian( (FLMUINT32)pRecord->getContainerID(), pucBufPos); - pucBufPos += 4; - - flmUINT32ToBigEndian( (FLMUINT32)pRecord->getID(), pucBufPos); - pucBufPos += 4; - - /* - Send the descriptor and record source. - */ - - if( RC_BAD( rc = m_pDOStream->write( pucBuffer, - pucBufPos - pucBuffer))) - { - goto Exit; - } - - /* - Send the record. - */ - - if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord, FALSE, m_bSendGedcom))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendDrnList( - FLMUINT uiTag, - FLMUINT * puiList) -{ - FLMUINT uiItemCount; - FLMUINT uiLoop; - FLMUINT uiBufSize = 0; - FLMBYTE * pucItemBuf = NULL; - FLMBYTE * pucItemPos; - RCODE rc = FERR_OK; - - /* - If the list pointer is invalid, goto exit. - */ - - if( !puiList) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_DRN_LIST: - { - uiTag |= WIRE_VALUE_TYPE_BINARY << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - /* - Count the entries in the list. For now, support only a list of - 2048 elements. - */ - - for( uiItemCount = 0; uiItemCount < 2048; uiItemCount++) - { - if( !puiList[ uiItemCount]) - { - /* - End-Of-List. - */ - break; - } - } - - /* - Allocate a buffer for the list. - */ - - uiBufSize = (FLMUINT)(((FLMUINT)sizeof( FLMUINT) * uiItemCount) + (FLMUINT)4); - if( RC_BAD( rc = f_calloc( uiBufSize, &pucItemBuf))) - { - goto Exit; - } - pucItemPos = pucItemBuf; - - /* - Set the item count. - */ - - UD2FBA( uiItemCount, pucItemPos); - pucItemPos += 4; - - /* - Put the items into the buffer. - */ - - for( uiLoop = 0; uiLoop < uiItemCount; uiLoop++) - { - UD2FBA( puiList[ uiLoop], pucItemPos); - pucItemPos += 4; - } - - /* - Send the list. - */ - - if( RC_BAD( rc = m_pDOStream->writeBinary( - pucItemBuf, uiBufSize))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - if( pucItemBuf) - { - f_free( (void **)&pucItemBuf); - } - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendString( - FLMUINT uiTag, - FLMUNICODE * puzString) -{ - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_FILE_NAME: - case WIRE_VALUE_FILE_PATH: - case WIRE_VALUE_FILE_PATH_2: - case WIRE_VALUE_FILE_PATH_3: - case WIRE_VALUE_DICT_FILE_PATH: - case WIRE_VALUE_ITEM_NAME: - case WIRE_VALUE_DICT_BUFFER: - { - uiTag |= WIRE_VALUE_TYPE_UTF << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeUTF( puzString))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendHTD( - FLMUINT uiTag, - NODE * pHTD) -{ - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_HTD: - case WIRE_VALUE_ITERATOR_SELECT: - case WIRE_VALUE_ITERATOR_FROM: - case WIRE_VALUE_ITERATOR_WHERE: - case WIRE_VALUE_ITERATOR_CONFIG: - { - uiTag |= WIRE_VALUE_TYPE_HTD << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeHTD( pHTD, NULL, TRUE, m_bSendGedcom))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendHTD( - FLMUINT uiTag, - FlmRecord * pRecord) -{ - RCODE rc = FERR_OK; - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_HTD: - { - uiTag |= WIRE_VALUE_TYPE_HTD << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDOStream->writeHTD( NULL, pRecord, FALSE, m_bSendGedcom))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Copies the current HTD tree to the application's pool -*****************************************************************************/ -RCODE FCS_WIRE::getHTD( - POOL * pPool, - NODE ** ppTreeRV) -{ - RCODE rc = FERR_OK; - - if( !m_pHTD) - { - *ppTreeRV = NULL; - goto Exit; - } - - if( (*ppTreeRV = GedCopy( pPool, GED_FOREST, m_pHTD)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendCreateOpts( - FLMUINT uiTag, - CREATE_OPTS * pCreateOpts) -{ - NODE * pRootNd = NULL; - void * pvMark = GedPoolMark( m_pPool); - RCODE rc = FERR_OK; - FLMUINT uiTmp; - - /* - If no create options, goto exit. - */ - - if( !pCreateOpts) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Send the parameter tag and value. - */ - - switch( uiTag) - { - case WIRE_VALUE_CREATE_OPTS: - { - uiTag |= WIRE_VALUE_TYPE_HTD << WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - - /* - Build the root node of the CreateOpts tree. - */ - - if( (pRootNd = GedNodeMake( m_pPool, FCS_COPT_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - /* - Add fields to the tree. - */ - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_BLOCK_SIZE, (void *)&pCreateOpts->uiBlockSize, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_MIN_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMinRflFileSize, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_MAX_RFL_FILE_SIZE, (void *)&pCreateOpts->uiMaxRflFileSize, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - uiTmp = pCreateOpts->bKeepRflFiles ? 1 : 0; - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_KEEP_RFL_FILES, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - uiTmp = pCreateOpts->bLogAbortedTransToRfl ? 1 : 0; - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_LOG_ABORTED_TRANS, (void *)&uiTmp, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_DEFAULT_LANG, (void *)&pCreateOpts->uiDefaultLanguage, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_VERSION, (void *)&pCreateOpts->uiVersionNum, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_APP_MAJOR_VER, (void *)&pCreateOpts->uiAppMajorVer, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - if( RC_BAD( rc = gedAddField( m_pPool, pRootNd, - FCS_COPT_APP_MINOR_VER, (void *)&pCreateOpts->uiAppMinorVer, - 0, FLM_NUMBER_TYPE))) - { - goto Exit; - } - - /* - Send the tree. - */ - - if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd, NULL, TRUE, m_bSendGedcom))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - GedPoolReset( m_pPool, pvMark); - return( rc); -} - -/**************************************************************************** -Desc: Sends a value to the client -*****************************************************************************/ -RCODE FCS_WIRE::sendNameTable( - FLMUINT uiTag, - F_NameTable * pNameTable) -{ - void * pvMark = GedPoolMark( m_pPool); - NODE * pRootNd; - NODE * pNd; - NODE * pItemIdNd; - FLMUINT uiMaxNameChars = 1024; - FLMUNICODE * puzItemName = NULL; - FLMUINT uiId; - FLMUINT uiType; - FLMUINT uiSubType; - FLMUINT uiNextPos; - RCODE rc = FERR_OK; - - // If the name table pointer is invalid, goto exit. - - if( !pNameTable) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Allocate a temporary name buffer - - if( (puzItemName = (FLMUNICODE *)GedPoolAlloc( m_pPool, - uiMaxNameChars * sizeof( FLMUNICODE))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Send the parameter tag and value. - - switch( uiTag) - { - case WIRE_VALUE_NAME_TABLE: - { - uiTag |= WIRE_VALUE_TYPE_HTD << - WIRE_VALUE_TYPE_START_BIT; - - if( RC_BAD( rc = m_pDOStream->writeUShort( (FLMUINT16)uiTag))) - { - goto Exit; - } - - - // Build the root node of the name table tree. - - if( (pRootNd = GedNodeMake( m_pPool, - FCS_NAME_TABLE_CONTEXT, &rc)) == NULL) - { - goto Exit; - } - - uiNextPos = 0; - while( pNameTable->getNextTagNumOrder( &uiNextPos, puzItemName, - NULL, uiMaxNameChars * sizeof( FLMUNICODE), - &uiId, &uiType, &uiSubType)) - { - if( (pItemIdNd = GedNodeMake( m_pPool, - FCS_NAME_TABLE_ITEM_ID, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = GedPutUINT( m_pPool, pItemIdNd, uiId))) - { - goto Exit; - } - - if( (pNd = GedNodeMake( m_pPool, - FCS_NAME_TABLE_ITEM_NAME, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = GedPutUNICODE( m_pPool, pNd, puzItemName))) - { - goto Exit; - } - - GedChildGraft( pItemIdNd, pNd, GED_LAST); - - if( (pNd = GedNodeMake( m_pPool, - FCS_NAME_TABLE_ITEM_TYPE, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiType))) - { - goto Exit; - } - - GedChildGraft( pItemIdNd, pNd, GED_LAST); - - if( (pNd = GedNodeMake( m_pPool, - FCS_NAME_TABLE_ITEM_SUBTYPE, &rc)) == NULL) - { - goto Exit; - } - - if( RC_BAD( rc = GedPutUINT( m_pPool, pNd, uiSubType))) - { - goto Exit; - } - - GedChildGraft( pItemIdNd, pNd, GED_LAST); - - // Graft the item into the tree - - GedChildGraft( pRootNd, pItemIdNd, GED_LAST); - - // Release CPU to prevent CPU hog - - f_yieldCPU(); - } - - // Send the tree. - - if( RC_BAD( rc = m_pDOStream->writeHTD( pRootNd, - NULL, TRUE, m_bSendGedcom))) - { - goto Exit; - } - break; - } - - default: - { -#ifdef FLM_DEBUG - flmAssert( 0); -#else - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; -#endif - } - } - -Exit: - - GedPoolReset( m_pPool, pvMark); - return( rc); -} - -/**************************************************************************** -Desc: Receives a record -*****************************************************************************/ -RCODE FCS_WIRE::receiveRecord( - FlmRecord ** ppRecord) -{ - FLMBYTE ucDescriptor = 0; - FLMUINT uiIdLen = 0; - FLMUINT32 ui32Container; - FLMUINT32 ui32Drn; - void * pvMark = GedPoolMark( m_pPool); - FLMBOOL bHasId = FALSE; - RCODE rc = FERR_OK; - - /* - Read the record. - */ - - if( RC_BAD( rc = m_pDIStream->read( &ucDescriptor, 1, NULL))) - { - goto Exit; - } - - uiIdLen = (FLMUINT)(ucDescriptor & RECORD_ID_SIZE_MASK); - - if( uiIdLen != RECORD_ID_SIZE) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - else if( uiIdLen) - { - bHasId = TRUE; - } - - /* - Read the record ID. - */ - - if( bHasId) - { - if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Container))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pDIStream->readUInt( &ui32Drn))) - { - goto Exit; - } - } - - /* - Read the record. - */ - - if( (ucDescriptor & RECORD_HAS_HTD_FLAG)) - { - if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, - ui32Container, ui32Drn, NULL, ppRecord))) - { - goto Exit; - } - } - -Exit: - - if( RC_BAD( rc) && ppRecord && *ppRecord) - { - (*ppRecord)->Release(); - *ppRecord = NULL; - } - - GedPoolReset( m_pPool, pvMark); - return( rc); -} - -/**************************************************************************** -Desc: Receives a CREATE_OPTS structure as an HTD tree. -*****************************************************************************/ -RCODE FCS_WIRE::receiveCreateOpts( void) -{ - NODE * pRootNd; - NODE * pTmpNd; - void * pPoolMark; - FLMUINT fieldPath[ 8]; - FLMUINT uiTmp; - RCODE rc = FERR_OK; - - pPoolMark = GedPoolMark( m_pPool); - - /* - Initialize the CREATE_OPTS structure to its default values. - */ - - fcsInitCreateOpts( &m_CreateOpts); - - /* - Receive the tree. - */ - - if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, - 0, 0, &pRootNd, NULL))) - { - goto Exit; - } - - /* - Parse the tree and extract the values. - */ - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_BLOCK_SIZE; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiBlockSize); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_MIN_RFL_FILE_SIZE; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMinRflFileSize); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_MAX_RFL_FILE_SIZE; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiMaxRflFileSize); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_KEEP_RFL_FILES; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - m_CreateOpts.bKeepRflFiles = (FLMBOOL)((uiTmp) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_LOG_ABORTED_TRANS; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &uiTmp); - m_CreateOpts.bLogAbortedTransToRfl = (FLMBOOL)((uiTmp) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_DEFAULT_LANG; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiDefaultLanguage); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_VERSION; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiVersionNum); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_APP_MAJOR_VER; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMajorVer); - } - - fieldPath[ 0] = FCS_COPT_CONTEXT; - fieldPath[ 1] = FCS_COPT_APP_MINOR_VER; - fieldPath[ 2] = 0; - - if( (pTmpNd = GedPathFind( GED_TREE, pRootNd, fieldPath, 1)) != NULL) - { - (void) GedGetUINT( pTmpNd, &m_CreateOpts.uiAppMinorVer); - } - -Exit: - - GedPoolReset( m_pPool, pPoolMark); - return( rc); -} - -/**************************************************************************** -Desc: Receives a name table. -*****************************************************************************/ -RCODE FCS_WIRE::receiveNameTable( - F_NameTable ** ppNameTable) -{ - NODE * pRootNd; - NODE * pItemIdNd; - NODE * pNd = NULL; - void * pvMark = GedPoolMark( m_pPool); - FLMUINT uiMaxNameChars = 1024; - FLMUNICODE * puzItemName; - FLMUINT uiItemId; - FLMUINT uiItemType; - FLMUINT uiItemSubType; - F_NameTable * pNameTable = NULL; - FLMBOOL bCreatedTable = FALSE; - RCODE rc = FERR_OK; - - // Allocate a temporary name buffer - - if( (puzItemName = (FLMUNICODE *)GedPoolAlloc( m_pPool, - uiMaxNameChars * sizeof( FLMUNICODE))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Initialize the name table. - - if( (pNameTable = *ppNameTable) == NULL) - { - if( (pNameTable = f_new F_NameTable) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - bCreatedTable = TRUE; - } - else - { - pNameTable->clearTable(); - } - - // Receive the tree. - - if( RC_BAD( rc = m_pDIStream->readHTD( m_pPool, - 0, 0, &pRootNd, NULL))) - { - goto Exit; - } - - // Parse the tree and extract the values. - - pItemIdNd = GedChild( pRootNd); - while( pItemIdNd) - { - if( GedTagNum( pItemIdNd) == FCS_NAME_TABLE_ITEM_ID) - { - if( RC_BAD( rc = GedGetUINT( pItemIdNd, &uiItemId))) - { - goto Exit; - } - - uiItemType = 0; - uiItemSubType = 0; - pNd = GedChild( pItemIdNd); - while( pNd) - { - switch( GedTagNum( pNd)) - { - case FCS_NAME_TABLE_ITEM_NAME: - { - FLMUINT uiStrLen = uiMaxNameChars * sizeof( FLMUNICODE); - - if( RC_BAD( rc = GedGetUNICODE( pNd, puzItemName, - &uiStrLen))) - { - goto Exit; - } - - break; - } - - case FCS_NAME_TABLE_ITEM_TYPE: - { - if( RC_BAD( rc = GedGetUINT( pNd, &uiItemType))) - { - goto Exit; - } - - break; - } - - case FCS_NAME_TABLE_ITEM_SUBTYPE: - { - if( RC_BAD( rc = GedGetUINT( pNd, &uiItemSubType))) - { - goto Exit; - } - - break; - } - } - - pNd = GedSibNext( pNd); - } - - if( puzItemName[ 0]) - { - if( RC_BAD( rc = pNameTable->addTag( puzItemName, NULL, - uiItemId, uiItemType, uiItemSubType, FALSE))) - { - goto Exit; - } - } - } - - pItemIdNd = GedSibNext( pItemIdNd); - - // Release CPU to prevent CPU hog - - f_yieldCPU(); - } - - pNameTable->sortTags(); - *ppNameTable = pNameTable; - pNameTable = NULL; - -Exit: - - if( pNameTable && bCreatedTable) - { - pNameTable->Release(); - } - - GedPoolReset( m_pPool, pvMark); - return( rc); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FCL_WIRE::FCL_WIRE( CS_CONTEXT_p pCSContext, FDB_p pDb) : - FCS_WIRE( pCSContext != NULL ? pCSContext->pIDataStream : NULL, - pCSContext != NULL ? pCSContext->pODataStream : NULL) -{ - m_pCSContext = pCSContext; - m_pDb = pDb; - - if( m_pCSContext) - { - m_bSendGedcom = m_pCSContext->bGedcomSupport; - } -} - -/**************************************************************************** -Desc: Sets the CS CONTEXT in FCL_WIRE and the I/O streams in FCS_WIRE -*****************************************************************************/ -void FCL_WIRE::setContext( - CS_CONTEXT_p pCSContext) -{ - m_pCSContext = pCSContext; - m_bSendGedcom = pCSContext->bGedcomSupport; - FCS_WIRE::setDIStream( pCSContext->pIDataStream); - FCS_WIRE::setDOStream( pCSContext->pODataStream); -} - -/**************************************************************************** -Desc: Send a client/server opcode with session id, and optionally the - database id -****************************************************************************/ -RCODE FCL_WIRE::sendOp( - FLMUINT uiClass, - FLMUINT uiOp) -{ - RCODE rc = FERR_OK; - - if (!m_pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Exit; - } - - /* Send the class and opcode. */ - - if (RC_BAD( rc = sendOpcode( (FLMBYTE)uiClass, (FLMBYTE)uiOp))) - { - goto Transmission_Error; - } - - /* Send session ID. */ - - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_SESSION_ID, m_pCSContext->uiSessionId))) - { - goto Transmission_Error; - } - - /* Send session cookie. */ - - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_SESSION_COOKIE, m_pCSContext->uiSessionCookie))) - { - goto Transmission_Error; - } - - /* Send operation sequence number. */ - - m_pCSContext->uiOpSeqNum++; - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_OP_SEQ_NUM, m_pCSContext->uiOpSeqNum))) - { - goto Transmission_Error; - } - -Exit: - - return( rc); - -Transmission_Error: - m_pCSContext->bConnectionGood = FALSE; - goto Exit; -} - - -/**************************************************************************** -Desc: This routine instructs the server to start or end a transaction -****************************************************************************/ -RCODE FCL_WIRE::doTransOp( - FLMUINT uiOp, - FLMUINT uiTransType, - FLMUINT uiFlags, - FLMUINT uiMaxLockWait, - FLMBYTE * pszHeader, - FLMBOOL bForceCheckpoint) -{ - FLMUINT uiTransFlags = 0; - RCODE rc = FERR_OK; - - /* Send request to server. */ - - if( RC_BAD( rc = sendOp( FCS_OPCLASS_TRANS, uiOp))) - { - goto Exit; - } - - if( uiOp == FCS_OP_TRANSACTION_BEGIN) - { - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_TRANSACTION_TYPE, uiTransType))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_MAX_LOCK_WAIT, uiMaxLockWait))) - { - goto Transmission_Error; - } - - if( pszHeader) - { - uiTransFlags |= FCS_TRANS_FLAG_GET_HEADER; - } - - if( uiFlags & FLM_DONT_KILL_TRANS) - { - uiTransFlags |= FCS_TRANS_FLAG_DONT_KILL; - } - - if( uiFlags & FLM_DONT_POISON_CACHE) - { - uiTransFlags |= FCS_TRANS_FLAG_DONT_POISON; - } - } - else if( uiOp == FCS_OP_TRANSACTION_COMMIT_EX) - { - if( pszHeader) - { - if( RC_BAD( rc = sendBinary( - WIRE_VALUE_BLOCK, pszHeader, F_TRANS_HEADER_SIZE))) - { - goto Exit; - } - } - - if( bForceCheckpoint) - { - uiTransFlags |= FCS_TRANS_FORCE_CHECKPOINT; - } - } - - if( uiTransFlags) - { - if (RC_BAD( rc = sendNumber( - WIRE_VALUE_FLAGS, uiTransFlags))) - { - goto Transmission_Error; - } - } - - if( RC_BAD( rc = sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if( RC_BAD( rc = read())) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = getRCode())) - { - goto Exit; - } - - if( pszHeader) - { - if( getBlockSize()) - { - f_memcpy( pszHeader, getBlock(), getBlockSize()); - } - else - { - f_memset( pszHeader, 0, 2048); - } - } - - if (!m_pDb) - { - m_pCSContext->bTransActive = (FLMBOOL)((uiOp == FCS_OP_TRANSACTION_BEGIN) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - } - -Exit: - - return( rc); -Transmission_Error: - m_pCSContext->bConnectionGood = FALSE; - goto Exit; -} - -/**************************************************************************** -Desc: Reads a server response for the client. -*****************************************************************************/ -RCODE FCL_WIRE::read( void) -{ - FLMUINT uiTag; - FLMUINT uiCount = 0; - FLMBOOL bDone = FALSE; - RCODE rc = FERR_OK; - - /* - Read the opcode. - */ - - if( RC_BAD( rc = readOpcode())) - { - goto Exit; - } - - /* - Read the request / response values. - */ - - for( ;;) - { - if (RC_BAD( rc = readCommon( &uiTag, &bDone))) - { - if( rc == FERR_EOF_HIT && !uiCount) - { - rc = FERR_OK; - } - goto Exit; - } - - if( bDone) - { - goto Exit; - } - - /* - uiTag will be non-zero if readCommon did not understand it. - */ - - uiCount++; - if( uiTag) - { - switch( (uiTag & WIRE_VALUE_TAG_MASK)) - { - case WIRE_VALUE_NAME_TABLE: - { - if( RC_BAD( rc = receiveNameTable( &m_pNameTable))) - { - goto Exit; - } - break; - } - - default: - { - if( RC_BAD( rc = skipValue( uiTag))) - { - goto Exit; - } - break; - } - } - } - } - -Exit: - - if( rc == FERR_EOF_HIT) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - return( rc); -} diff --git a/flaim/src/fdb.cpp b/flaim/src/fdb.cpp index 569d078..f250b3f 100644 --- a/flaim/src/fdb.cpp +++ b/flaim/src/fdb.cpp @@ -422,7 +422,7 @@ Desc: This function checks to see if an update transaction should be forced ****************************************************************************/ void flmExit( eFlmFuncs eFlmFuncId, - FDB_p pDb, + FDB * pDb, RCODE rc) { diff --git a/flaim/src/fdbcnfig.cpp b/flaim/src/fdbcnfig.cpp index 169753c..df4e77f 100644 --- a/flaim/src/fdbcnfig.cpp +++ b/flaim/src/fdbcnfig.cpp @@ -1,1561 +1,1807 @@ -//------------------------------------------------------------------------- -// Desc: Routines for database configuration. -// Tabs: 3 -// -// Copyright (c) 1996-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fdbcnfig.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE flmDbGetSizes( - FDB * pDb, - FLMUINT64 * pui64DbFileSize, - FLMUINT64 * pui64RollbackFileSize, - FLMUINT64 * pui64RflFileSize); - -void flmGetCPInfo( - void * pFilePtr, - CHECKPOINT_INFO * pCheckpointInfo); - -/******************************************************************************* -Desc: Sets indexing callback function -*******************************************************************************/ -FLMEXP void FLMAPI FlmSetIndexingCallback( - HFDB hDb, - IX_CALLBACK fnIxCallback, - void * pvAppData) -{ - ((FDB_p)hDb)->fnIxCallback = fnIxCallback; - ((FDB_p)hDb)->IxCallbackData = pvAppData; -} - -/******************************************************************************* -Desc: Returns indexing callback function -*******************************************************************************/ -FLMEXP void FLMAPI FlmGetIndexingCallback( - HFDB hDb, - IX_CALLBACK * pfnIxCallback, - void ** ppvAppData) -{ - if (pfnIxCallback) - { - *pfnIxCallback = ((FDB_p)hDb)->fnIxCallback; - } - - if (ppvAppData) - { - *ppvAppData = ((FDB_p)hDb)->IxCallbackData; - } -} - -/******************************************************************************* -Desc : Configures a callback function which allows validation of records - before they are returned to the user or committed to the - database. -Notes: This function stores a pointer to a callback function which is - called whenever a record is added, deleted, modified or - retrieved. This allows an application to validate record operations - before they are committed to the database (update operations) - or before records are returned to the application (read operations). - By default, no record validation is performed by FLAIM. -*******************************************************************************/ -FLMEXP void FLMAPI FlmSetRecValidatorHook( - HFDB hDb, - REC_VALIDATOR_HOOK fnRecValidatorHook, - void * pvAppData) -{ - ((FDB_p)hDb)->fnRecValidator = fnRecValidatorHook; - ((FDB_p)hDb)->RecValData = pvAppData; -} - -/******************************************************************************* -Desc : Returns to the user the sessions current Rec Validator Hook values. -*******************************************************************************/ -FLMEXP void FLMAPI FlmGetRecValidatorHook( - HFDB hDb, - REC_VALIDATOR_HOOK * pfnRecValidatorHook, // [out] RecValidator func pointer - void ** ppvAppData) // [out] application data -{ - if (pfnRecValidatorHook) - { - *pfnRecValidatorHook = ((FDB_p)hDb)->fnRecValidator; - } - - if (ppvAppData) - { - *ppvAppData = ((FDB_p)hDb)->RecValData; - } -} - -/******************************************************************************* -Desc : Configures a callback function which is called to return general - purpose information. -*******************************************************************************/ -FLMEXP void FLMAPI FlmSetStatusHook( - HFDB hDb, - STATUS_HOOK fnStatusHook, - void * pvAppData) -{ - ((FDB_p)hDb)->fnStatus = fnStatusHook; - ((FDB_p)hDb)->StatusData = pvAppData; -} - -/******************************************************************************* -Desc : Returns to the user the session's current status hook values. -*******************************************************************************/ -FLMEXP void FLMAPI FlmGetStatusHook( - HFDB hDb, - STATUS_HOOK * pfnStatusHook, - void ** ppvAppData) -{ - if (pfnStatusHook) - { - *pfnStatusHook = ((FDB_p)hDb)->fnStatus; - } - - if (ppvAppData) - { - *ppvAppData = ((FDB_p)hDb)->StatusData; - } -} - -/******************************************************************************* -Desc: Allows an application to configure various options for a database. -*******************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbConfig( - HFDB hDb, - eDbConfigType eConfigType, - void * Value1, - void * Value2 - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB_p)hDb; - FFILE * pFile = pDb->pFile; - LFILE * pLFile; - FLMBOOL bDbInitialized = FALSE; - FLMBOOL bStartedTrans = FALSE; - FLMBOOL bDbLocked = FALSE; - - /* - Handle client/server requests - */ - - if( IsInCSMode( hDb)) - { - fdbInitCS( pDb); - bDbInitialized = TRUE; - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_CONFIG))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TYPE, (FLMUINT)eConfigType))) - { - goto Transmission_Error; - } - - switch( eConfigType) - { - case FDB_SET_APP_VERSION: - case FDB_RFL_KEEP_FILES: - case FDB_KEEP_ABORTED_TRANS_IN_RFL: - case FDB_AUTO_TURN_OFF_KEEP_RFL: - case FDB_SET_APP_DATA: - if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER2, - (FLMUINT)Value1))) - { - goto Transmission_Error; - } - break; - - case FDB_RFL_DIR: - { - FLMUNICODE * puzRflDir; - - if( RC_BAD( rc = fcsConvertNativeToUnicode( - Wire.getPool(), (const char *)Value1, &puzRflDir))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendString( - WIRE_VALUE_FILE_PATH, puzRflDir))) - { - goto Transmission_Error; - } - break; - } - - case FDB_RFL_FILE_LIMITS: - case FDB_ENABLE_FIELD_ID_TABLE: - if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, - (FLMUINT)Value1))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER2, - (FLMUINT)Value2))) - { - goto Transmission_Error; - } - break; - - case FDB_FILE_EXTEND_SIZE: - if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, - (FLMUINT)Value1))) - { - goto Transmission_Error; - } - break; - - case FDB_RFL_ROLL_TO_NEXT_FILE: - break; - - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - // See if the database is being forced to close - - if( RC_BAD( rc = flmCheckDatabaseState( pDb))) - { - goto Exit; - } - - /* - Process the local (non-C/S) request - */ - - switch( eConfigType) - { - case FDB_RFL_KEEP_FILES: - { - FLMBOOL bKeepFiles = (FLMBOOL)(Value1 ? TRUE : FALSE); - - // This operation is not legal for pre 4.3 databases. - - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Make sure we don't have a transaction going - - if( pDb->uiTransType != FLM_NO_TRANS) - { - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - - // Make sure there is no active backup running - - f_mutexLock( gv_FlmSysData.hShareMutex); - if( pDb->pFile->bBackupActive) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - rc = RC_SET( FERR_BACKUP_ACTIVE); - goto Exit; - } - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - // Need to lock the database but not start a transaction yet. - - if( !(pDb->uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) - { - if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, - FLM_NO_TIMEOUT))) - { - goto Exit; - } - bDbLocked = TRUE; - } - - // If we aren't changing the keep flag, jump to exit without doing - // anything. - - if ((bKeepFiles && - pDb->pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES]) || - (!bKeepFiles && - !pDb->pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES])) - { - goto Exit; // Will return FERR_OK; - } - - // Force a checkpoint and roll to the next RFL file numbers. - // When changing from keep to no-keep or vice versa, we need to - // go to a new RFL file so that the new RFL file gets new - // serial numbers and a new keep or no-keep flag. - - if (RC_BAD( rc = FlmDbCheckpoint( hDb, FLM_NO_TIMEOUT))) - { - goto Exit; - } - - f_memcpy( pDb->pFile->ucUncommittedLogHdr, - pDb->pFile->ucLastCommittedLogHdr, - LOG_HEADER_SIZE); - pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_RFL_FILES] = - (FLMBYTE)((bKeepFiles) ? (FLMBYTE)1 : (FLMBYTE)0); - - // Force a new RFL file - this will also write out the entire - // log header - including the changes we made above. - - if (RC_BAD( rc = pDb->pFile->pRfl->finishCurrFile( pDb, TRUE))) - { - goto Exit; - } - break; - } - - case FDB_RFL_DIR: - { - const char * pszNewRflDir = (const char *)Value1; - - // This operation is not legal for pre 4.3 databases. - - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Make sure we don't have a transaction going - - if( pDb->uiTransType != FLM_NO_TRANS) - { - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - - // Make sure there is no active backup running - - f_mutexLock( gv_FlmSysData.hShareMutex); - if( pDb->pFile->bBackupActive) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - rc = RC_SET( FERR_BACKUP_ACTIVE); - goto Exit; - } - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - // Make sure the path exists and that it is a directory - // rather than a file. - - if (pszNewRflDir && *pszNewRflDir) - { - if( !gv_FlmSysData.pFileSystem->IsDir( pszNewRflDir)) - { - rc = RC_SET( FERR_IO_INVALID_PATH); - goto Exit; - } - } - - // Need to lock the database because we can't change the RFL - // directory until after the checkpoint has completed. The - // checkpoint code will unlock the transaction, but not the - // file if we have an explicit lock. We need to do this to - // prevent another transaction from beginning before we have - // changed the RFL directory. - - if( !(pDb->uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) - { - if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, - FLM_NO_TIMEOUT))) - { - goto Exit; - } - bDbLocked = TRUE; - } - - // Force a checkpoint and roll to the next RFL file numbers. Both - // of these steps are necessary to ensure that we won't have to do - // any recovery using the current RFL file - because we do not - // move the current RFL file to the new directory. Forcing the - // checkpoint ensures that we have no transactions that will need - // to be recovered if we were to crash. Rolling the RFL file number - // ensures that no more transactions will be logged to the current - // RFL file. - - if (RC_BAD( rc = FlmDbCheckpoint( hDb, FLM_NO_TIMEOUT))) - { - goto Exit; - } - - // Force a new RFL file. - - if (RC_BAD( rc = pDb->pFile->pRfl->finishCurrFile( pDb, FALSE))) - { - goto Exit; - } - - // Set the RFL directory to the new value now that we have - // finished the checkpoint and rolled to the next RFL file. - - f_mutexLock( gv_FlmSysData.hShareMutex); - rc = pFile->pRfl->setRflDir( pszNewRflDir); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - break; - } - - case FDB_RFL_FILE_LIMITS: - { - FLMUINT uiMinRflSize = (FLMUINT)Value1; - FLMUINT uiMaxRflSize = (FLMUINT)Value2; - - // Make sure the limits are valid. - - if (pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - - // Maximum must be enough to hold at least one packet plus - // the RFL header. Minimum must not be greater than the - // maximum. NOTE: Minimum and maximum are allowed to be - // equal, but in all cases, maximum takes precedence over - // minimum. We will first NOT exceed the maximum. Then, - // if possible, we will go above the minimum. - - if (uiMaxRflSize < RFL_MAX_PACKET_SIZE + 512) - { - uiMaxRflSize = RFL_MAX_PACKET_SIZE + 512; - } - if (uiMaxRflSize > gv_FlmSysData.uiMaxFileSize) - { - uiMaxRflSize = gv_FlmSysData.uiMaxFileSize; - } - if (uiMinRflSize > uiMaxRflSize) - { - uiMinRflSize = uiMaxRflSize; - } - } - - // Start an update transaction. Must not already be one going. - - bDbInitialized = TRUE; - if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - 0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS, - &bStartedTrans))) - { - goto Exit; - } - - // Commit the transaction. - - UD2FBA( (FLMUINT32)uiMinRflSize, - &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); - if (pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - UD2FBA( (FLMUINT32)uiMaxRflSize, - &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]); - } - if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) - { - goto Exit; - } - bStartedTrans = FALSE; - break; - } - - case FDB_RFL_ROLL_TO_NEXT_FILE: - - // This operation is not legal for pre 4.3 databases. - - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - /* - NOTE: finishCurrFile will not roll to the next file if the current - file has not been created. - */ - - if (RC_BAD( rc = pDb->pFile->pRfl->finishCurrFile( pDb, FALSE))) - { - goto Exit; - } - break; - - case FDB_SET_APP_VERSION: - { - FLMUINT uiOldMajorVer; - FLMUINT uiOldMinorVer; - - /* - Start an update transaction. - */ - - bDbInitialized = TRUE; - if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - 0, 5 | FLM_AUTO_TRANS, &bStartedTrans))) - { - goto Exit; - } - - /* - Set the version. - */ - - f_mutexLock( gv_FlmSysData.hShareMutex); - uiOldMajorVer = pDb->pFile->FileHdr.uiAppMajorVer; - pDb->pFile->FileHdr.uiAppMajorVer = (FLMUINT)Value1; - uiOldMinorVer = pDb->pFile->FileHdr.uiAppMinorVer; - pDb->pFile->FileHdr.uiAppMinorVer = (FLMUINT)Value2; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - /* - Commit the transaction. NOTE: This will always cause - us to write out the application version numbers, because - we always write out the prefix - first 512 bytes. - */ - - if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) - { - /* - Undo the changes made above - */ - - f_mutexLock( gv_FlmSysData.hShareMutex); - pDb->pFile->FileHdr.uiAppMajorVer = uiOldMajorVer; - pDb->pFile->FileHdr.uiAppMinorVer = uiOldMinorVer; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - goto Exit; - } - bStartedTrans = FALSE; - break; - } - - case FDB_KEEP_ABORTED_TRANS_IN_RFL: - case FDB_AUTO_TURN_OFF_KEEP_RFL: - - // These operations are not legal for pre 4.3 databases. - - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Start an update transaction. Must not already be one going. - - bDbInitialized = TRUE; - if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - 0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS, - &bStartedTrans))) - { - goto Exit; - } - - // Change the uncommitted log header - - if (eConfigType == FDB_KEEP_ABORTED_TRANS_IN_RFL) - { - pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL] = - (FLMBYTE)(Value1 - ? (FLMBYTE)1 - : (FLMBYTE)0); - } - else - { - pDb->pFile->ucUncommittedLogHdr [LOG_AUTO_TURN_OFF_KEEP_RFL] = - (FLMBYTE)(Value1 - ? (FLMBYTE)1 - : (FLMBYTE)0); - } - - // Commit the transaction. - - if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) - { - goto Exit; - } - bStartedTrans = FALSE; - break; - - case FDB_FILE_EXTEND_SIZE: - pDb->pFile->uiFileExtendSize = (FLMUINT)Value1; - break; - - case FDB_SET_APP_DATA: - pDb->pvAppData = Value1; - break; - - case FDB_SET_COMMIT_CALLBACK: - pDb->fnCommit = (COMMIT_FUNC)((FLMUINT)Value1); - pDb->pvCommitData = Value2; - break; - - case FDB_ENABLE_FIELD_ID_TABLE: - if (pDb->pDict) - { - if (RC_BAD( rc = fdictGetContainer( pDb->pDict, (FLMUINT)Value1, - &pLFile))) - { - goto Exit; - } - pLFile->bMakeFieldIdTable = (FLMBOOL)Value2; - } - else if (pDb->pFile->pDictList) - { - if (RC_BAD( rc = fdictGetContainer( pDb->pFile->pDictList, - (FLMUINT)Value1, &pLFile))) - { - goto Exit; - } - pLFile->bMakeFieldIdTable = (FLMBOOL)Value2; - } - break; - - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - -Exit: - - if( bStartedTrans) - { - flmAbortDbTrans( pDb); - } - - if( bDbLocked) - { - FlmDbUnlock( hDb); - } - - if( bDbInitialized) - { - fdbExit( pDb); - } - - return( rc); -} - -/**************************************************************************** -Desc: Returns database, rollback, and rollforward sizes. We are guaranteed - to be inside an update transaction at this point. -****************************************************************************/ -FSTATIC RCODE flmDbGetSizes( - FDB * pDb, - FLMUINT64 * pui64DbFileSize, - FLMUINT64 * pui64RollbackFileSize, - FLMUINT64 * pui64RflFileSize - ) -{ - RCODE rc = FERR_OK; - FFILE * pFile = pDb->pFile; - FLMUINT uiDbVersion = pFile->FileHdr.uiVersionNum; - FLMUINT uiEndAddress; - FLMUINT uiLastFileNumber; - FLMUINT uiLastFileSize; - char szTmpName[ F_PATH_MAX_SIZE]; - char szRflDir[ F_PATH_MAX_SIZE]; - char szPrefix[ F_FILENAME_SIZE]; - F_FileHdlImp * pFileHdl = NULL; - F_DirHdl * pDirHdl = NULL; - - // Better be inside an update transaction at this point. - - flmAssert( pDb->uiTransType == FLM_UPDATE_TRANS); - - // See if they want the database files sizes. - - if (pui64DbFileSize) - { - uiEndAddress = pDb->LogHdr.uiLogicalEOF; - uiLastFileNumber = FSGetFileNumber( uiEndAddress); - - // Last file number better be in the proper range. - - flmAssert( uiLastFileNumber >= 1 && - uiLastFileNumber <= MAX_DATA_BLOCK_FILE_NUMBER( uiDbVersion)); - - // Get the actual size of the last file. - - if (RC_BAD( rc = pDb->pSFileHdl->GetFileSize( uiLastFileNumber, - &uiLastFileSize))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - if (uiLastFileNumber > 1) - { - rc = FERR_OK; - uiLastFileSize = 0; - } - else - { - - // Should always be a data file #1 - - flmAssert( 0); - goto Exit; - } - } - else - { - goto Exit; - } - } - - // One of two situations exists with respect to the last - // file: 1) it has not been fully written out yet (blocks - // are still cached, or 2) it has been written out and - // extended beyond what the logical EOF shows. We want - // the larger of these two possibilities. - - if (FSGetFileOffset( uiEndAddress) > uiLastFileSize) - { - uiLastFileSize = FSGetFileOffset( uiEndAddress); - } - - if (uiLastFileNumber == 1) - { - - // Only one file - use last file's size. - - *pui64DbFileSize = (FLMUINT64)uiLastFileSize; - } - else - { - - // Size is the sum of full size for all files except the last one, - // plus the calculated (or actual) size of the last one. - - (*pui64DbFileSize) = (FLMUINT64)(uiLastFileNumber - 1) * - (FLMUINT64)pFile->uiMaxFileSize + - (FLMUINT64)uiLastFileSize; - } - } - - // See if they want the rollback files sizes. - - if (pui64RollbackFileSize) - { - uiEndAddress = (FLMUINT)FB2UD( - &pFile->ucUncommittedLogHdr [LOG_ROLLBACK_EOF]); - uiLastFileNumber = FSGetFileNumber( uiEndAddress); - - // Last file number better be in the proper range. - - flmAssert( !uiLastFileNumber || - (uiLastFileNumber >= - FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion) && - uiLastFileNumber <= - MAX_LOG_BLOCK_FILE_NUMBER( uiDbVersion))); - - // Get the size of the last file number. - - if (RC_BAD( rc = pDb->pSFileHdl->GetFileSize( uiLastFileNumber, - &uiLastFileSize))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - if (uiLastFileNumber) - { - rc = FERR_OK; - uiLastFileSize = 0; - } - else - { - - // Should always have rollback file #0 - - flmAssert( 0); - goto Exit; - } - } - else - { - goto Exit; - } - } - - // If the EOF offset for the last file is greater than the - // actual file size, use it instead of the actual file size. - - if (FSGetFileOffset( uiEndAddress) > uiLastFileSize) - { - uiLastFileSize = FSGetFileOffset( uiEndAddress); - } - - // Special case handling here because rollback file numbers start with - // zero and then skip to a file number that is one beyond the - // highest data file number - so the calculation for file size needs - // to account for this. - - if (!uiLastFileNumber) - { - *pui64RollbackFileSize = (FLMUINT64)uiLastFileSize; - } - else - { - FLMUINT uiFirstLogFileNum = - FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); - - // Add full size of file zero plus a full size for every file - // except the last one. - - (*pui64RollbackFileSize) = (FLMUINT64)(uiLastFileNumber - - uiFirstLogFileNum + 1) * - (FLMUINT64)pFile->uiMaxFileSize + - (FLMUINT64)uiLastFileSize; - } - } - - // See if they want the roll-forward log file sizes. - - if (pui64RflFileSize) - { - char * pszDbFileName = pFile->pszDbPath; - - *pui64RflFileSize = 0; - if (uiDbVersion < FLM_VER_4_3) - { - - // For pre-4.3 versions, only need to get the size for one - // RFL file. - - if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDbFileName, - NULL, 1, szTmpName))) - { - goto Exit; - } - - // Open the file and get its size. - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( szTmpName, - F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, - 512, &pFileHdl))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - uiLastFileSize = 0; - } - else - { - goto Exit; - } - } - else - { - if (RC_BAD( rc = pFileHdl->Size( &uiLastFileSize))) - { - goto Exit; - } - } - if (pFileHdl) - { - pFileHdl->Release(); - pFileHdl = NULL; - } - *pui64RflFileSize = (FLMUINT64)uiLastFileSize; - } - else - { - - // For 4.3 and greater, need to scan the RFL directory for - // RFL files. The call below to rflGetDirAndPrefix is done - // to get the prefix. It will not return the correct - // RFL directory name, because we are passing in a NULL - // RFL directory path (which may or may not be correct). - // That's OK, because we get the RFL directory directly - // from the F_Rfl object anyway. - - if (RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDbFileName, - NULL, szRflDir, szPrefix))) - { - goto Exit; - } - - // We need to get the RFL directory from the F_Rfl object. - - f_strcpy( szRflDir, pFile->pRfl->getRflDirPtr()); - - // See if the directory exists. If not, we are done. - - if (gv_FlmSysData.pFileSystem->IsDir( szRflDir)) - { - - // Open the directory and scan for RFL files. - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenDir( - szRflDir, "*", &pDirHdl))) - { - goto Exit; - } - for (;;) - { - if (RC_BAD( rc = pDirHdl->Next())) - { - if (rc == FERR_IO_NO_MORE_FILES) - { - rc = FERR_OK; - break; - } - else - { - goto Exit; - } - } - pDirHdl->CurrentItemPath( szTmpName); - - // If the item looks like an RFL file name, get - // its size. - - if (!pDirHdl->CurrentItemIsDir() && - rflGetFileNum( uiDbVersion, szPrefix, szTmpName, - &uiLastFileNumber)) - { - - // Open the file and get its size. - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( - szTmpName, - F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, - 512, &pFileHdl))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - uiLastFileSize = 0; - } - else - { - goto Exit; - } - } - else - { - if (RC_BAD( rc = pFileHdl->Size( &uiLastFileSize))) - { - goto Exit; - } - } - if (pFileHdl) - { - pFileHdl->Release(); - pFileHdl = NULL; - } - (*pui64RflFileSize) += (FLMUINT64)uiLastFileSize; - } - } - } - } - } - -Exit: - if (pFileHdl) - { - pFileHdl->Release(); - } - if (pDirHdl) - { - pDirHdl->Release(); - } - return( rc); -} - -/******************************************************************************* -Desc: Returns information about a particular database. -*******************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetConfig( - HFDB hDb, - eDbGetConfigType eGetConfigType, - void * Value1, - void * Value2, - void * Value3 - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FFILE * pFile = pDb->pFile; - FLMBOOL bDbInitialized = FALSE; - FLMBOOL bStartedTrans = FALSE; - FLMUINT uiTransType = FLM_NO_TRANS; - CHECKPOINT_INFO * pCheckpointInfo; - - if( IsInCSMode( hDb)) - { - fdbInitCS( pDb); - bDbInitialized = TRUE; - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - CREATE_OPTS createOpts; - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_CONFIG))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TYPE, (FLMUINT)eGetConfigType))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - switch( eGetConfigType) - { - case FDB_GET_VERSION: - Wire.copyCreateOpts( &createOpts); - *((FLMUINT *)Value1) = createOpts.uiVersionNum; - break; - case FDB_GET_BLKSIZ: - Wire.copyCreateOpts( &createOpts); - *((FLMUINT *)Value1) = createOpts.uiBlockSize; - break; - case FDB_GET_DEFAULT_LANG: - Wire.copyCreateOpts( &createOpts); - *((FLMUINT *)Value1) = createOpts.uiDefaultLanguage; - break; - case FDB_GET_PATH: - case FDB_GET_RFL_DIR: - { - char * pszPath; - POOL * pPool = Wire.getPool(); - void * pvMark = GedPoolMark( pPool); - - if( RC_BAD( rc = fcsConvertUnicodeToNative( pPool, - (FLMUNICODE *)Wire.getFilePath(), &pszPath))) - { - goto Exit; - } - f_strcpy( (char *)Value1, pszPath); - GedPoolReset( pPool, pvMark); - break; - } - case FDB_GET_TRANS_ID: - case FDB_GET_RFL_FILE_NUM: - case FDB_GET_RFL_HIGHEST_NU: - case FDB_GET_LAST_BACKUP_TRANS_ID: - case FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP: - case FDB_GET_FILE_EXTEND_SIZE: - case FDB_GET_APP_DATA: - case FDB_GET_NEXT_INC_BACKUP_SEQ_NUM: - case FDB_GET_DICT_SEQ_NUM: - case FDB_GET_FFILE_ID: - case FDB_GET_MUST_CLOSE_RC: - *((FLMUINT *)Value1) = (FLMUINT)Wire.getNumber1(); - break; - case FDB_GET_RFL_FILE_SIZE_LIMITS: - if (Value1) - { - *((FLMUINT *)Value1) = (FLMUINT)Wire.getNumber1(); - } - if (Value2) - { - *((FLMUINT *)Value2) = (FLMUINT)Wire.getNumber2(); - } - break; - case FDB_GET_RFL_KEEP_FLAG: - case FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG: - case FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG: - *((FLMBOOL *)Value1) = Wire.getBoolean(); - break; - case FDB_GET_CHECKPOINT_INFO: - rc = fcsExtractCheckpointInfo( Wire.getHTD(), (CHECKPOINT_INFO *)Value1); - break; - case FDB_GET_LOCK_HOLDER: - rc = fcsExtractLockUser( Wire.getHTD(), FALSE, ((LOCK_USER *)Value1)); - break; - case FDB_GET_LOCK_WAITERS: - rc = fcsExtractLockUser( Wire.getHTD(), TRUE, ((void *)Value1)); - break; - case FDB_GET_SERIAL_NUMBER: - { - f_memcpy( (FLMBYTE *)Value1, - Wire.getSerialNum(), F_SERIAL_NUM_SIZE); - break; - } - case FDB_GET_SIZES: - if (Value1) - { - *((FLMUINT64 *)Value1) = (FLMUINT64)Wire.getNumber1(); - } - if (Value2) - { - *((FLMUINT64 *)Value2) = (FLMUINT64)Wire.getNumber2(); - } - if (Value3) - { - *((FLMUINT64 *)Value3) = (FLMUINT64)Wire.getNumber3(); - } - break; - - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - break; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if (eGetConfigType == FDB_GET_RFL_FILE_NUM || - eGetConfigType == FDB_GET_RFL_HIGHEST_NU || - eGetConfigType == FDB_GET_RFL_FILE_SIZE_LIMITS || - eGetConfigType == FDB_GET_RFL_KEEP_FLAG || - eGetConfigType == FDB_GET_LAST_BACKUP_TRANS_ID || - eGetConfigType == FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP || - eGetConfigType == FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG || - eGetConfigType == FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG || - eGetConfigType == FDB_GET_SIZES || - eGetConfigType == FDB_GET_NEXT_INC_BACKUP_SEQ_NUM) - { - uiTransType = FLM_UPDATE_TRANS; - } - - bDbInitialized = TRUE; - if (RC_BAD( rc = fdbInit( pDb, uiTransType, - FDB_TRANS_GOING_OK | FDB_DONT_RESET_DIAG, - FLM_NO_TIMEOUT | FLM_AUTO_TRANS, &bStartedTrans))) - { - goto Exit; - } - - switch( eGetConfigType) - { - case FDB_GET_VERSION: - *((FLMUINT *)Value1) = pFile->FileHdr.uiVersionNum; - break; - case FDB_GET_BLKSIZ: - *((FLMUINT *)Value1) = pFile->FileHdr.uiBlockSize; - break; - case FDB_GET_DEFAULT_LANG: - *((FLMUINT *)Value1) = pFile->FileHdr.uiDefaultLanguage; - break; - case FDB_GET_PATH: - if( RC_BAD( rc = flmGetFilePath( pFile, ((char *)Value1)))) - { - goto Exit; - } - break; - case FDB_GET_TRANS_ID: - if (pDb->uiTransType != FLM_NO_TRANS) - { - *((FLMUINT *)Value1) = pDb->LogHdr.uiCurrTransID; - } - else if (pDb->uiFlags & FDB_HAS_FILE_LOCK) - { - - // Get last committed value. - - *((FLMUINT *)Value1) = FB2UD( &pFile->ucLastCommittedLogHdr [LOG_CURR_TRANS_ID]); - } - else - { - *((FLMUINT *)Value1) = 0; - } - break; - case FDB_GET_CHECKPOINT_INFO: - pCheckpointInfo = (CHECKPOINT_INFO *)Value1; - f_mutexLock( gv_FlmSysData.hShareMutex); - flmGetCPInfo( pFile, pCheckpointInfo); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - break; - case FDB_GET_LOCK_HOLDER: - if (pFile->pFileLockObj) - { - rc = pFile->pFileLockObj->GetLockInfo( FALSE, (void *)Value1); - } - else - { - ((LOCK_USER *)Value1)->uiThreadId = 0; - ((LOCK_USER *)Value1)->uiTime = 0; - } - break; - case FDB_GET_LOCK_WAITERS: - if (pFile->pFileLockObj) - { - rc = pFile->pFileLockObj->GetLockInfo( TRUE, (void *)Value1); - } - else - { - *((LOCK_USER **)Value1) = NULL; - } - break; - - case FDB_GET_LOCK_WAITERS_EX: - { - FlmLockInfo * pLockInfo = (FlmLockInfo *)Value1; - - if (pFile->pFileLockObj) - { - rc = pFile->pFileLockObj->GetLockInfo( pLockInfo); - } - else - { - pLockInfo->setLockCount( 0); - } - break; - } - - case FDB_GET_RFL_DIR: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - f_mutexLock( gv_FlmSysData.hShareMutex); - f_strcpy( (char *)Value1, pDb->pFile->pRfl->getRflDirPtr()); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - break; - - case FDB_GET_RFL_FILE_NUM: - { - FLMUINT uiLastCPFile; - FLMUINT uiLastTransFile; - - /* - Get the CP and last trans RFL file numbers. Need to - return the higher of the two. No need to lock the - mutex because we are in an update transaction. - */ - - uiLastCPFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ - LOG_RFL_LAST_CP_FILE_NUM]); - - uiLastTransFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ - LOG_RFL_FILE_NUM]); - - *((FLMUINT *)Value1) = uiLastCPFile > uiLastTransFile - ? uiLastCPFile - : uiLastTransFile; - break; - } - - case FDB_GET_RFL_HIGHEST_NU: - { - FLMUINT uiLastCPFile; - FLMUINT uiLastTransFile; - - /* - Get the CP and last trans RFL file numbers. Need to - return the lower of the two minus 1. - */ - - uiLastCPFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ - LOG_RFL_LAST_CP_FILE_NUM]); - - uiLastTransFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ - LOG_RFL_FILE_NUM]); - - *((FLMUINT *)Value1) = - (FLMUINT)((uiLastCPFile < uiLastTransFile - ? uiLastCPFile - : uiLastTransFile) - 1); - break; - } - - case FDB_GET_RFL_FILE_SIZE_LIMITS: - if (Value1) - { - *((FLMUINT *)Value1) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); - } - if (Value2) - { - if (pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - *((FLMUINT *)Value2) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]); - } - else - { - *((FLMUINT *)Value2) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); - } - } - break; - - case FDB_GET_RFL_KEEP_FLAG: - *((FLMBOOL *)Value1) = - pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_RFL_FILES] - ? TRUE - : FALSE; - break; - - case FDB_GET_LAST_BACKUP_TRANS_ID: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - *((FLMUINT *)Value1) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr [LOG_LAST_BACKUP_TRANS_ID]); - break; - - case FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - *((FLMUINT *)Value1) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr[ LOG_BLK_CHG_SINCE_BACKUP]); - break; - - case FDB_GET_SERIAL_NUMBER: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - f_mutexLock( gv_FlmSysData.hShareMutex); - f_memcpy( (FLMBYTE *)Value1, - &pDb->pFile->ucLastCommittedLogHdr [LOG_DB_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - break; - - case FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - *((FLMBOOL *)Value1) = FALSE; - } - else - { - *((FLMBOOL *)Value1) = - pDb->pFile->ucUncommittedLogHdr [LOG_AUTO_TURN_OFF_KEEP_RFL] - ? TRUE - : FALSE; - } - break; - - case FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - *((FLMBOOL *)Value1) = FALSE; - } - else - { - *((FLMBOOL *)Value1) = - pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL] - ? TRUE - : FALSE; - } - break; - - case FDB_GET_SIZES: - rc = flmDbGetSizes( pDb, (FLMUINT64 *)Value1, (FLMUINT64 *)Value2, - (FLMUINT64 *)Value3); - break; - - case FDB_GET_FILE_EXTEND_SIZE: - *((FLMUINT *)Value1) = pDb->pFile->uiFileExtendSize; - break; - - case FDB_GET_APP_DATA: - *((void **)Value1) = pDb->pvAppData; - break; - - case FDB_GET_NEXT_INC_BACKUP_SEQ_NUM: - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - *((FLMUINT *)Value1) = (FLMUINT)FB2UD( - &pDb->pFile->ucUncommittedLogHdr[ LOG_INC_BACKUP_SEQ_NUM]); - break; - - case FDB_GET_DICT_SEQ_NUM: - if( pDb->pDict) - { - *((FLMUINT *)Value1) = pDb->pDict->uiDictSeq; - } - else - { - *((FLMUINT *)Value1) = pDb->pFile->pDictList->uiDictSeq; - } - break; - case FDB_GET_FFILE_ID: - *((FLMUINT *)Value1) = pDb->pFile->uiFFileId; - break; - case FDB_GET_MUST_CLOSE_RC: - *((RCODE *)Value1) = pDb->pFile->rcMustClose; - break; - default: - rc = RC_SET( FERR_NOT_IMPLEMENTED); - break; - } - -Exit: - - if( bStartedTrans) - { - flmAbortDbTrans( pDb); - } - - if( bDbInitialized) - { - fdbExit( pDb); - } - - return( rc); -} - -/**************************************************************************** -Desc: Retrieves the Checkpoint info for the pFile passed in. This assumes the - hShareMutex has already been locked. -*****************************************************************************/ -void flmGetCPInfo( - void * pFilePtr, - CHECKPOINT_INFO * pCheckpointInfo - ) -{ - FFILE * pFile; - FLMUINT uiElapTime; - FLMUINT uiCurrTime; - - flmAssert( pFilePtr); - flmAssert( pCheckpointInfo); - - pFile = (FFILE *)pFilePtr; - - f_memset( pCheckpointInfo, 0, sizeof( CHECKPOINT_INFO)); - if (pFile->pCPInfo) - { - pCheckpointInfo->bRunning = pFile->pCPInfo->bDoingCheckpoint; - if (pCheckpointInfo->bRunning) - { - if (pFile->pCPInfo->uiStartTime) - { - uiCurrTime = FLM_GET_TIMER(); - - uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, - pFile->pCPInfo->uiStartTime); - FLM_TIMER_UNITS_TO_MILLI( uiElapTime, pCheckpointInfo->uiRunningTime); - } - else - { - pCheckpointInfo->uiRunningTime = 0; - } - pCheckpointInfo->bForcingCheckpoint = - pFile->pCPInfo->bForcingCheckpoint; - if (pFile->pCPInfo->uiForceCheckpointStartTime) - { - uiCurrTime = FLM_GET_TIMER(); - uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, - pFile->pCPInfo->uiForceCheckpointStartTime); - FLM_TIMER_UNITS_TO_MILLI( uiElapTime, - pCheckpointInfo->uiForceCheckpointRunningTime); - } - else - { - pCheckpointInfo->uiForceCheckpointRunningTime = 0; - } - pCheckpointInfo->iForceCheckpointReason = - pFile->pCPInfo->iForceCheckpointReason; - pCheckpointInfo->bWritingDataBlocks = - pFile->pCPInfo->bWritingDataBlocks; - pCheckpointInfo->uiLogBlocksWritten = - pFile->pCPInfo->uiLogBlocksWritten; - pCheckpointInfo->uiDataBlocksWritten = - pFile->pCPInfo->uiDataBlocksWritten; - } - pCheckpointInfo->uiBlockSize = - (FLMUINT)pFile->FileHdr.uiBlockSize; - pCheckpointInfo->uiDirtyCacheBytes = - pFile->uiDirtyCacheCount * pFile->FileHdr.uiBlockSize; - if (pFile->pCPInfo->uiStartWaitTruncateTime) - { - uiCurrTime = FLM_GET_TIMER(); - - uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, - pFile->pCPInfo->uiStartWaitTruncateTime); - FLM_TIMER_UNITS_TO_MILLI( uiElapTime, - pCheckpointInfo->uiWaitTruncateTime); - } - else - { - pCheckpointInfo->uiWaitTruncateTime = 0; - } - } -} +//------------------------------------------------------------------------- +// Desc: Routines for database configuration. +// Tabs: 3 +// +// Copyright (c) 1996-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fdbcnfig.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC RCODE flmDbGetSizes( + FDB * pDb, + FLMUINT64 * pui64DbFileSize, + FLMUINT64 * pui64RollbackFileSize, + FLMUINT64 * pui64RflFileSize); + +void flmGetCPInfo( + void * pFilePtr, + CHECKPOINT_INFO * pCheckpointInfo); + +/******************************************************************************* +Desc: Sets indexing callback function +*******************************************************************************/ +FLMEXP void FLMAPI FlmSetIndexingCallback( + HFDB hDb, + IX_CALLBACK fnIxCallback, + void * pvAppData) +{ + ((FDB *)hDb)->fnIxCallback = fnIxCallback; + ((FDB *)hDb)->IxCallbackData = pvAppData; +} + +/******************************************************************************* +Desc: Returns indexing callback function +*******************************************************************************/ +FLMEXP void FLMAPI FlmGetIndexingCallback( + HFDB hDb, + IX_CALLBACK * pfnIxCallback, + void ** ppvAppData) +{ + if (pfnIxCallback) + { + *pfnIxCallback = ((FDB *)hDb)->fnIxCallback; + } + + if (ppvAppData) + { + *ppvAppData = ((FDB *)hDb)->IxCallbackData; + } +} + +/******************************************************************************* +Desc : Configures a callback function which allows validation of records + before they are returned to the user or committed to the + database. +Notes: This function stores a pointer to a callback function which is + called whenever a record is added, deleted, modified or + retrieved. This allows an application to validate record operations + before they are committed to the database (update operations) + or before records are returned to the application (read operations). + By default, no record validation is performed by FLAIM. +*******************************************************************************/ +FLMEXP void FLMAPI FlmSetRecValidatorHook( + HFDB hDb, + REC_VALIDATOR_HOOK fnRecValidatorHook, + void * pvAppData) +{ + ((FDB *)hDb)->fnRecValidator = fnRecValidatorHook; + ((FDB *)hDb)->RecValData = pvAppData; +} + +/******************************************************************************* +Desc : Returns to the user the sessions current Rec Validator Hook values. +*******************************************************************************/ +FLMEXP void FLMAPI FlmGetRecValidatorHook( + HFDB hDb, + REC_VALIDATOR_HOOK * pfnRecValidatorHook, // [out] RecValidator func pointer + void ** ppvAppData) // [out] application data +{ + if (pfnRecValidatorHook) + { + *pfnRecValidatorHook = ((FDB *)hDb)->fnRecValidator; + } + + if (ppvAppData) + { + *ppvAppData = ((FDB *)hDb)->RecValData; + } +} + +/******************************************************************************* +Desc : Configures a callback function which is called to return general + purpose information. +*******************************************************************************/ +FLMEXP void FLMAPI FlmSetStatusHook( + HFDB hDb, + STATUS_HOOK fnStatusHook, + void * pvAppData) +{ + ((FDB *)hDb)->fnStatus = fnStatusHook; + ((FDB *)hDb)->StatusData = pvAppData; +} + +/******************************************************************************* +Desc : Returns to the user the session's current status hook values. +*******************************************************************************/ +FLMEXP void FLMAPI FlmGetStatusHook( + HFDB hDb, + STATUS_HOOK * pfnStatusHook, + void ** ppvAppData) +{ + if (pfnStatusHook) + { + *pfnStatusHook = ((FDB *)hDb)->fnStatus; + } + + if (ppvAppData) + { + *ppvAppData = ((FDB *)hDb)->StatusData; + } +} + +/******************************************************************************* +Desc: Allows an application to configure various options for a database. +*******************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbConfig( + HFDB hDb, + eDbConfigType eConfigType, + void * pvValue1, + void * pvValue2) +{ + RCODE rc = FERR_OK; + FDB * pDb = (FDB *)hDb; + FFILE * pFile = pDb->pFile; + LFILE * pLFile; + FLMBOOL bDbInitialized = FALSE; + FLMBOOL bStartedTrans = FALSE; + FLMBOOL bDbLocked = FALSE; + + // Process the client/server request + + if( IsInCSMode( hDb)) + { + fdbInitCS( pDb); + bDbInitialized = TRUE; + + CS_CONTEXT * pCSContext = pDb->pCSContext; + FCL_WIRE Wire( pCSContext, pDb); + + if( !pCSContext->bConnectionGood) + { + rc = RC_SET( FERR_BAD_SERVER_CONNECTION); + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendOp( + FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_CONFIG))) + { + goto Exit; + } + + if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TYPE, (FLMUINT)eConfigType))) + { + goto Transmission_Error; + } + + switch( eConfigType) + { + case FDB_SET_APP_VERSION: + case FDB_RFL_KEEP_FILES: + case FDB_KEEP_ABORTED_TRANS_IN_RFL: + case FDB_AUTO_TURN_OFF_KEEP_RFL: + case FDB_SET_APP_DATA: + { + if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER2, + (FLMUINT)pvValue1))) + { + goto Transmission_Error; + } + break; + } + + case FDB_RFL_DIR: + { + FLMUNICODE * puzRflDir; + + if( RC_BAD( rc = fcsConvertNativeToUnicode( + Wire.getPool(), (const char *)pvValue1, &puzRflDir))) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendString( + WIRE_VALUE_FILE_PATH, puzRflDir))) + { + goto Transmission_Error; + } + break; + } + + case FDB_RFL_FILE_LIMITS: + { + if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, + (FLMUINT)pvValue1))) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER2, + (FLMUINT)pvValue2))) + { + goto Transmission_Error; + } + break; + } + + case FDB_FILE_EXTEND_SIZE: + { + if( RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, + (FLMUINT)pvValue1))) + { + goto Transmission_Error; + } + break; + } + + case FDB_RFL_ROLL_TO_NEXT_FILE: + { + break; + } + + default: + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + } + + if( RC_BAD( rc = Wire.sendTerminate())) + { + goto Transmission_Error; + } + + // Read the response + + if (RC_BAD( rc = Wire.read())) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.getRCode())) + { + goto Exit; + } + + goto Exit; + +Transmission_Error: + + pCSContext->bConnectionGood = FALSE; + goto Exit; + } + + // See if the database is being forced to close + + if( RC_BAD( rc = flmCheckDatabaseState( pDb))) + { + goto Exit; + } + + // Process the local (non-C/S) request + + switch( eConfigType) + { + case FDB_RFL_KEEP_FILES: + { + FLMBOOL bKeepFiles = (FLMBOOL)(pvValue1 ? TRUE : FALSE); + + // This operation is not legal for pre 4.3 databases. + + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Make sure we don't have a transaction going + + if( pDb->uiTransType != FLM_NO_TRANS) + { + rc = RC_SET( FERR_TRANS_ACTIVE); + goto Exit; + } + + // Make sure there is no active backup running + + f_mutexLock( gv_FlmSysData.hShareMutex); + if( pFile->bBackupActive) + { + f_mutexUnlock( gv_FlmSysData.hShareMutex); + rc = RC_SET( FERR_BACKUP_ACTIVE); + goto Exit; + } + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + // Need to lock the database but not start a transaction yet. + + if( !(pDb->uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) + { + if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, + FLM_NO_TIMEOUT))) + { + goto Exit; + } + + bDbLocked = TRUE; + } + + // If we aren't changing the keep flag, jump to exit without doing + // anything. + + if ((bKeepFiles && + pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES]) || + (!bKeepFiles && + !pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES])) + { + goto Exit; // Will return FERR_OK; + } + + // Force a checkpoint and roll to the next RFL file numbers. + // When changing from keep to no-keep or vice versa, we need to + // go to a new RFL file so that the new RFL file gets new + // serial numbers and a new keep or no-keep flag. + + if (RC_BAD( rc = FlmDbCheckpoint( hDb, FLM_NO_TIMEOUT))) + { + goto Exit; + } + + f_memcpy( pFile->ucUncommittedLogHdr, + pFile->ucLastCommittedLogHdr, + LOG_HEADER_SIZE); + pFile->ucUncommittedLogHdr [LOG_KEEP_RFL_FILES] = + (FLMBYTE)((bKeepFiles) ? (FLMBYTE)1 : (FLMBYTE)0); + + // Force a new RFL file - this will also write out the entire + // log header - including the changes we made above. + + if (RC_BAD( rc = pFile->pRfl->finishCurrFile( pDb, TRUE))) + { + goto Exit; + } + + // Update the RFL size + + if( bKeepFiles) + { + FLMUINT64 ui64RflDiskUsage; + + if( RC_BAD( rc = flmRflCalcDiskUsage( + pFile->pRfl->getRflDirPtr(), pFile->pRfl->getDbPrefixPtr(), + pFile->FileHdr.uiVersionNum, &ui64RflDiskUsage))) + { + goto Exit; + } + + f_mutexLock( gv_FlmSysData.hShareMutex); + pFile->ui64RflDiskUsage = ui64RflDiskUsage; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + } + + break; + } + + case FDB_RFL_DIR: + { + const char * pszNewRflDir = (const char *)pvValue1; + + // This operation is not legal for pre 4.3 databases. + + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Make sure we don't have a transaction going + + if( pDb->uiTransType != FLM_NO_TRANS) + { + rc = RC_SET( FERR_TRANS_ACTIVE); + goto Exit; + } + + // Make sure there is no active backup running + + f_mutexLock( gv_FlmSysData.hShareMutex); + if( pFile->bBackupActive) + { + f_mutexUnlock( gv_FlmSysData.hShareMutex); + rc = RC_SET( FERR_BACKUP_ACTIVE); + goto Exit; + } + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + // Make sure the path exists and that it is a directory + // rather than a file. + + if (pszNewRflDir && *pszNewRflDir) + { + if( !gv_FlmSysData.pFileSystem->IsDir( pszNewRflDir)) + { + rc = RC_SET( FERR_IO_INVALID_PATH); + goto Exit; + } + } + + // Need to lock the database because we can't change the RFL + // directory until after the checkpoint has completed. The + // checkpoint code will unlock the transaction, but not the + // file if we have an explicit lock. We need to do this to + // prevent another transaction from beginning before we have + // changed the RFL directory. + + if( !(pDb->uiFlags & (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED))) + { + if( RC_BAD( rc = FlmDbLock( hDb, FLM_LOCK_EXCLUSIVE, 0, + FLM_NO_TIMEOUT))) + { + goto Exit; + } + bDbLocked = TRUE; + } + + // Force a checkpoint and roll to the next RFL file numbers. Both + // of these steps are necessary to ensure that we won't have to do + // any recovery using the current RFL file - because we do not + // move the current RFL file to the new directory. Forcing the + // checkpoint ensures that we have no transactions that will need + // to be recovered if we were to crash. Rolling the RFL file number + // ensures that no more transactions will be logged to the current + // RFL file. + + if (RC_BAD( rc = FlmDbCheckpoint( hDb, FLM_NO_TIMEOUT))) + { + goto Exit; + } + + // Force a new RFL file. + + if (RC_BAD( rc = pFile->pRfl->finishCurrFile( pDb, FALSE))) + { + goto Exit; + } + + // Set the RFL directory to the new value now that we have + // finished the checkpoint and rolled to the next RFL file. + + f_mutexLock( gv_FlmSysData.hShareMutex); + rc = pFile->pRfl->setRflDir( pszNewRflDir); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + break; + } + + case FDB_RFL_FILE_LIMITS: + { + FLMUINT uiMinRflSize = (FLMUINT)pvValue1; + FLMUINT uiMaxRflSize = (FLMUINT)pvValue2; + + // Make sure the limits are valid. + + if (pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + + // Maximum must be enough to hold at least one packet plus + // the RFL header. Minimum must not be greater than the + // maximum. NOTE: Minimum and maximum are allowed to be + // equal, but in all cases, maximum takes precedence over + // minimum. We will first NOT exceed the maximum. Then, + // if possible, we will go above the minimum. + + if (uiMaxRflSize < RFL_MAX_PACKET_SIZE + 512) + { + uiMaxRflSize = RFL_MAX_PACKET_SIZE + 512; + } + if (uiMaxRflSize > gv_FlmSysData.uiMaxFileSize) + { + uiMaxRflSize = gv_FlmSysData.uiMaxFileSize; + } + if (uiMinRflSize > uiMaxRflSize) + { + uiMinRflSize = uiMaxRflSize; + } + } + + // Start an update transaction. Must not already be one going. + + bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, + 0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS, + &bStartedTrans))) + { + goto Exit; + } + + // Commit the transaction. + + UD2FBA( (FLMUINT32)uiMinRflSize, + &pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); + if (pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + UD2FBA( (FLMUINT32)uiMaxRflSize, + &pFile->ucUncommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]); + } + if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) + { + goto Exit; + } + bStartedTrans = FALSE; + break; + } + + case FDB_RFL_ROLL_TO_NEXT_FILE: + { + // This operation is not legal for pre 4.3 databases. + + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // NOTE: finishCurrFile will not roll to the next file if the current + // file has not been created. + + if (RC_BAD( rc = pFile->pRfl->finishCurrFile( pDb, FALSE))) + { + goto Exit; + } + break; + } + + case FDB_SET_APP_VERSION: + { + FLMUINT uiOldMajorVer; + FLMUINT uiOldMinorVer; + + // Start an update transaction. + + bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, + 0, 5 | FLM_AUTO_TRANS, &bStartedTrans))) + { + goto Exit; + } + + // Set the version. + + f_mutexLock( gv_FlmSysData.hShareMutex); + uiOldMajorVer = pFile->FileHdr.uiAppMajorVer; + pFile->FileHdr.uiAppMajorVer = (FLMUINT)pvValue1; + uiOldMinorVer = pFile->FileHdr.uiAppMinorVer; + pFile->FileHdr.uiAppMinorVer = (FLMUINT)pvValue2; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + // Commit the transaction. NOTE: This will always cause + // us to write out the application version numbers, because + // we always write out the prefix - first 512 bytes. + + if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) + { + // Undo the changes made above + + f_mutexLock( gv_FlmSysData.hShareMutex); + pFile->FileHdr.uiAppMajorVer = uiOldMajorVer; + pFile->FileHdr.uiAppMinorVer = uiOldMinorVer; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + goto Exit; + } + bStartedTrans = FALSE; + break; + } + + case FDB_KEEP_ABORTED_TRANS_IN_RFL: + case FDB_AUTO_TURN_OFF_KEEP_RFL: + { + + // These operations are not legal for pre 4.3 databases. + + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Start an update transaction. Must not already be one going. + + bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, + 0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS, + &bStartedTrans))) + { + goto Exit; + } + + // Change the uncommitted log header + + if (eConfigType == FDB_KEEP_ABORTED_TRANS_IN_RFL) + { + pFile->ucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL] = + (FLMBYTE)(pvValue1 + ? (FLMBYTE)1 + : (FLMBYTE)0); + } + else + { + pFile->ucUncommittedLogHdr [LOG_AUTO_TURN_OFF_KEEP_RFL] = + (FLMBYTE)(pvValue1 + ? (FLMBYTE)1 + : (FLMBYTE)0); + } + + // Commit the transaction. + + if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) + { + goto Exit; + } + bStartedTrans = FALSE; + break; + } + + case FDB_FILE_EXTEND_SIZE: + { + pFile->uiFileExtendSize = (FLMUINT)pvValue1; + break; + } + + case FDB_SET_APP_DATA: + { + pDb->pvAppData = pvValue1; + break; + } + + case FDB_SET_COMMIT_CALLBACK: + { + pDb->fnCommit = (COMMIT_FUNC)((FLMUINT)pvValue1); + pDb->pvCommitData = pvValue2; + break; + } + + case FDB_SET_RFL_SIZE_THRESHOLD: + { + if( RC_BAD( rc = flmSetRflSizeThreshold( hDb, (FLMUINT)pvValue1, + FLM_MAX_UINT, FLM_MAX_UINT))) + { + goto Exit; + } + + break; + } + + case FDB_SET_RFL_SIZE_EVENT_INTERVALS: + { + FLMUINT uiTimeInterval = (FLMUINT)pvValue1; + FLMUINT uiSizeInterval = (FLMUINT)pvValue2; + + if( RC_BAD( rc = flmSetRflSizeThreshold( hDb, FLM_MAX_UINT, + uiTimeInterval, uiSizeInterval))) + { + goto Exit; + } + + break; + } + + case FDB_ENABLE_FIELD_ID_TABLE: + { + if (pDb->pDict) + { + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, (FLMUINT)pvValue1, + &pLFile))) + { + goto Exit; + } + pLFile->bMakeFieldIdTable = (FLMBOOL)pvValue2; + } + else if (pDb->pFile->pDictList) + { + if (RC_BAD( rc = fdictGetContainer( pDb->pFile->pDictList, + (FLMUINT)pvValue1, &pLFile))) + { + goto Exit; + } + pLFile->bMakeFieldIdTable = (FLMBOOL)pvValue2; + } + break; + } + + default: + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + } + +Exit: + + if( bStartedTrans) + { + flmAbortDbTrans( pDb); + } + + if( bDbLocked) + { + FlmDbUnlock( hDb); + } + + if( bDbInitialized) + { + fdbExit( pDb); + } + + return( rc); +} + +/**************************************************************************** +Desc: Returns database, rollback, and rollforward sizes. We are guaranteed + to be inside an update transaction at this point. +****************************************************************************/ +FSTATIC RCODE flmDbGetSizes( + FDB * pDb, + FLMUINT64 * pui64DbFileSize, + FLMUINT64 * pui64RollbackFileSize, + FLMUINT64 * pui64RflFileSize) +{ + RCODE rc = FERR_OK; + FFILE * pFile = pDb->pFile; + FLMUINT uiDbVersion = pFile->FileHdr.uiVersionNum; + FLMUINT uiEndAddress; + FLMUINT uiLastFileNumber; + FLMUINT uiLastFileSize; + char szTmpName[ F_PATH_MAX_SIZE]; + char szRflDir[ F_PATH_MAX_SIZE]; + char szPrefix[ F_FILENAME_SIZE]; + F_FileHdlImp * pFileHdl = NULL; + F_DirHdl * pDirHdl = NULL; + + // Better be inside an update transaction at this point. + + flmAssert( pDb->uiTransType == FLM_UPDATE_TRANS); + + // See if they want the database files sizes. + + if (pui64DbFileSize) + { + uiEndAddress = pDb->LogHdr.uiLogicalEOF; + uiLastFileNumber = FSGetFileNumber( uiEndAddress); + + // Last file number better be in the proper range. + + flmAssert( uiLastFileNumber >= 1 && + uiLastFileNumber <= MAX_DATA_BLOCK_FILE_NUMBER( uiDbVersion)); + + // Get the actual size of the last file. + + if (RC_BAD( rc = pDb->pSFileHdl->GetFileSize( uiLastFileNumber, + &uiLastFileSize))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || + rc == FERR_IO_INVALID_PATH) + { + if (uiLastFileNumber > 1) + { + rc = FERR_OK; + uiLastFileSize = 0; + } + else + { + + // Should always be a data file #1 + + flmAssert( 0); + goto Exit; + } + } + else + { + goto Exit; + } + } + + // One of two situations exists with respect to the last + // file: 1) it has not been fully written out yet (blocks + // are still cached, or 2) it has been written out and + // extended beyond what the logical EOF shows. We want + // the larger of these two possibilities. + + if (FSGetFileOffset( uiEndAddress) > uiLastFileSize) + { + uiLastFileSize = FSGetFileOffset( uiEndAddress); + } + + if (uiLastFileNumber == 1) + { + + // Only one file - use last file's size. + + *pui64DbFileSize = (FLMUINT64)uiLastFileSize; + } + else + { + + // Size is the sum of full size for all files except the last one, + // plus the calculated (or actual) size of the last one. + + (*pui64DbFileSize) = (FLMUINT64)(uiLastFileNumber - 1) * + (FLMUINT64)pFile->uiMaxFileSize + + (FLMUINT64)uiLastFileSize; + } + } + + // See if they want the rollback files sizes. + + if (pui64RollbackFileSize) + { + uiEndAddress = (FLMUINT)FB2UD( + &pFile->ucUncommittedLogHdr [LOG_ROLLBACK_EOF]); + uiLastFileNumber = FSGetFileNumber( uiEndAddress); + + // Last file number better be in the proper range. + + flmAssert( !uiLastFileNumber || + (uiLastFileNumber >= + FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion) && + uiLastFileNumber <= + MAX_LOG_BLOCK_FILE_NUMBER( uiDbVersion))); + + // Get the size of the last file number. + + if (RC_BAD( rc = pDb->pSFileHdl->GetFileSize( uiLastFileNumber, + &uiLastFileSize))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || + rc == FERR_IO_INVALID_PATH) + { + if (uiLastFileNumber) + { + rc = FERR_OK; + uiLastFileSize = 0; + } + else + { + + // Should always have rollback file #0 + + flmAssert( 0); + goto Exit; + } + } + else + { + goto Exit; + } + } + + // If the EOF offset for the last file is greater than the + // actual file size, use it instead of the actual file size. + + if (FSGetFileOffset( uiEndAddress) > uiLastFileSize) + { + uiLastFileSize = FSGetFileOffset( uiEndAddress); + } + + // Special case handling here because rollback file numbers start with + // zero and then skip to a file number that is one beyond the + // highest data file number - so the calculation for file size needs + // to account for this. + + if (!uiLastFileNumber) + { + *pui64RollbackFileSize = (FLMUINT64)uiLastFileSize; + } + else + { + FLMUINT uiFirstLogFileNum = + FIRST_LOG_BLOCK_FILE_NUMBER( uiDbVersion); + + // Add full size of file zero plus a full size for every file + // except the last one. + + (*pui64RollbackFileSize) = (FLMUINT64)(uiLastFileNumber - + uiFirstLogFileNum + 1) * + (FLMUINT64)pFile->uiMaxFileSize + + (FLMUINT64)uiLastFileSize; + } + } + + // See if they want the roll-forward log file sizes. + + if (pui64RflFileSize) + { + char * pszDbFileName = pFile->pszDbPath; + + *pui64RflFileSize = 0; + if (uiDbVersion < FLM_FILE_FORMAT_VER_4_3) + { + + // For pre-4.3 versions, only need to get the size for one + // RFL file. + + if (RC_BAD( rc = rflGetFileName( uiDbVersion, pszDbFileName, + NULL, 1, szTmpName))) + { + goto Exit; + } + + // Open the file and get its size. + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( szTmpName, + F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, + 512, &pFileHdl))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) + { + rc = FERR_OK; + uiLastFileSize = 0; + } + else + { + goto Exit; + } + } + else + { + if (RC_BAD( rc = pFileHdl->Size( &uiLastFileSize))) + { + goto Exit; + } + } + if (pFileHdl) + { + pFileHdl->Release(); + pFileHdl = NULL; + } + *pui64RflFileSize = (FLMUINT64)uiLastFileSize; + } + else + { + + // For 4.3 and greater, need to scan the RFL directory for + // RFL files. The call below to rflGetDirAndPrefix is done + // to get the prefix. It will not return the correct + // RFL directory name, because we are passing in a NULL + // RFL directory path (which may or may not be correct). + // That's OK, because we get the RFL directory directly + // from the F_Rfl object anyway. + + if (RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDbFileName, + NULL, szRflDir, szPrefix))) + { + goto Exit; + } + + // We need to get the RFL directory from the F_Rfl object. + + f_strcpy( szRflDir, pFile->pRfl->getRflDirPtr()); + + // See if the directory exists. If not, we are done. + + if (gv_FlmSysData.pFileSystem->IsDir( szRflDir)) + { + + // Open the directory and scan for RFL files. + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenDir( + szRflDir, "*", &pDirHdl))) + { + goto Exit; + } + for (;;) + { + if (RC_BAD( rc = pDirHdl->Next())) + { + if (rc == FERR_IO_NO_MORE_FILES) + { + rc = FERR_OK; + break; + } + else + { + goto Exit; + } + } + pDirHdl->CurrentItemPath( szTmpName); + + // If the item looks like an RFL file name, get + // its size. + + if (!pDirHdl->CurrentItemIsDir() && + rflGetFileNum( uiDbVersion, szPrefix, szTmpName, + &uiLastFileNumber)) + { + + // Open the file and get its size. + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( + szTmpName, + F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, + 512, &pFileHdl))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || + rc == FERR_IO_INVALID_PATH) + { + rc = FERR_OK; + uiLastFileSize = 0; + } + else + { + goto Exit; + } + } + else + { + if (RC_BAD( rc = pFileHdl->Size( &uiLastFileSize))) + { + goto Exit; + } + } + if (pFileHdl) + { + pFileHdl->Release(); + pFileHdl = NULL; + } + (*pui64RflFileSize) += (FLMUINT64)uiLastFileSize; + } + } + } + } + } + +Exit: + if (pFileHdl) + { + pFileHdl->Release(); + } + if (pDirHdl) + { + pDirHdl->Release(); + } + return( rc); +} + +/******************************************************************************* +Desc: Returns information about a particular database. +*******************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbGetConfig( + HFDB hDb, + eDbGetConfigType eGetConfigType, + void * pvValue1, + void * pvValue2, + void * pvValue3) +{ + RCODE rc = FERR_OK; + FDB * pDb = (FDB *)hDb; + FFILE * pFile = pDb->pFile; + FLMBOOL bDbInitialized = FALSE; + FLMBOOL bStartedTrans = FALSE; + FLMUINT uiTransType = FLM_NO_TRANS; + CHECKPOINT_INFO * pCheckpointInfo; + + if( IsInCSMode( hDb)) + { + fdbInitCS( pDb); + bDbInitialized = TRUE; + + CS_CONTEXT * pCSContext = pDb->pCSContext; + FCL_WIRE Wire( pCSContext, pDb); + CREATE_OPTS createOpts; + + if( !pCSContext->bConnectionGood) + { + rc = RC_SET( FERR_BAD_SERVER_CONNECTION); + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendOp( + FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_CONFIG))) + { + goto Exit; + } + + if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TYPE, (FLMUINT)eGetConfigType))) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendTerminate())) + { + goto Transmission_Error; + } + + // Read the response + + if (RC_BAD( rc = Wire.read())) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.getRCode())) + { + goto Exit; + } + + switch( eGetConfigType) + { + case FDB_GET_VERSION: + { + Wire.copyCreateOpts( &createOpts); + *((FLMUINT *)pvValue1) = createOpts.uiVersionNum; + break; + } + + case FDB_GET_BLKSIZ: + { + Wire.copyCreateOpts( &createOpts); + *((FLMUINT *)pvValue1) = createOpts.uiBlockSize; + break; + } + + case FDB_GET_DEFAULT_LANG: + { + Wire.copyCreateOpts( &createOpts); + *((FLMUINT *)pvValue1) = createOpts.uiDefaultLanguage; + break; + } + + case FDB_GET_PATH: + case FDB_GET_RFL_DIR: + { + char * pszPath; + POOL * pPool = Wire.getPool(); + void * pvMark = GedPoolMark( pPool); + + if( RC_BAD( rc = fcsConvertUnicodeToNative( pPool, + (FLMUNICODE *)Wire.getFilePath(), &pszPath))) + { + goto Exit; + } + f_strcpy( (char *)pvValue1, pszPath); + GedPoolReset( pPool, pvMark); + break; + } + + case FDB_GET_TRANS_ID: + case FDB_GET_RFL_FILE_NUM: + case FDB_GET_RFL_HIGHEST_NU: + case FDB_GET_LAST_BACKUP_TRANS_ID: + case FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP: + case FDB_GET_FILE_EXTEND_SIZE: + case FDB_GET_APP_DATA: + case FDB_GET_NEXT_INC_BACKUP_SEQ_NUM: + case FDB_GET_DICT_SEQ_NUM: + case FDB_GET_FFILE_ID: + case FDB_GET_MUST_CLOSE_RC: + { + *((FLMUINT *)pvValue1) = (FLMUINT)Wire.getNumber1(); + break; + } + + case FDB_GET_RFL_FILE_SIZE_LIMITS: + { + if (pvValue1) + { + *((FLMUINT *)pvValue1) = (FLMUINT)Wire.getNumber1(); + } + + if (pvValue2) + { + *((FLMUINT *)pvValue2) = (FLMUINT)Wire.getNumber2(); + } + + break; + } + + case FDB_GET_RFL_KEEP_FLAG: + case FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG: + case FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG: + { + *((FLMBOOL *)pvValue1) = Wire.getBoolean(); + break; + } + + case FDB_GET_CHECKPOINT_INFO: + { + rc = fcsExtractCheckpointInfo( Wire.getHTD(), (CHECKPOINT_INFO *)pvValue1); + break; + } + + case FDB_GET_LOCK_HOLDER: + { + rc = fcsExtractLockUser( Wire.getHTD(), FALSE, ((LOCK_USER *)pvValue1)); + break; + } + + case FDB_GET_LOCK_WAITERS: + { + rc = fcsExtractLockUser( Wire.getHTD(), TRUE, ((void *)pvValue1)); + break; + } + + case FDB_GET_SERIAL_NUMBER: + { + f_memcpy( (FLMBYTE *)pvValue1, + Wire.getSerialNum(), F_SERIAL_NUM_SIZE); + break; + } + + case FDB_GET_SIZES: + { + if (pvValue1) + { + *((FLMUINT64 *)pvValue1) = (FLMUINT64)Wire.getNumber1(); + } + + if (pvValue2) + { + *((FLMUINT64 *)pvValue2) = (FLMUINT64)Wire.getNumber2(); + } + + if (pvValue3) + { + *((FLMUINT64 *)pvValue3) = (FLMUINT64)Wire.getNumber3(); + } + + break; + } + + default: + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + break; + } + } + + goto Exit; + +Transmission_Error: + + pCSContext->bConnectionGood = FALSE; + goto Exit; + } + + if (eGetConfigType == FDB_GET_RFL_FILE_NUM || + eGetConfigType == FDB_GET_RFL_HIGHEST_NU || + eGetConfigType == FDB_GET_RFL_FILE_SIZE_LIMITS || + eGetConfigType == FDB_GET_RFL_KEEP_FLAG || + eGetConfigType == FDB_GET_LAST_BACKUP_TRANS_ID || + eGetConfigType == FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP || + eGetConfigType == FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG || + eGetConfigType == FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG || + eGetConfigType == FDB_GET_SIZES || + eGetConfigType == FDB_GET_NEXT_INC_BACKUP_SEQ_NUM) + { + uiTransType = FLM_UPDATE_TRANS; + } + + bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, uiTransType, + FDB_TRANS_GOING_OK | FDB_DONT_RESET_DIAG, + FLM_NO_TIMEOUT | FLM_AUTO_TRANS, &bStartedTrans))) + { + goto Exit; + } + + switch( eGetConfigType) + { + case FDB_GET_VERSION: + { + *((FLMUINT *)pvValue1) = pFile->FileHdr.uiVersionNum; + break; + } + + case FDB_GET_BLKSIZ: + { + *((FLMUINT *)pvValue1) = pFile->FileHdr.uiBlockSize; + break; + } + + case FDB_GET_DEFAULT_LANG: + { + *((FLMUINT *)pvValue1) = pFile->FileHdr.uiDefaultLanguage; + break; + } + + case FDB_GET_PATH: + { + if( RC_BAD( rc = flmGetFilePath( pFile, ((char *)pvValue1)))) + { + goto Exit; + } + break; + } + + case FDB_GET_TRANS_ID: + { + if (pDb->uiTransType != FLM_NO_TRANS) + { + *((FLMUINT *)pvValue1) = pDb->LogHdr.uiCurrTransID; + } + else if (pDb->uiFlags & FDB_HAS_FILE_LOCK) + { + + // Get last committed value. + + *((FLMUINT *)pvValue1) = + FB2UD( &pFile->ucLastCommittedLogHdr [LOG_CURR_TRANS_ID]); + } + else + { + *((FLMUINT *)pvValue1) = 0; + } + break; + } + + case FDB_GET_CHECKPOINT_INFO: + { + pCheckpointInfo = (CHECKPOINT_INFO *)pvValue1; + f_mutexLock( gv_FlmSysData.hShareMutex); + flmGetCPInfo( pFile, pCheckpointInfo); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + break; + } + + case FDB_GET_LOCK_HOLDER: + { + if (pFile->pFileLockObj) + { + rc = pFile->pFileLockObj->GetLockInfo( FALSE, (void *)pvValue1); + } + else + { + ((LOCK_USER *)pvValue1)->uiThreadId = 0; + ((LOCK_USER *)pvValue1)->uiTime = 0; + } + break; + } + + case FDB_GET_LOCK_WAITERS: + { + if (pFile->pFileLockObj) + { + rc = pFile->pFileLockObj->GetLockInfo( TRUE, (void *)pvValue1); + } + else + { + *((LOCK_USER **)pvValue1) = NULL; + } + break; + } + + case FDB_GET_LOCK_WAITERS_EX: + { + FlmLockInfo * pLockInfo = (FlmLockInfo *)pvValue1; + + if (pFile->pFileLockObj) + { + rc = pFile->pFileLockObj->GetLockInfo( pLockInfo); + } + else + { + pLockInfo->setLockCount( 0); + } + break; + } + + case FDB_GET_RFL_DIR: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + + f_mutexLock( gv_FlmSysData.hShareMutex); + f_strcpy( (char *)pvValue1, pDb->pFile->pRfl->getRflDirPtr()); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + break; + } + + case FDB_GET_RFL_FILE_NUM: + { + FLMUINT uiLastCPFile; + FLMUINT uiLastTransFile; + + // Get the CP and last trans RFL file numbers. Need to + // return the higher of the two. No need to lock the + // mutex because we are in an update transaction. + + uiLastCPFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ + LOG_RFL_LAST_CP_FILE_NUM]); + + uiLastTransFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ + LOG_RFL_FILE_NUM]); + + *((FLMUINT *)pvValue1) = uiLastCPFile > uiLastTransFile + ? uiLastCPFile + : uiLastTransFile; + break; + } + + case FDB_GET_RFL_HIGHEST_NU: + { + FLMUINT uiLastCPFile; + FLMUINT uiLastTransFile; + + // Get the CP and last trans RFL file numbers. Need to + // return the lower of the two minus 1. + + uiLastCPFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ + LOG_RFL_LAST_CP_FILE_NUM]); + + uiLastTransFile = FB2UD( &pDb->pFile->ucUncommittedLogHdr[ + LOG_RFL_FILE_NUM]); + + *((FLMUINT *)pvValue1) = + (FLMUINT)((uiLastCPFile < uiLastTransFile + ? uiLastCPFile + : uiLastTransFile) - 1); + break; + } + + case FDB_GET_RFL_FILE_SIZE_LIMITS: + { + if (pvValue1) + { + *((FLMUINT *)pvValue1) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); + } + if (pvValue2) + { + if (pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + *((FLMUINT *)pvValue2) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]); + } + else + { + *((FLMUINT *)pvValue2) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); + } + } + break; + } + + case FDB_GET_RFL_KEEP_FLAG: + { + *((FLMBOOL *)pvValue1) = + pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_RFL_FILES] + ? TRUE + : FALSE; + break; + } + + case FDB_GET_LAST_BACKUP_TRANS_ID: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + *((FLMUINT *)pvValue1) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr [LOG_LAST_BACKUP_TRANS_ID]); + break; + } + + case FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + *((FLMUINT *)pvValue1) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr[ LOG_BLK_CHG_SINCE_BACKUP]); + break; + } + + case FDB_GET_SERIAL_NUMBER: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + f_mutexLock( gv_FlmSysData.hShareMutex); + f_memcpy( (FLMBYTE *)pvValue1, + &pDb->pFile->ucLastCommittedLogHdr [LOG_DB_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + break; + } + + case FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + *((FLMBOOL *)pvValue1) = FALSE; + } + else + { + *((FLMBOOL *)pvValue1) = + pDb->pFile->ucUncommittedLogHdr [LOG_AUTO_TURN_OFF_KEEP_RFL] + ? TRUE + : FALSE; + } + break; + } + + case FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + *((FLMBOOL *)pvValue1) = FALSE; + } + else + { + *((FLMBOOL *)pvValue1) = + pDb->pFile->ucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL] + ? TRUE + : FALSE; + } + break; + } + + case FDB_GET_SIZES: + { + rc = flmDbGetSizes( pDb, (FLMUINT64 *)pvValue1, (FLMUINT64 *)pvValue2, + (FLMUINT64 *)pvValue3); + break; + } + + case FDB_GET_FILE_EXTEND_SIZE: + { + *((FLMUINT *)pvValue1) = pDb->pFile->uiFileExtendSize; + break; + } + + case FDB_GET_APP_DATA: + { + *((void **)pvValue1) = pDb->pvAppData; + break; + } + + case FDB_GET_NEXT_INC_BACKUP_SEQ_NUM: + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + *((FLMUINT *)pvValue1) = (FLMUINT)FB2UD( + &pDb->pFile->ucUncommittedLogHdr[ LOG_INC_BACKUP_SEQ_NUM]); + break; + } + + case FDB_GET_DICT_SEQ_NUM: + { + if( pDb->pDict) + { + *((FLMUINT *)pvValue1) = pDb->pDict->uiDictSeq; + } + else + { + *((FLMUINT *)pvValue1) = pDb->pFile->pDictList->uiDictSeq; + } + break; + } + + case FDB_GET_FFILE_ID: + { + *((FLMUINT *)pvValue1) = pDb->pFile->uiFFileId; + break; + } + + case FDB_GET_MUST_CLOSE_RC: + { + *((RCODE *)pvValue1) = pDb->pFile->rcMustClose; + break; + } + + default: + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + break; + } + } + +Exit: + + if( bStartedTrans) + { + flmAbortDbTrans( pDb); + } + + if( bDbInitialized) + { + fdbExit( pDb); + } + + return( rc); +} + +/**************************************************************************** +Desc: Retrieves the Checkpoint info for the pFile passed in. This assumes the + hShareMutex has already been locked. +*****************************************************************************/ +void flmGetCPInfo( + void * pFilePtr, + CHECKPOINT_INFO * pCheckpointInfo) +{ + FFILE * pFile; + FLMUINT uiElapTime; + FLMUINT uiCurrTime; + + flmAssert( pFilePtr); + flmAssert( pCheckpointInfo); + + pFile = (FFILE *)pFilePtr; + + f_memset( pCheckpointInfo, 0, sizeof( CHECKPOINT_INFO)); + if (pFile->pCPInfo) + { + pCheckpointInfo->bRunning = pFile->pCPInfo->bDoingCheckpoint; + if (pCheckpointInfo->bRunning) + { + if (pFile->pCPInfo->uiStartTime) + { + uiCurrTime = FLM_GET_TIMER(); + + uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, + pFile->pCPInfo->uiStartTime); + FLM_TIMER_UNITS_TO_MILLI( uiElapTime, pCheckpointInfo->uiRunningTime); + } + else + { + pCheckpointInfo->uiRunningTime = 0; + } + pCheckpointInfo->bForcingCheckpoint = + pFile->pCPInfo->bForcingCheckpoint; + if (pFile->pCPInfo->uiForceCheckpointStartTime) + { + uiCurrTime = FLM_GET_TIMER(); + uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, + pFile->pCPInfo->uiForceCheckpointStartTime); + FLM_TIMER_UNITS_TO_MILLI( uiElapTime, + pCheckpointInfo->uiForceCheckpointRunningTime); + } + else + { + pCheckpointInfo->uiForceCheckpointRunningTime = 0; + } + + pCheckpointInfo->iForceCheckpointReason = + pFile->pCPInfo->iForceCheckpointReason; + pCheckpointInfo->bWritingDataBlocks = + pFile->pCPInfo->bWritingDataBlocks; + pCheckpointInfo->uiLogBlocksWritten = + pFile->pCPInfo->uiLogBlocksWritten; + pCheckpointInfo->uiDataBlocksWritten = + pFile->pCPInfo->uiDataBlocksWritten; + } + + pCheckpointInfo->uiBlockSize = + (FLMUINT)pFile->FileHdr.uiBlockSize; + pCheckpointInfo->uiDirtyCacheBytes = + pFile->uiDirtyCacheCount * pFile->FileHdr.uiBlockSize; + + if (pFile->pCPInfo->uiStartWaitTruncateTime) + { + uiCurrTime = FLM_GET_TIMER(); + + uiElapTime = FLM_ELAPSED_TIME( uiCurrTime, + pFile->pCPInfo->uiStartWaitTruncateTime); + FLM_TIMER_UNITS_TO_MILLI( uiElapTime, + pCheckpointInfo->uiWaitTruncateTime); + } + else + { + pCheckpointInfo->uiWaitTruncateTime = 0; + } + } +} + +/**************************************************************************** +Desc: +*****************************************************************************/ +RCODE flmSetRflSizeThreshold( + HFDB hDb, + FLMUINT uiSizeThreshold, + FLMUINT uiTimeInterval, + FLMUINT uiSizeInterval) +{ + RCODE rc = FERR_OK; + FDB * pDb = (FDB *)hDb; + FFILE * pFile = pDb->pFile; + FLMBOOL bDbInitialized = FALSE; + FLMBOOL bStartedTrans = FALSE; + + // Start an update transaction. Must not already be one going. + + bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, + 0, FLM_NO_TIMEOUT | FLM_AUTO_TRANS, &bStartedTrans))) + { + goto Exit; + } + + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_61) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Set the size threshold and event intervals + + if( uiSizeThreshold == FLM_MAX_UINT) + { + uiSizeThreshold = FB2UD( + &pFile->ucUncommittedLogHdr [LOG_RFL_DISK_SPACE_THRESHOLD]); + } + else + { + UD2FBA( (FLMUINT32)uiSizeThreshold, + &pFile->ucUncommittedLogHdr [LOG_RFL_DISK_SPACE_THRESHOLD]); + } + + if( uiTimeInterval == FLM_MAX_UINT) + { + uiTimeInterval = FB2UD( + &pFile->ucUncommittedLogHdr [LOG_RFL_LIMIT_TIME_FREQ]); + } + else + { + UD2FBA( (FLMUINT32)uiTimeInterval, + &pFile->ucUncommittedLogHdr [LOG_RFL_LIMIT_TIME_FREQ]); + } + + if( uiSizeInterval == FLM_MAX_UINT) + { + uiSizeInterval = FB2UD( + &pFile->ucUncommittedLogHdr [LOG_RFL_LIMIT_SPACE_FREQ]); + } + else + { + UD2FBA( (FLMUINT32)uiSizeInterval, + &pFile->ucUncommittedLogHdr [LOG_RFL_LIMIT_SPACE_FREQ]); + } + + // Log the change to the RFL + + if( RC_BAD( rc = pFile->pRfl->logSizeEventConfig( + pDb->LogHdr.uiCurrTransID, uiSizeThreshold, uiTimeInterval, + uiSizeInterval))) + { + goto Exit; + } + + // Commit the transaction. + + if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) + { + goto Exit; + } + + bStartedTrans = FALSE; + +Exit: + + if( bStartedTrans) + { + flmAbortDbTrans( pDb); + } + + if( bDbInitialized) + { + fdbExit( pDb); + } + + return( rc); +} diff --git a/flaim/src/fdbcopy.cpp b/flaim/src/fdbcopy.cpp index bb01ca0..6023b74 100644 --- a/flaim/src/fdbcopy.cpp +++ b/flaim/src/fdbcopy.cpp @@ -389,7 +389,7 @@ FSTATIC RCODE flmCopyDb( // Get the sizes of the roll-forward log files - if( uiDbVersion < FLM_VER_4_3) + if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to copy one RFL file. @@ -553,7 +553,7 @@ FSTATIC RCODE flmCopyDb( // Copy the RFL files - if( uiDbVersion < FLM_VER_4_3) + if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { // Get the source file path and the destination file path. diff --git a/flaim/src/fdbremov.cpp b/flaim/src/fdbremov.cpp index dbe990d..c1309ba 100644 --- a/flaim/src/fdbremov.cpp +++ b/flaim/src/fdbremov.cpp @@ -38,12 +38,11 @@ FLMEXP RCODE FLMAPI FlmDbRemove( FLMBYTE * pucBuffer = NULL; FLMUINT uiFileNumber; FILE_HDR FileHdr; - LOG_HDR LogHdr; + FLMUINT uiVersionNum; char * pszTmpName = NULL; char * pszRflDirName; char * pszDataName; char * pszBaseName; - FLMBYTE * pucLogHdr; char szPrefix[ F_FILENAME_SIZE]; char * pszExt; char * pszDataExt; @@ -59,8 +58,8 @@ FLMEXP RCODE FLMAPI FlmDbRemove( // Allocate memory, so as to not consume stack. - if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE * 3 + F_FILENAME_SIZE + - LOG_HEADER_SIZE, &pszTmpName))) + if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE * 3 + F_FILENAME_SIZE, + &pszTmpName))) { goto Exit; } @@ -68,7 +67,6 @@ FLMEXP RCODE FLMAPI FlmDbRemove( pszRflDirName = pszTmpName + F_PATH_MAX_SIZE; pszDataName = pszRflDirName + F_PATH_MAX_SIZE; pszBaseName = pszDataName + F_PATH_MAX_SIZE; - pucLogHdr =(FLMBYTE *)(pszBaseName + F_FILENAME_SIZE); // First make sure we have closed this database and gotten rid of // it from our internal memory tables - in case it had been open. @@ -99,9 +97,13 @@ FLMEXP RCODE FLMAPI FlmDbRemove( // file numbers. if (RC_BAD( flmReadAndVerifyHdrInfo( NULL, pFileHdl, - pucBuffer, &FileHdr, &LogHdr, pucLogHdr))) + pucBuffer, &FileHdr, NULL, NULL))) { - goto Exit; + uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM; + } + else + { + uiVersionNum = FileHdr.uiVersionNum; } // Close the file. @@ -181,8 +183,7 @@ FLMEXP RCODE FLMAPI FlmDbRemove( uiFileNumber = 1; for (;;) { - bldSuperFileExtension( FileHdr.uiVersionNum, - uiFileNumber, pszDataExt); + bldSuperFileExtension( uiVersionNum, uiFileNumber, pszDataExt); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->Delete( pszDataName))) { @@ -196,8 +197,8 @@ FLMEXP RCODE FLMAPI FlmDbRemove( goto Exit; } } - if (uiFileNumber == - MAX_DATA_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) + + if (uiFileNumber == MAX_DATA_BLOCK_FILE_NUMBER( uiVersionNum)) { break; } @@ -206,12 +207,10 @@ FLMEXP RCODE FLMAPI FlmDbRemove( // Delete rollback log files. - uiFileNumber = - FIRST_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum); + uiFileNumber = FIRST_LOG_BLOCK_FILE_NUMBER( uiVersionNum); for (;;) { - bldSuperFileExtension( FileHdr.uiVersionNum, - uiFileNumber, pszExt); + bldSuperFileExtension( uiVersionNum, uiFileNumber, pszExt); if (RC_BAD( rc = gv_FlmSysData.pFileSystem->Delete( pszTmpName))) { @@ -225,11 +224,12 @@ FLMEXP RCODE FLMAPI FlmDbRemove( goto Exit; } } - if (uiFileNumber == - MAX_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) + + if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( uiVersionNum)) { break; } + uiFileNumber++; } @@ -238,16 +238,17 @@ FLMEXP RCODE FLMAPI FlmDbRemove( // Delete roll-forward log files. - if (FileHdr.uiVersionNum < FLM_VER_4_3) + if (uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to delete one RFL file. - if (RC_BAD( rc = rflGetFileName( FileHdr.uiVersionNum, - pszDbName, pszRflDir, 1, pszTmpName))) + if (RC_BAD( rc = rflGetFileName( uiVersionNum, pszDbName, + pszRflDir, 1, pszTmpName))) { goto Exit; } + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->Delete( pszTmpName))) { if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) @@ -267,7 +268,7 @@ FLMEXP RCODE FLMAPI FlmDbRemove( // For 4.3 and greater, need to scan the RFL directory for // RFL files. - if (RC_BAD( rc = rflGetDirAndPrefix( FileHdr.uiVersionNum, + if (RC_BAD( rc = rflGetDirAndPrefix( uiVersionNum, pszDbName, pszRflDir, pszRflDirName, szPrefix))) { goto Exit; @@ -316,7 +317,7 @@ FLMEXP RCODE FLMAPI FlmDbRemove( { bCanDeleteDir = FALSE; } - else if (!rflGetFileNum( FileHdr.uiVersionNum, + else if (!rflGetFileNum( uiVersionNum, szPrefix, pszTmpName, &uiFileNumber)) { bCanDeleteDir = FALSE; @@ -367,21 +368,26 @@ FLMEXP RCODE FLMAPI FlmDbRemove( } Exit: + if (pszTmpName) { f_free( &pszTmpName); } + if (pFileHdl) { pFileHdl->Release(); } + if (pucBuffer) { f_free( &pucBuffer); } + if (pDirHdl) { pDirHdl->Release(); } + return( rc); } diff --git a/flaim/src/fdbrenam.cpp b/flaim/src/fdbrenam.cpp index d57ffbb..7427747 100644 --- a/flaim/src/fdbrenam.cpp +++ b/flaim/src/fdbrenam.cpp @@ -69,6 +69,7 @@ FSTATIC RCODE flmRenameFile( { *pbFileFound = TRUE; } + goto Exit; } @@ -154,11 +155,14 @@ FSTATIC RCODE flmRenameFile( pRenameFile = NULL; } + Exit: + if (pRenameFile) { f_free( &pRenameFile); } + return( rc); } @@ -222,6 +226,7 @@ FLMEXP RCODE FLMAPI FlmDbRename( { goto Exit; } + if (RC_BAD( rc = f_pathReduce( pszNewDbName, pszNewName, szNewBase))) { goto Exit; @@ -336,6 +341,7 @@ FLMEXP RCODE FLMAPI FlmDbRename( pszExtNew = pszNewName + f_strlen( pszNewName) - 1; pszDataExtNew = pszNewDataName + f_strlen( pszNewDataName) - 1; + while (pszExtNew != pszOldName && *pszExtNew != '.') { pszExtNew--; @@ -346,6 +352,7 @@ FLMEXP RCODE FLMAPI FlmDbRename( pszDataExtNew--; } + if (*pszExtNew != '.') { pszExtNew = pszNewName + f_strlen( pszNewName); @@ -411,21 +418,24 @@ FLMEXP RCODE FLMAPI FlmDbRename( { goto Exit; } + if (!bFileFound) { break; } + if (uiFileNumber == MAX_LOG_BLOCK_FILE_NUMBER( FileHdr.uiVersionNum)) { break; } + uiFileNumber++; } // Rename roll-forward log files. - if (FileHdr.uiVersionNum < FLM_VER_4_3) + if (FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { // For pre-4.3 versions, only need to rename one RFL file. @@ -476,10 +486,12 @@ FLMEXP RCODE FLMAPI FlmDbRename( } Exit: + if (pFileHdl) { pFileHdl->Release(); } + if (pucBuffer) { f_free( &pucBuffer); @@ -502,7 +514,9 @@ Exit: gv_FlmSysData.pFileSystem->Rename( pRenameFile->Info.szDstFileName, pRenameFile->Info.szSrcFileName); } + f_free( &pRenameFile); } + return( rc); } diff --git a/flaim/src/fddpcode.h b/flaim/src/fddpcode.h deleted file mode 100644 index b3cc810..0000000 --- a/flaim/src/fddpcode.h +++ /dev/null @@ -1,233 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Typedefs for strucures needed to build pcode. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fddpcode.h 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#ifndef FDDPCODE_H -#define FDDPCODE_H - -#include "fpackon.h" -// IMPORTANT NOTE: No other include files should follow this one except -// for fpackoff.h - -// Logical File Save Area Layout for 4.x files. - -#define LFH_LF_NUMBER_OFFSET 0 // Logical file number -#define LFH_TYPE_OFFSET 2 // Type of logical file -#define LFH_STATUS_OFFSET 3 // Contains status bits -#define LFH_ROOT_BLK_OFFSET 4 // B-TREE root block address -//#define LFH_FUTURE1 8 // Not necessarily zeroes - Code bases - // 31 and 40 put stuff here. -#define LFH_NEXT_DRN_OFFSET 12 // Next DRN for containers -#define LFH_MAX_FILL_OFFSET 16 // Max fill % after rightmost split. -#define LFH_MIN_FILL_OFFSET 17 // Min fill % in blk after normal delete -//#define LFH_FUTURE2 18 // Filled with zeros -#define LFH_SIZE 32 // Maximum size of LFH. - - -typedef struct DDEntry * DDENTRY_p; -typedef struct TmpFieldDef * TFIELD_p; -typedef struct TmpIndexFieldPath * TIFP_p; -typedef struct TmpIndexFieldDef * TIFD_p; -typedef struct TmpIndexDef * TIXD_p; -typedef struct Tmp_Dictionary * TDICT_p; -typedef struct TmpFlaimArea * TFAREA_p; - -RCODE fdictRebuild( - FDB * pDb); - -RCODE fdictBuildTables( - TDICT_p pTDict, - FLMBOOL bRereadLFiles, - FLMBOOL bNewDict); - -RCODE fdictInitTDict( - FDB * pDb, - TDICT_p pTDict); - -RCODE fdictCopySkeletonDict( - FDB * pDb); - -RCODE fdictCloneDict( - FDB * pDb); - -RCODE fdictFixupLFileTbl( - FDICT * pDict); - -RCODE fdictProcessAllDictRecs( - FDB * pDb, - TDICT_p pTDict); - -RCODE fdictProcessRec( - TDICT_p pTDict, - FlmRecord * pRecord, - FLMUINT uiDictRecNum); - -RCODE DDGetFieldType( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo); - -RCODE DDGetEncType( - FlmRecord * pRecord, - void * pvField, - FLMUINT * puiFldInfo); - -RCODE fdictCreateNewDict( - FDB * pDb); - -RCODE fdictCreate( - FDB * pDb, - const char * pszDictPath, - const char * pDictBuf); - -RCODE flmAddRecordToDict( - FDB * pDb, - FlmRecord * pRecord, - FLMUINT uiDictId, - FLMBOOL bRereadLFiles); - -/**************************************************************************** -Desc: Structure for type, DRN and name for data dictionary entries -****************************************************************************/ -typedef struct DDEntry -{ - DDENTRY_p pNextEntry; - void * vpDef; - FLMUINT uiEntryNum; - FLMUINT uiType; -} DDENTRY; - -/**************************************************************************** -Desc: Temporary field info used during a database create or dictionary - modification. This field is pointed to by the DDEntry structure. -****************************************************************************/ -typedef struct TmpFieldDef -{ - FLMUINT uiFldNum; - FLMUINT uiFldInfo; -} TFIELD; - -/**************************************************************************** -Desc: Temporary encryption definition info used during a database create or - dictionary modification. This field is pointed to by the - DDEntry structure. -****************************************************************************/ -typedef struct -{ - FLMUINT uiRecNum; - FLMUINT uiState; - FLMUINT uiAlgType; - FLMBYTE * pucKeyInfo; - FLMUINT uiLength; -} TENCDEF; - -/**************************************************************************** -Desc: Used as temporary storage for index definitions during a - database create or dictionary modification. This field is - pointed to by the DDEntry structure. -****************************************************************************/ -typedef struct TmpIndexFieldPath -{ - TIFP_p pNextTIfp; // Linked list of IFPs - FLMBOOL bFieldInThisDict; // Was field reference found in the - // dictionary we are updating? - FLMUINT uiFldNum; // Fixedup field ID value -} TIFP; - -/**************************************************************************** -Desc: Used as temporary storage for index definitions during a - database create or dictionary modification. This field is - pointed to by the DDEntry structure. -****************************************************************************/ -typedef struct TmpIndexFieldDef -{ - TIFP_p pTIfp; // Linked list of temporary field paths - TIFD_p pNextTIfd; // Linked List - FLMUINT uiFlags; // Field type & processing flags - FLMUINT uiNextFixupPos; // Next fixup position - FLMUINT uiLimit; // Zero or limit of characters/bytes - FLMUINT uiCompoundPos; // Position of this field is in - // the compound key. Zero based number. -} TIFD; - -/**************************************************************************** -Desc: Used as temporary storage for index definitions during a - database create or dictionary modification. This field is - pointed to by the DDEntry structure. -****************************************************************************/ -typedef struct TmpIndexDef -{ - TIFD_p pNextTIfd; // Linked list of TIFDs - FLMUINT uiFlags; // Index attributes - FLMUINT uiContainerNum; // Container number of data records - FLMUINT uiNumFlds; // Number of field definitions - FLMUINT uiLanguage; // Index language - FLMUINT uiEncId; // Encryption Definition -} TIXD; - -/**************************************************************************** -Desc: Contains the dictionary entries through parsing all of the dictionary - records. Used for expanding record definitions, checking index - definitions, building fixup position values and last of all - BUILDING THE PCODE. -****************************************************************************/ -typedef struct Tmp_Dictionary -{ - FDB * pDb; - POOL pool; // Pool for the DDENTRY allocations. - LFILE * pLFile; // Dictionary container LFile - FDICT_p pDict; // Pointer to new dictionary. - FLMBOOL bWriteToDisk; // Flag indicating if PCODE should be - // written to disk after being generated. - - // Variables for building dictionaries - - FLMUINT uiCurPcodeAddr; // Current pcode block we are adding to - FLMUINT uiBlockSize; // PCODE Block size - - // Used in building the temporary structures - - FLMUINT uiVersionNum; // Version number of database. - DDENTRY_p pFirstEntry; - DDENTRY_p pLastEntry; - - FLMUINT uiNewIxds; - FLMUINT uiNewIfds; - FLMUINT uiNewFldPaths; - FLMUINT uiNewLFiles; - - FLMUINT uiTotalItts; - FLMUINT uiTotalIxds; - FLMUINT uiTotalIfds; - FLMUINT uiTotalFldPaths; - FLMUINT uiTotalLFiles; - - FLMUINT uiBadField; // Set to field number on most errors. - FLMUINT uiBadReference; // Same - - FLMUINT uiDefaultLanguage;// Default language to set in each index. -} TDICT; - -#include "fpackoff.h" - -#endif diff --git a/flaim/src/fdict.cpp b/flaim/src/fdict.cpp index 8200136..9bba465 100644 --- a/flaim/src/fdict.cpp +++ b/flaim/src/fdict.cpp @@ -24,6 +24,2572 @@ #include "flaimsys.h" +FSTATIC RCODE fdictAddDictIndex( + TDICT * pTDict); + +FSTATIC RCODE DDFieldParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord, + FLMUINT uiDictRecNum); + +FSTATIC RCODE DDGetReference( + FlmRecord * pRecord, + void * pvField, + const char * pszBuffer, + FLMUINT * puiIdRef); + +FSTATIC RCODE DDAllocEntry( + TDICT * pTDict, + FlmRecord * pRecord, + FLMUINT uiDictRecNum, + DDENTRY ** ppDDEntryRV); + +FSTATIC RCODE DDIxParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord, + void * pvField); + +FSTATIC RCODE DDBuildFldPath( + TDICT * pTDict, + TIFD ** ppTIfd, + FlmRecord * pRecord, + void * pvField, + FLMUINT uiBaseNum); + +FSTATIC FLMBOOL DDMoveWord( + char * pucDest, + char * pucSrc, + FLMUINT uiMaxDestLen, + FLMUINT * puiPos); + +FSTATIC RCODE DDContainerParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord); + +FSTATIC void DDTextToNative( + FlmRecord * pRecord, + void * pvField, + char * pszBuffer, + FLMUINT uiBufLen, + FLMUINT * puiBufLen); + +FSTATIC RCODE DDParseStateOptions( + FlmRecord * pRecord, + void * pvField, + FLMUINT * puiFldInfo); + +FSTATIC RCODE DDEncDefParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord, + FLMUINT uiDictRecNum); + +FSTATIC RCODE DDGetEncKey( + TDICT * pTDict, + FlmRecord * pRecord, + void * pvField, + TENCDEF * pTEncDef); + +FSTATIC RCODE DDMakeDictIxKey( + FDB * pDb, + FlmRecord * pRecord, + FLMBYTE * pKeyBuf, + FLMUINT * puiKeyLenRV); + +FSTATIC RCODE DDCheckNameConflict( + FDB * pDb, + LFILE * pDictIxLFile, + FlmRecord * pNewRec, + FLMUINT uiDrn, + FlmRecord * pOldRec); + +FSTATIC RCODE DDCheckIDConflict( + FDB * pDb, + LFILE * pDictContLFile, + FLMUINT uiDrn); + +FSTATIC RCODE DDIxDictRecord( + FDB * pDb, + LFILE * pDictIxLFile, + FLMUINT uiDrn, + FlmRecord * pRecord, + FLMUINT uiFlags); + +FSTATIC void fdictFixupPointers( + FDICT * pNewDict, + FDICT * pOldDict); + +FSTATIC RCODE fdictReallocAllTables( + TDICT * pTDict); + +FSTATIC RCODE fdictReallocTbl( + FLMUINT uiElementSize, + FLMUINT uiTblSize, + FLMUINT uiAddElements, + void ** ppvTblRV); + +FSTATIC void fdictAddItem( + TDICT * pTDict, + FLMUINT uiFieldNum, + FLMUINT uiFieldType); + +FSTATIC RCODE fdictAddIndex( + TDICT * pTDict, + DDENTRY * pEntry); + +FSTATIC RCODE fdictFixupIfdPointers( + FDICT * pDict, + FLMUINT uiIfdStartOffset); + +FSTATIC RCODE fdictAddNewCCS( + TDICT * pTDict, + TENCDEF * pTEncDef, + FLMUINT uiRecNum); + +#define FDD_MAX_VALUE_SIZE 64 +#define MAX_ENC_TYPES 3 + +#define START_DD_INDEX_OPTS 0 +#define DD_IX_FIELD_OPT 0 +#define DD_IX_COMPOUND_OPT 1 +#define DD_IX_UPPER_OPT 2 +#define DD_IX_EACHWORD_OPT 3 +#define DD_IX_MIXED_OPT 4 +#define DD_IX_CONTEXT_OPT 5 +#define DD_IX_POST_OPT 6 +#define MAX_DD_INDEX_OPTS 7 + +// NOTE: If you change the arrangement of the values in this array, make sure +// you search the entire codebase for references to DDEncOpts and DDGetEncType +// and verify that the changes won't cause problems. This is particularly +// important because these values DO NOT match up exactly with the values in +// the SMEncryptionScheme enum that's used at the SMI level. + +char * DDEncOpts[ MAX_ENC_TYPES] = +{ + "aes", + "des3", + "des" +}; + +FSTATIC POOL_STATS g_TDictPoolStats = {0,0}; + +/******************************************************************************* +Desc: Retrieves a dictionary item name. +Notes: Given an item ID, this routine will search a specified shared or + local dictionary for the item. If it is found, the name + of the item will be returned. This routine supports version 2.0 and + higher databases only. +*******************************************************************************/ +FLMEXP RCODE FLMAPI FlmGetItemName( + HFDB hDb, + FLMUINT uiItemId, + FLMUINT uiNameBufSize, + char * pszNameBuf) +{ + RCODE rc = FERR_OK; + FlmRecord * pRecord = NULL; + + *pszNameBuf = 0; + if( RC_BAD( rc = FlmRecordRetrieve( hDb, + FLM_DICT_CONTAINER, uiItemId, FO_EXACT, &pRecord, NULL))) + { + goto Exit; + } + + if( RC_BAD( rc = pRecord->getNative( pRecord->root(), + pszNameBuf, &uiNameBufSize))) + { + goto Exit; + } + +Exit: + + if( pRecord) + { + pRecord->Release(); + } + + return (rc == FERR_EOF_HIT) ? RC_SET( FERR_NOT_FOUND) : rc; +} + +/**************************************************************************** +Desc: Read all data dictionary records parsing and sending to process. + All temporary structures are off of pTDict. pTDict must be setup. +****************************************************************************/ +RCODE fdictProcessAllDictRecs( + FDB * pDb, + TDICT * pTDict) +{ + RCODE rc; + LFILE * pLFile = pTDict->pLFile; + BTSK stackBuf[ BH_MAX_LEVELS ]; // Stack to hold b-tree variables + BTSK * stack = stackBuf; // Points to proper stack frame + FLMBYTE btKeyBuf[ DRN_KEY_SIZ +8]; // Key buffer pointed to by stack + FLMBYTE key[4]; // Used for dummy empty key + FLMUINT uiDrn; + FlmRecord * pRecord = NULL; + + // Add the dictionary index to the front of TDICT. + + if( RC_BAD( rc = fdictAddDictIndex( pTDict))) + { + goto Exit; + } + + // Position to the first of the data dictionary data records & read. + + FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); + stack->pKeyBuf = btKeyBuf; + flmUINT32ToBigEndian( 0, key); + + if( RC_BAD(rc = FSBtSearch( pDb, pLFile, &stack, key, DRN_KEY_SIZ, 0 ))) + { + goto Exit; + } + + // Special case of no records. + if( stack->uiCmpStatus == BT_END_OF_DATA) + goto Exit; + stack->uiFlags = NO_STACK; // Fake out the stack for speed. + + do + { + uiDrn = flmBigEndianToUINT32( btKeyBuf); + + if( uiDrn == DRN_LAST_MARKER) + { + break; + } + + // VERY IMPORTANT NOTE: + // DO NOT READ FROM CACHE - THE RECORD MAY + // NOT HAVE BEEN PUT INTO RECORD CACHE YET, AND WE NEED TO HAVE + // THE CORRECT VERSION OF THE RECORD. + + if( RC_BAD( rc = FSReadElement( pDb, &pDb->TempPool, pLFile, + uiDrn, stack, TRUE, &pRecord, NULL, NULL))) + { + break; + } + + if( RC_BAD(rc = fdictProcessRec( pTDict, pRecord, uiDrn))) + { + pDb->Diag.uiDrn = uiDrn; + pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; + if( pTDict->uiBadField != 0) + { + pDb->Diag.uiFieldNum = pTDict->uiBadField; + pDb->Diag.uiInfoFlags |= FLM_DIAG_FIELD_NUM; + } + break; + } + + // Position to the next record - SUCCESS or FERR_BT_END_OF_DATA + rc = FSNextRecord( pDb, pLFile, stack); + + } while( RC_OK(rc)); + + rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; + +Exit: + + if( pRecord) + { + pRecord->Release(); + } + + FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); + return( rc ); +} + +/**************************************************************************** +Desc: Add the dictionary index to pTDict. +****************************************************************************/ +RCODE fdictAddDictIndex( + TDICT * pTDict) +{ + RCODE rc; + DDENTRY * pDDEntry; + TIXD * pTIxd; + TIFD * pTIfd; + TIFP * pTIfp; + + if( RC_BAD( rc = DDAllocEntry( pTDict, NULL, FLM_DICT_INDEX, &pDDEntry))) + { + goto Exit; + } + pDDEntry->uiType = ITT_INDEX_TYPE; + + if( (pTIxd = (TIXD *) GedPoolAlloc( &pTDict->pool, sizeof( TIXD))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTDict->uiNewIxds++; + pDDEntry->vpDef = (void *) pTIxd; + pTIxd->uiFlags = IXD_UNIQUE; + pTIxd->uiContainerNum = FLM_DICT_CONTAINER; + pTIxd->uiNumFlds = 1; + pTIxd->uiLanguage = pTDict->uiDefaultLanguage; + pTIxd->uiEncId = 0; + + if( (pTIfd = (TIFD *) GedPoolAlloc( &pTDict->pool, sizeof( TIFD))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTIxd->pNextTIfd = pTIfd; + pTDict->uiNewIfds++; + pTIfd->pTIfp = NULL; + pTIfd->pNextTIfd = NULL; + pTIfd->uiFlags = (FLMUINT)(IFD_FIELD | FLM_TEXT_TYPE); + pTIfd->uiNextFixupPos = 0; + pTIfd->uiLimit = IFD_DEFAULT_LIMIT; + pTIfd->uiCompoundPos = 0; + + if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, sizeof( TIFP ))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTDict->uiNewFldPaths += 2; + pTIfd->pTIfp = pTIfp; + + pTIfp->pNextTIfp = NULL; + pTIfp->bFieldInThisDict = FALSE; + pTIfp->uiFldNum = FLM_NAME_TAG; + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Process a single data dictionary record. Parse the record for syntax + errors depending on flag value. Only supports adding new stuff + to pTDict. +****************************************************************************/ +RCODE fdictProcessRec( + TDICT * pTDict, + FlmRecord * pRecord, + FLMUINT uiDictRecNum) +{ + RCODE rc = FERR_OK; + DDENTRY * pDDEntry; + void * pvField = pRecord->root(); + + // Ignore items with root nodes that are in the unregistered range. + + if( pRecord->getFieldID( pvField) >= FLM_UNREGISTERED_TAGS) + { + goto Exit; + } + + // Parse only on modify or add. + + switch( pRecord->getFieldID( pvField)) + { + case FLM_FIELD_TAG: + { + if( RC_BAD( rc = DDAllocEntry( + pTDict, pRecord, uiDictRecNum, &pDDEntry))) + { + goto Exit; + } + + pDDEntry->uiType = 0; // Type of zero means field. + if( RC_BAD( rc = DDFieldParse( pTDict, pDDEntry, + pRecord, uiDictRecNum))) + { + goto Exit; + } + break; + } + + case FLM_INDEX_TAG: + { + if( RC_BAD( rc = DDAllocEntry( + pTDict, pRecord, uiDictRecNum, &pDDEntry))) + { + goto Exit; + } + pDDEntry->uiType = ITT_INDEX_TYPE; + if( RC_BAD( rc = DDIxParse( pTDict, pDDEntry, pRecord, pvField))) + { + goto Exit; + } + pTDict->uiNewIxds++; + break; + } + + case FLM_CONTAINER_TAG: + { + if( RC_BAD( rc = DDAllocEntry( + pTDict, pRecord, uiDictRecNum, &pDDEntry))) + { + goto Exit; + } + pDDEntry->uiType = ITT_CONTAINER_TYPE; + if( RC_BAD( rc = DDContainerParse( pTDict, pDDEntry, pRecord))) + { + goto Exit; + } + pTDict->uiTotalLFiles++; + break; + } + case FLM_ENCDEF_TAG: + { + if( RC_BAD( rc = DDAllocEntry( + pTDict, pRecord, uiDictRecNum, &pDDEntry))) + { + goto Exit; + } + pDDEntry->uiType = ITT_ENCDEF_TYPE; + if (RC_BAD( rc = DDEncDefParse( pTDict, pDDEntry, pRecord, uiDictRecNum))) + { + goto Exit; + } + break; + } + case FLM_AREA_TAG: + case FLM_RESERVED_TAG: + { + break; + } + + default: + { + // Cannot allow anything else to pass through the dictionary. + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Allocate, check and add a name to the DDEntry structure. +****************************************************************************/ +FSTATIC RCODE DDAllocEntry( + TDICT * pTDict, + FlmRecord * pRecord, + FLMUINT uiDictRecNum, + DDENTRY ** ppDDEntryRV) +{ + RCODE rc = FERR_OK; + DDENTRY * pNewEntry; + + pNewEntry = (DDENTRY *)GedPoolAlloc( &pTDict->pool, sizeof(DDENTRY)); + if( !pNewEntry) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pNewEntry->pNextEntry = NULL; + pNewEntry->vpDef = NULL; + pNewEntry->uiEntryNum = uiDictRecNum; + pNewEntry->uiType = 0; + + // Zero length name NOT allowed for dictionary items. + + if( pRecord) + { + if( pRecord->getDataLength( pRecord->root()) == 0) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + + if( pTDict->pLastEntry) + { + pTDict->pLastEntry->pNextEntry = pNewEntry; + } + else + { + pTDict->pFirstEntry = pNewEntry; + } + pTDict->pLastEntry = pNewEntry; + *ppDDEntryRV = pNewEntry; + +Exit: + + return( rc ); +} + +/**************************************************************************** +Desc: Parse field definition +****************************************************************************/ +FSTATIC RCODE DDFieldParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord, + FLMUINT uiDictRecNum) +{ + RCODE rc = FERR_OK; + TFIELD * pTField; + void * pvField; + + if( (pTField = (TFIELD *)GedPoolAlloc( &pTDict->pool, sizeof(TFIELD))) == NULL) + { + return( RC_SET( FERR_MEM)); + } + + pTField->uiFldNum = uiDictRecNum; + pTField->uiFldInfo = FLM_CONTEXT_TYPE; + pDDEntry->vpDef = (void *) pTField; + + if( (pvField = pRecord->firstChild( pRecord->root())) == NULL) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + + for( ; pvField; pvField = pRecord->nextSibling( pvField)) + { + switch( pRecord->getFieldID( pvField)) + { + case FLM_TYPE_TAG: + { + rc = DDGetFieldType( pRecord, pvField, &pTField->uiFldInfo); + break; + } + + case FLM_STATE_TAG: + { + rc = DDParseStateOptions( pRecord, pvField, &pTField->uiFldInfo); + break; + } + + default: + { + if( pRecord->getFieldID( pvField) < FLM_UNREGISTERED_TAGS && + pRecord->getFieldID( pvField) != FLM_COMMENT_TAG) + { + rc = RC_SET( FERR_SYNTAX); + } + break; + } + } + } + +Exit: + + if( RC_BAD(rc) && pvField) + { + pTDict->uiBadField = pRecord->getFieldID( pvField); + } + return( rc ); +} + +/**************************************************************************** +Desc: Returns the fields data type. May be called outside of DDPREP.C +****************************************************************************/ +RCODE DDGetFieldType( + FlmRecord * pRecord, + void * pvField, + FLMUINT * puiFldInfo) +{ + RCODE rc = FERR_OK; + char szNativeBuf[ FDD_MAX_VALUE_SIZE]; + + DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL ); + + // Parse the type keyword - only one type allowed. + + if (f_strnicmp( szNativeBuf, "text", 4) == 0) + { + *puiFldInfo = FLM_TEXT_TYPE; + } + else if (f_strnicmp( szNativeBuf, "numb", 4) == 0) + { + *puiFldInfo = FLM_NUMBER_TYPE; + } + else if (f_strnicmp( szNativeBuf, "bina", 4) == 0) + { + *puiFldInfo = FLM_BINARY_TYPE; + } + else if (f_strnicmp( szNativeBuf, "cont", 4) == 0) + { + *puiFldInfo = FLM_CONTEXT_TYPE; + } + else if (f_strnicmp( szNativeBuf, "blob", 4) == 0) + { + *puiFldInfo = FLM_BLOB_TYPE; + } + else + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Parses the 'state' option that is found within the 'field' + dictionary definition. +Format: state [checking | unused | purge | active] +****************************************************************************/ +FSTATIC RCODE DDParseStateOptions( + FlmRecord * pRecord, + void * pvField, + FLMUINT * puiFldInfo) +{ + RCODE rc = FERR_OK; + char szNativeBuf[ FDD_MAX_VALUE_SIZE]; + + DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL); + + // Parse the 'state' keyword - only one type allowed + + if( f_strnicmp( szNativeBuf, "chec", 4) == 0) + { + // 0xFFCF is used to clear out any existing field 'state' value + + *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_CHECKING); + } + else if( f_strnicmp( szNativeBuf, "unus", 4) == 0) + { + *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_UNUSED); + } + else if( f_strnicmp( szNativeBuf, "purg", 4) == 0) + { + *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_PURGE); + } + else if( f_strnicmp( szNativeBuf, "acti", 4) == 0) + { + *puiFldInfo = (FLMUINT)((*puiFldInfo & ~ITT_FLD_STATE_MASK) | ITT_FLD_STATE_ACTIVE); + } + else + { + rc = RC_SET( FERR_SYNTAX); + } + + return( rc); +} + +/**************************************************************************** +Desc: Get a number reference and set in the (OUT) parameter. +****************************************************************************/ +FSTATIC RCODE DDGetReference( + FlmRecord * pRecord, + void * pvField, + const char * pszBuffer, + FLMUINT * puiIdRef) +{ + RCODE rc = FERR_OK; + + *puiIdRef = 0; + if( pszBuffer) + { + if( !(*pszBuffer)) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + + *puiIdRef = f_atoud( pszBuffer); + } + else + { + if( RC_BAD( rc = pRecord->getUINT( pvField, puiIdRef))) + { + goto Exit; + } + } + +Exit: + + return( rc); +} + + +/**************************************************************************** +Desc: Returns the encryption type. May be called outside of DDPREP.C +****************************************************************************/ +RCODE DDGetEncType( + FlmRecord * pRecord, + void * pvField, + FLMUINT * puiFldInfo) +{ + RCODE rc = FERR_OK; + FLMUINT uiType; + char szNativeBuf[ FDD_MAX_VALUE_SIZE]; + + DDTextToNative( pRecord, pvField, szNativeBuf, FDD_MAX_VALUE_SIZE, NULL ); + + // Parse the type keyword - only one type allowed. + + for( uiType = 0; + uiType < MAX_ENC_TYPES ; + uiType++) + { + if( f_strnicmp( szNativeBuf, DDEncOpts[ uiType], + f_strlen(DDEncOpts[ uiType])) == 0) + { + *puiFldInfo = uiType; + goto Exit; + } + } + + rc = RC_SET( FERR_SYNTAX); + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Returns the binary key info. May be called outside of DDPREP.C +****************************************************************************/ +FSTATIC RCODE DDGetEncKey( + TDICT * pTDict, + FlmRecord * pRecord, + void * pvField, + TENCDEF * pTEncDef) +{ + RCODE rc = FERR_OK; + char * pucBuffer = NULL; + FLMUINT uiLength; + + pTEncDef->uiLength = 0; + + if (RC_BAD( rc = pRecord->getNativeLength( pvField, &uiLength))) + { + goto Exit; + } + uiLength++; + + // Allocate the buffer from the pool so it will be easily freed later. + + if( (pucBuffer = (char *)GedPoolAlloc( &pTDict->pool, uiLength)) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( rc = pRecord->getNative( pvField, pucBuffer, &uiLength))) + { + goto Exit; + } + + pTEncDef->uiLength = uiLength; + pTEncDef->pucKeyInfo = (FLMBYTE *)pucBuffer; + +Exit: + + return( rc); + +} + +/**************************************************************************** +Desc: Parse an data dictionary index definition for correct syntax & + assign the correct attributes. Build the pcode buffer for the index. +Return: RCODE - SUCCESS or FERR_SYNTAX +Format: + +0 index # FLM_INDEX_TAG +[ 1 area [ 0 | ]] # FLM_AREA_TAG - QF files area, 0 = "same as DB" +[ 1 container {DEFAULT | }] # FLM_CONTAINER_TAG - indexes span only one container +[ 1 count [ KEYS &| REFS]] # FLM_COUNT_TAG - key count of keys and/or refs +[ 1 language {US | }] # FLM_LANGUAGE_TAG - for full-text parsing and/or sorting +[ 1 positioning] # FLM_POSITIONING_TAG - full reference counts at all b-tree elements +[ 1 encdef ] # FLM_ENCDEF_TAG - identify the encryption definition to use + + 1 key [EACHWORD] # FLM_KEY_TAG - 'use' defaults based on type + [ 2 base ] # FLM_BASE_TAG - base rec/field for fields below + [ 2 combinations # FLM_COMBINATIONS_TAG - how to handle repeating fields + { ALL | NORMALIZED}] + [ 2 post] # FLM_POST_TAG - case-flags post-pended to key + [ 2 required*] # FLM_REQUIRED_TAG - key value is required + [ 2 unique] # FLM_UNIQUE_TAG - key has only 1 reference + { 2 }... # FLM_FIELD_TAG - compound key if 2 or more + [ 3 case mixed | upper] # FLM_CASE_TAG - text-only, define chars case + [ 3 ]... # FLM_FIELD_TAG - alternate field(s) + [ 3 paired] # FLM_PAIRED_TAG - add field ID to key + [ 3 optional* # FLM_OPTIONAL_TAG - component's value is optional + | 3 required] # FLM_REQUIRED_TAG - component's value is required + [ 3 use eachword|value|field|minspaces|nounderscore|nospace|nodash] # FLM_USE_TAG + + == + n field # path identifies field -- maybe "based" + [ m type ] # FLM_TYPE_TAG - only for ixing unregistered fields + +Please Note: This code only supports the minimal old 11 index format + needed for skads databases. +****************************************************************************/ +FSTATIC RCODE DDIxParse( + TDICT * pTDict, + DDENTRY * pDDEntry, // Points to defined entry. + FlmRecord * pRecord, // Index definition record. + void * pvField) +{ + RCODE rc = FERR_OK; + FLMUINT uiIfdFlags; + FLMUINT uiTempIfdFlags; + FLMUINT uiBaseNum; + FLMUINT uiNLen; + TIXD * pTIxd; + TIFD * pLastTIfd; + TIFD * pTIfd; + void * pvTempField = NULL; + void * pvIfdField = NULL; + char szNativeBuf[ 64]; + FLMUINT uiCompoundPos; + FLMUINT uiTemp; + FLMBOOL bHasRequiredTag = TRUE; + FLMBOOL bOld11Mode = FALSE; + + if( (pTIxd = (TIXD *) GedPoolAlloc( &pTDict->pool, sizeof( TIXD))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTIxd->pNextTIfd = NULL; + pTIxd->uiFlags = 0; + pTIxd->uiContainerNum = FLM_DATA_CONTAINER; + pTIxd->uiNumFlds = 0; + pTIxd->uiLanguage = pTDict->uiDefaultLanguage; + pTIxd->uiEncId = 0; + + if( (pvField = pRecord->firstChild( pRecord->root())) == NULL) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + + pLastTIfd = NULL; + for( ; pvField; pvField = pRecord->nextSibling( pvField)) + { + switch ( pRecord->getFieldID( pvField)) + { + case FLM_CONTAINER_TAG: + { + char szTmpBuf [50]; + FLMUINT uiLen = sizeof( szTmpBuf); + + // See if a special keyword is used - ALL or * + + if ((pRecord->getDataType( pvField) == FLM_TEXT_TYPE) && + (RC_OK( pRecord->getNative( pvField, szTmpBuf, &uiLen))) && + (f_stricmp( "ALL", szTmpBuf) == 0 || + f_stricmp( "*", szTmpBuf) == 0)) + { + if (pTDict->pDb->pFile->FileHdr.uiVersionNum < + FLM_FILE_FORMAT_VER_4_50) + { + rc = RC_SET( FERR_UNSUPPORTED_FEATURE); + goto Exit; + } + + // Zero will mean all containers + + pTIxd->uiContainerNum = 0; + } + else + { + if( RC_BAD( rc = DDGetReference( pRecord, pvField, NULL, + &pTIxd->uiContainerNum))) + { + goto Exit; + } + if( pTIxd->uiContainerNum == 0) + { + pTIxd->uiContainerNum = FLM_DATA_CONTAINER; + } + } + break; + } + + case FLM_COUNT_TAG: + pTIxd->uiFlags |= IXD_COUNT; + break; + + case FLM_LANGUAGE_TAG: + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); + pTIxd->uiLanguage = FlmLanguage( szNativeBuf); + break; + + + case FLM_ENCDEF_TAG: + { + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); + pTIxd->uiEncId = f_atoud( szNativeBuf); + flmAssert( pTIxd->uiEncId); + break; + } + + case FLM_TYPE_TAG: + // Is only compound for NDS definitions. This parsers default. + bOld11Mode = TRUE; + break; + + case FLM_POSITIONING_TAG: + if (pTDict->pDb->pFile->FileHdr.uiVersionNum >= + FLM_FILE_FORMAT_VER_4_3) + { + pTIxd->uiFlags |= IXD_POSITIONING; + } + else + { + + // Positioning indexes not allowed prior to 4.3 + + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + break; + + case FLM_FIELD_TAG: + uiCompoundPos = 0; + uiBaseNum = 0; + uiIfdFlags = IFD_FIELD; + bHasRequiredTag = TRUE; + pvTempField = pvField; + bOld11Mode = TRUE; + goto Parse_Fields; + + case FLM_KEY_TAG: + uiCompoundPos = 0; + uiBaseNum = 0; + uiIfdFlags = IFD_FIELD | IFD_OPTIONAL; + bHasRequiredTag = FALSE; + + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvField, szNativeBuf, &uiNLen); + + if( f_strnicmp( szNativeBuf, "EACH", 4) == 0) + { + pTIxd->uiFlags |= IXD_EACHWORD; + uiIfdFlags = IFD_EACHWORD | IFD_OPTIONAL; + } + + if( (pvTempField = pRecord->firstChild( pvField)) == NULL) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } +Parse_Fields: + for( ; pvTempField; pvTempField = pRecord->nextSibling( pvTempField)) + { + switch( pRecord->getFieldID( pvTempField)) + { + case FLM_BASE_TAG: + if( RC_BAD( rc = DDGetReference( pRecord, + pvTempField, NULL, &uiBaseNum))) + { + goto Exit; + } + break; + + case FLM_COMBINATIONS_TAG: + rc = RC_SET( FERR_SYNTAX); + goto Exit; + + case FLM_POST_TAG: + pTIxd->uiFlags |= IXD_HAS_POST; + uiIfdFlags |= IFD_POST; + break; + + case FLM_REQUIRED_TAG: // Default - doesn't mean anything + break; + + case FLM_OPTIONAL_TAG: + rc = RC_SET( FERR_SYNTAX); + goto Exit; + + case FLM_UNIQUE_TAG : + pTIxd->uiFlags |= IXD_UNIQUE; + uiIfdFlags |= IFD_UNIQUE_PIECE; // Set the Unique Index Flag + break; + + case FLM_FIELD_TAG: + pTIxd->uiNumFlds++; + + if( bOld11Mode) + { + pvField = pvTempField; + } + + // Need to set IFD_COMPOUND if there is more than one field. + + if( pTIxd->uiNumFlds == 1 && + (pRecord->find( pvTempField, FLM_FIELD_TAG, 2) != NULL)) + { + uiIfdFlags |= IFD_COMPOUND; + } + + pTIfd = pLastTIfd; + if( RC_BAD(rc = DDBuildFldPath( pTDict, &pLastTIfd, + pRecord, pvTempField, uiBaseNum))) + { + goto Exit; + } + + pLastTIfd->uiCompoundPos = uiCompoundPos++; + + if( !pTIfd) // First time? + { + pTIxd->pNextTIfd = pLastTIfd; // Link first IFD + } + else + { + pTIfd->pNextTIfd = pLastTIfd; + } + uiTempIfdFlags = uiIfdFlags; + if( bOld11Mode) + { + // Default is required for each field. + uiTempIfdFlags &= ~IFD_OPTIONAL; + uiTempIfdFlags |= (IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); + } + + for( pvIfdField = pRecord->firstChild( pvTempField); + pvIfdField; pvIfdField = pRecord->nextSibling( pvIfdField)) + { + switch ( pRecord->getFieldID( pvIfdField)) + { + // + // General IFD options only for this field GROUP + // + case FLM_CASE_TAG: + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); + + if( f_strnicmp( szNativeBuf, "UPPE", 4) == 0) + { + uiTempIfdFlags |= IFD_UPPER; + } + break; + + case FLM_FIELD_TAG: + break; + + case FLM_OPTIONAL_TAG: + if( bOld11Mode) + { + // Old 11 format - default for each field is required. + uiTempIfdFlags |= IFD_OPTIONAL; + uiTempIfdFlags &= ~(IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); + } + // New format default is optional + break; + + case FLM_PAIRED_TAG: + uiTempIfdFlags |= IFD_FIELDID_PAIR; + break; + + case FLM_POST_TAG: + // FUTURE: Post piece where other pieces are not + uiTempIfdFlags |= IFD_POST; + break; + + case FLM_REQUIRED_TAG: + bHasRequiredTag = TRUE; + uiTempIfdFlags &= ~IFD_OPTIONAL; + uiTempIfdFlags |= (IFD_REQUIRED_PIECE | IFD_REQUIRED_IN_SET); + break; + + case FLM_LIMIT_TAG: + if( RC_BAD( pRecord->getUINT( pvIfdField, &uiTemp)) || + uiTemp > IFD_DEFAULT_LIMIT) + { + pLastTIfd->uiLimit = IFD_DEFAULT_LIMIT; + } + else + { + pLastTIfd->uiLimit = uiTemp; + } + break; + + case FLM_UNIQUE_TAG: + // FUTURE: option to select specific unique fields. + uiTempIfdFlags |= IFD_UNIQUE_PIECE; + pTIxd->uiFlags |= IXD_UNIQUE; + break; + + case FLM_USE_TAG: + // All these are exclusive values. Take the last value. + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); + + if( f_strnicmp( szNativeBuf, "EACH", 4) == 0) + { + uiTempIfdFlags |= IFD_EACHWORD; + uiTempIfdFlags &= ~(IFD_VALUE|IFD_SUBSTRING); + } + else if( f_strnicmp( szNativeBuf, "SUBS", 4) == 0) + { + pTIxd->uiFlags |= IXD_HAS_SUBSTRING; + uiTempIfdFlags |= IFD_SUBSTRING; + uiTempIfdFlags &= ~(IFD_VALUE|IFD_EACHWORD); + if( pLastTIfd->uiLimit == IFD_DEFAULT_LIMIT) + { + pLastTIfd->uiLimit = IFD_DEFAULT_SUBSTRING_LIMIT; + } + } + else if( f_strnicmp( szNativeBuf, "VALU", 4) == 0) + { + uiTempIfdFlags |= IFD_VALUE; + uiTempIfdFlags &= ~(IFD_EACHWORD|IFD_SUBSTRING); + } + else if( f_strnicmp( szNativeBuf, "FIEL", 4) == 0) + { + uiTempIfdFlags |= IFD_CONTEXT; + uiTempIfdFlags &= ~(IFD_VALUE|IFD_EACHWORD|IFD_SUBSTRING); + } + break; + + case FLM_FILTER_TAG: + uiNLen = sizeof( szNativeBuf); + (void) pRecord->getNative( pvIfdField, szNativeBuf, &uiNLen); + + if( f_strnicmp( szNativeBuf, "MINS", 4) == 0) + { + uiTempIfdFlags |= IFD_MIN_SPACES; + } + else if( f_strnicmp( szNativeBuf, "NOUN", 4) == 0) + { + uiTempIfdFlags |= IFD_NO_UNDERSCORE; + } + else if( f_strnicmp( szNativeBuf, "NOSP", 4) == 0) + { + uiTempIfdFlags |= IFD_NO_SPACE; + } + else if( f_strnicmp( szNativeBuf, "NODA", 4) == 0) + { + uiTempIfdFlags |= IFD_NO_DASH; + } + else + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + break; + + default: + if( pRecord->getFieldID( pvIfdField) < FLM_UNREGISTERED_TAGS && + pRecord->getFieldID( pvIfdField) != FLM_COMMENT_TAG) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + break; + } // end switch + } // end for loop parsing all level 3 tags + + // Parse again the level 3 field definitions. Now we + // have the IFD uiFlags value to assign each piece that + // will have the same compound position. + + pLastTIfd->uiFlags |= uiTempIfdFlags; + + for( pvIfdField = pRecord->firstChild( pvTempField); + pvIfdField; pvIfdField = pRecord->nextSibling( pvIfdField)) + { + if( pRecord->getFieldID( pvIfdField) == FLM_FIELD_TAG ) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + break; // Done parsing "2 field xx yy zz" + + default: + if( bOld11Mode) + { + break; + } + + if( pRecord->getFieldID( pvTempField) < FLM_UNREGISTERED_TAGS && + pRecord->getFieldID( pvTempField) != FLM_COMMENT_TAG) + + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + break; + } // end switch + + } // end for loop + + // Special case for optional + if( !bHasRequiredTag) + { + // Set all of the IFD flags to IFD_REQUIRED_IN_SET + for( pTIfd = pTIxd->pNextTIfd; pTIfd; pTIfd = pTIfd->pNextTIfd) + { + pTIfd->uiFlags |= IFD_REQUIRED_IN_SET; + } + } + break; + + default: + if( pRecord->getFieldID( pvField) < FLM_UNREGISTERED_TAGS && + pRecord->getFieldID( pvField) != FLM_COMMENT_TAG) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + break; + } + } + pDDEntry->vpDef = (void *) pTIxd; + +Exit: + + if( RC_BAD(rc)) + { + if( pvIfdField) + pTDict->uiBadField = pRecord->getFieldID( pvIfdField); + else if( pvTempField) + pTDict->uiBadField = pRecord->getFieldID( pvTempField); + else if( pvField) + pTDict->uiBadField = pRecord->getFieldID( pvField); + } + else + { + pTDict->uiNewIxds++; + pTDict->uiNewIfds += pTIxd->uiNumFlds; + pTDict->uiNewLFiles++; + } + return( rc ); +} + +/**************************************************************************** +Desc: Build field path for each index field. This function will also + check for the existence of the 'batch' option for QF indexes. +****************************************************************************/ +FSTATIC RCODE DDBuildFldPath( + TDICT * pTDict, + TIFD ** ppTIfd, + FlmRecord * pRecord, + void * pvField, + FLMUINT uiBaseNum) +{ + RCODE rc = FERR_OK; + TIFD * pTIfd; + TIFP * pLastFldPath; + TIFP * pTIfp; + FLMUINT uiNumInFldPath; + char szNameBuf[ 32 ]; + char * pszCurrent; + char szNativeBuf[ FDD_MAX_VALUE_SIZE]; + FLMUINT uiBufLen; + FLMUINT uiPos; + + pTDict->uiTotalIfds++; + if( (pTIfd = (TIFD *) GedPoolAlloc( &pTDict->pool, sizeof( TIFD))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTIfd->pTIfp = NULL; + pTIfd->pNextTIfd = NULL; + pTIfd->uiFlags = 0; + pTIfd->uiNextFixupPos = 0; + pTIfd->uiLimit = IFD_DEFAULT_LIMIT; + pTIfd->uiCompoundPos = 0; + + pLastFldPath = NULL; + *ppTIfd = pTIfd; + + // Build the field paths + + DDTextToNative( pRecord, pvField, szNativeBuf, + FDD_MAX_VALUE_SIZE, &uiBufLen); + + pszCurrent = szNativeBuf; + uiNumInFldPath = uiPos = 0; + + if( uiBaseNum ) + { + uiNumInFldPath++; + if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, + sizeof( TIFP ))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pTIfp->pNextTIfp = NULL; + pTIfp->bFieldInThisDict = FALSE; + pTIfp->uiFldNum = uiBaseNum; + pTIfd->pTIfp = pTIfp; + pLastFldPath = pTIfp; + } + + while( uiPos < uiBufLen) + { + uiNumInFldPath++; + if( DDMoveWord( szNameBuf, pszCurrent, + sizeof( szNameBuf ), &uiPos ) == FALSE ) + { + break; + } + + if( (pTIfp = (TIFP *) GedPoolAlloc( &pTDict->pool, + sizeof( TIFP ))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pTIfp->pNextTIfp = NULL; + pTIfp->bFieldInThisDict = FALSE; + + if( pTIfd->pTIfp == NULL) + { + pTIfd->pTIfp = pTIfp; + } + else + { + pLastFldPath->pNextTIfp = pTIfp; + } + + pLastFldPath = pTIfp; + + // See if there is a wildcard in the path. + + if (f_stricmp( szNameBuf, "*") == 0) + { + if (pTDict->pDb->pFile->FileHdr.uiVersionNum < + FLM_FILE_FORMAT_VER_4_50) + { + rc = RC_SET( FERR_UNSUPPORTED_FEATURE); + goto Exit; + } + else + { + pTIfp->uiFldNum = FLM_ANY_FIELD; + } + } + else + { + if( RC_BAD( rc = DDGetReference( NULL, NULL, szNameBuf, + &pTIfp->uiFldNum))) + { + goto Exit; + } + } + } + + if( uiNumInFldPath == 0) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + + // Cannot have wildcard in last field of field path. + + if (pLastFldPath->uiFldNum == FLM_ANY_FIELD) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + + // Single field has the field NULL terminated + + if( uiNumInFldPath == 1 ) + { + pTDict->uiNewFldPaths += 2; + } + else + { + // The field paths are stored child to parent and parent to child + // each are zero terminated. + + pTDict->uiNewFldPaths += 2 * (uiNumInFldPath + 1); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Parse a data dictionary domain definition for correct syntax & + assign the correct attributes. +****************************************************************************/ +FSTATIC RCODE DDContainerParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + void * pvField = NULL; + + if( pDDEntry) + { + + if( (pvField = pRecord->firstChild( pRecord->root())) != NULL) + { + for( ; pvField; pvField = pRecord->nextSibling( pvField)) + { + // Only option is unregistered fields + + if( pRecord->getFieldID( pvField) < FLM_FREE_TAG_NUMS) + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + } + } + +Exit: + + if( RC_BAD(rc) && pvField) + { + pTDict->uiBadField = pRecord->getFieldID( pvField); + } + + return( rc ); +} + +/**************************************************************************** +Desc: Parse a data dictionary domain definition for correct syntax & + assign the correct attributes. +****************************************************************************/ +FSTATIC RCODE DDEncDefParse( + TDICT * pTDict, + DDENTRY * pDDEntry, + FlmRecord * pRecord, + FLMUINT uiDictRecNum) +{ + RCODE rc = FERR_OK; + void * pvField = NULL; + TENCDEF * pTEncDef; + + // Make sure the version of the database is correct for encryption. + + if (pTDict->pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_60) + { + rc = RC_SET( FERR_UNSUPPORTED_FEATURE); + goto Exit; + } + + if( (pTEncDef = (TENCDEF *)GedPoolAlloc( &pTDict->pool, + sizeof(TENCDEF))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pTEncDef->uiRecNum = uiDictRecNum; + pTEncDef->uiAlgType = 0; + pTEncDef->uiState = 0; + pTEncDef->pucKeyInfo = NULL; + pTEncDef->uiLength = 0; + + if( pDDEntry) + { + + if( (pvField = pRecord->firstChild( pRecord->root())) != NULL) + { + for( ; pvField; pvField = pRecord->nextSibling( pvField)) + { + switch ( pRecord->getFieldID( pvField) ) + { + case FLM_TYPE_TAG: + { + // Get the encryption type. + if (RC_BAD( rc = DDGetEncType( pRecord, + pvField, + &pTEncDef->uiAlgType))) + { + goto Exit; + } + break; + } + + case FLM_KEY_TAG: + { + // Get the key information. + if (RC_BAD( rc = DDGetEncKey( pTDict, + pRecord, + pvField, + pTEncDef))) + { + goto Exit; + } + break; + } + + case FLM_STATE_TAG: + { + // Get the status information. + if (RC_BAD( rc = DDParseStateOptions( pRecord, + pvField, + &pTEncDef->uiState))) + { + goto Exit; + } + break; + } + + default: + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + } + + pDDEntry->vpDef = (void *)pTEncDef; + + } + else + { + rc = RC_SET( FERR_SYNTAX); + goto Exit; + } + } + +Exit: + + if (RC_BAD( rc) && pvField) + { + pTDict->uiBadField = pRecord->getFieldID( pvField); + } + + return( rc ); +} + +/**************************************************************************** +Desc: Move word delimited by spaces from src to dest. Used to move a + word at a time for field path lists. +Notes: Isolated so changes can be made to delemeting NAMES. +Visit: Still bugs when name > buffer size - won't happen because only #'s +****************************************************************************/ +FSTATIC FLMBOOL DDMoveWord( + char * pucDest, + char * pucSrc, + FLMUINT uiMaxDestLen, + FLMUINT * puiPos) +{ + FLMBOOL bFoundWord = TRUE; + FLMUINT uiPos = *puiPos; + char * pMatch; + FLMUINT uiBytesToCopy; + + pucSrc += uiPos; + while( *pucSrc == NATIVE_SPACE) + { + pucSrc++; + } + + pMatch = pucSrc; + while( *pMatch > NATIVE_SPACE) + { + pMatch++; + } + + if( !*pMatch) + { + if( *pucSrc == '\0') + { + bFoundWord = FALSE; + goto Exit; + } + + uiBytesToCopy = f_strlen( pucSrc); + + if( uiBytesToCopy + 1 > uiMaxDestLen) + { + uiBytesToCopy = uiMaxDestLen - 1; + } + + f_memcpy( pucDest, pucSrc, uiBytesToCopy + 1); + *puiPos = uiPos + uiBytesToCopy + 1; + } + else + { + // Copy the bytes between pucSrc and pMatch minus one + + uiBytesToCopy = (FLMUINT) (pMatch - pucSrc); + + if( uiBytesToCopy + 1 > uiMaxDestLen) + { + uiBytesToCopy = uiMaxDestLen - 1; + } + + f_memcpy( pucDest, pucSrc, uiBytesToCopy ); + pucDest[ uiBytesToCopy ] = '\0'; + + // Go past consuctive spaces + + while( pucSrc[ ++uiBytesToCopy ] == NATIVE_SPACE) + { + uiBytesToCopy++; + } + + *puiPos = uiPos + uiBytesToCopy; + } + +Exit: + + return( bFoundWord); +} + +/**************************************************************************** +Desc: Normalizes an internal string with possible formatting codes into + a NATIVE string. Drops all formatting codes and extended chars. +****************************************************************************/ +FSTATIC void DDTextToNative( + FlmRecord * pRecord, + void * pvField, + char * pszBuffer, + FLMUINT uiBufLen, + FLMUINT * puiBufLen) +{ + RCODE rc = FERR_OK; + + pszBuffer[ 0] = 0; + + if( pRecord->getDataLength( pvField)) + { + if( RC_BAD( rc = pRecord->getNative( pvField, pszBuffer, &uiBufLen))) + { + if( rc != FERR_CONV_DEST_OVERFLOW) + { + pszBuffer[0] = 0; + uiBufLen = 0; + } + } + } + else + { + uiBufLen = 0; + } + + if( puiBufLen) + { + // Length needs to include the null byte + + *puiBufLen = uiBufLen + 1; + } + + return; +} + +/**************************************************************************** +Desc: Allocate the LFILE and read in the LFile entries. The default + data container and the dictionary container will be at hard coded + slots at the first of the table. The LFiles do not need to be in + any numeric order. +****************************************************************************/ +RCODE fdictReadLFiles( + FDB * pDb, + FDICT * pDict) +{ + RCODE rc = FERR_OK; + LFILE * pLFiles = NULL; + LFILE * pLFile; + SCACHE * pSCache; + FLMBOOL bReleaseCache = FALSE; + FLMBYTE * pucBlk; + FLMUINT uiBlkAddress; + FLMUINT uiPos; + FLMUINT uiEndPos; + FLMUINT uiEstCount; + FLMUINT uiLFileCnt; + FLMUINT uiLFHCnt; + FFILE * pFile = pDb->pFile; + FLMUINT uiBlkSize = pFile->FileHdr.uiBlockSize; + LFILE TmpLFile; + + f_memset( &TmpLFile, 0, sizeof( LFILE)); + + for( uiEstCount = 0, uiLFileCnt = 4, + uiBlkAddress = pDb->pFile->FileHdr.uiFirstLFHBlkAddr; + uiBlkAddress != BT_END; ) + { + if( RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_LFH_BLK, + uiBlkAddress, NULL, &pSCache))) + { + goto Exit; + } + bReleaseCache = TRUE; + + pucBlk = pSCache->pucBlk; + uiPos = BH_OVHD; + if( (uiEndPos = (FLMUINT)FB2UW( &pucBlk[ BH_ELM_END])) <= BH_OVHD) + { + uiEndPos = BH_OVHD; + uiLFHCnt = 0; + } + else + { + if( uiEndPos > uiBlkSize) + { + uiEndPos = uiBlkSize; + } + + uiLFHCnt = (FLMUINT)((uiEndPos - BH_OVHD) / LFH_SIZE); + uiEndPos = (FLMUINT)(BH_OVHD + uiLFHCnt * LFH_SIZE); + } + + // May allocate too many like the inactive ones but OK for now. + // Allocate an additional 2 for the default data and dict containers. + + if( !uiEstCount) + { + uiEstCount = uiLFHCnt + uiLFileCnt; + if( uiEstCount) + { + if( RC_BAD( rc = f_calloc( uiEstCount * sizeof( LFILE), &pLFiles))) + { + goto Exit; + } + } + } + else if( uiLFHCnt) + { + uiEstCount += uiLFHCnt; + + if( RC_BAD(rc = f_recalloc( uiEstCount * sizeof(LFILE), &pLFiles))) + { + goto Exit; + } + } + + // Read through all of the logical file definitions in the block + + for( ; uiPos < uiEndPos; uiPos += LFH_SIZE) + { + FLMUINT uiLfNum; + + // Have to fix up the offsets later when they are read in + + if( RC_BAD( rc = flmBufferToLFile( &pucBlk[ uiPos], &TmpLFile, + uiBlkAddress, uiPos))) + { + goto Exit; + } + + if( TmpLFile.uiLfType == LF_INVALID) + { + continue; + } + + uiLfNum = TmpLFile.uiLfNum; + + if( uiLfNum == FLM_DATA_CONTAINER) + { + pLFile = pLFiles + LFILE_DATA_CONTAINER_OFFSET; + } + else if( uiLfNum == FLM_DICT_CONTAINER) + { + pLFile = pLFiles + LFILE_DICT_CONTAINER_OFFSET; + } + else if( uiLfNum == FLM_DICT_INDEX) + { + pLFile = pLFiles + LFILE_DICT_INDEX_OFFSET; + } + else if( uiLfNum == FLM_TRACKER_CONTAINER) + { + pLFile = pLFiles + LFILE_TRACKER_CONTAINER_OFFSET; + } + else + { + pLFile = pLFiles + uiLFileCnt++; + } + + f_memcpy( pLFile, &TmpLFile, sizeof(LFILE)); + } + + // Get the next block in the chain + + uiBlkAddress = (FLMUINT)FB2UD( &pucBlk[ BH_NEXT_BLK]); + ScaReleaseCache( pSCache, FALSE); + bReleaseCache = FALSE; + } + + // This routine could be called to re-read in the dictionary. + + if( pDict->pLFileTbl) + { + f_free( &pDict->pLFileTbl); + } + + pDict->pLFileTbl = pLFiles; + pDict->uiLFileCnt = uiLFileCnt; + +Exit: + + if( bReleaseCache) + { + ScaReleaseCache( pSCache, FALSE); + } + + if( RC_BAD(rc) && pLFiles) + { + f_free( &pLFiles); + } + + return( rc); +} + +/**************************************************************************** +Desc: Add data dictionary records to the data dictionary. +****************************************************************************/ +RCODE fdictCreate( + FDB * pDb, + const char * pszDictPath, + const char * pDictBuf) +{ + RCODE rc = FERR_OK; + F_FileHdl * pDictFileHdl = NULL; + FlmRecord * pDictRec = NULL; + void * pvField; + const char * pucGedBuf; + LFILE * pDictContLFile; + LFILE * pDictIxLFile; + FLMUINT uiDrn = 0; + FLMUINT uiCurrDictNum; + FLMUINT uiLFileCount; + FLMBOOL bFileOpen = FALSE; + LFILE DictContLFile; + LFILE DictIxLFile; + LFILE TempLFile; + char ucTempBuf[ 256]; + FLMUINT uiBufLen = sizeof( ucTempBuf); + F_NameTable nameTable; + + // Initialize the name table + + if( RC_BAD( rc = nameTable.setupFromDb( HFDB_NULL))) + { + goto Exit; + } + + // Create Dictionary and Default Data containers + + if( RC_BAD(rc = flmLFileCreate( pDb, &DictContLFile, FLM_DICT_CONTAINER, + LF_CONTAINER))) + { + goto Exit; + } + uiCurrDictNum = FLM_DICT_CONTAINER; + + if( RC_BAD(rc = flmLFileCreate( pDb, &TempLFile, FLM_DATA_CONTAINER, + LF_CONTAINER))) + { + goto Exit; + } + + if( RC_BAD( rc = flmLFileCreate( pDb, &DictIxLFile, FLM_DICT_INDEX, + LF_INDEX))) + { + goto Exit; + } + + if( RC_BAD( rc = flmLFileCreate( pDb, &TempLFile, FLM_TRACKER_CONTAINER, + LF_CONTAINER))) + { + goto Exit; + } + + uiLFileCount = 4; + + // If we have a GEDCOM buffer, there is no need to open the file + + if( pDictBuf) + { + pucGedBuf = pDictBuf; + uiBufLen = f_strlen( pDictBuf) + 1; + } + else if( pszDictPath) + { + pucGedBuf = ucTempBuf; + if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( + pszDictPath, F_IO_RDONLY, &pDictFileHdl))) + { + goto Exit; + } + bFileOpen = TRUE; + } + else + { + // Neither a dictionary buffer or file were specified. Create will + // be done with an empty dictionary. + + goto Done_Getting_Dict; + } + + // Create a new FDICT so we can write the dictionary records. + // This FDICT is temporary and will be allocated again. + + if( RC_BAD( rc = fdictCreateNewDict( pDb))) + { + goto Exit; + } + + if( (pDictRec = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if( RC_BAD( rc = fdictGetContainer( pDb->pDict, + FLM_DICT_CONTAINER, &pDictContLFile))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictGetIndex( pDb->pDict, + pDb->pFile->bInLimitedMode, + FLM_DICT_INDEX, &pDictIxLFile, NULL))) + { + goto Exit; + } + + // Read through the dictionary records, adding them or creating dictionaries + // as we go. + + for( ;;) + { + // Get records from buffer or file + + rc = ( pDictFileHdl) + ? pDictRec->importRecord( pDictFileHdl, &nameTable) + : pDictRec->importRecord( &pucGedBuf, uiBufLen, &nameTable); + + if( RC_BAD( rc)) + { + if( rc == FERR_END || rc == FERR_EOF_HIT) + { + rc = FERR_OK; + break; + } + else if( uiDrn) + { + // If an error occur then at least set the DRN of the + // previous record in the diagnostic information. + + pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; + pDb->Diag.uiDrn = uiDrn; + } + + goto Exit; + } + + // See if we are switching dictionaries. + + pvField = pDictRec->root(); + if( pDictRec->getFieldID( pvField) == FLM_DICT_TAG) + { + rc = RC_SET( FERR_INVALID_TAG); + goto Exit; + } + + // Assign all fields a DRN value - parse for completeness. + // If there is no DRN in the record (zero), one will be assigned + // by FDDDictRecUpdate. + + uiDrn = pDictRec->getID(); + + // Add the data dictionary record. This also checks to see + // if the record is already defined. + + if( RC_BAD( rc = fdictRecUpdate( pDb, pDictContLFile, + pDictIxLFile, &uiDrn, pDictRec, NULL))) + { + goto Exit; + } + + // Don't need to do the processing below if it is not a record + // being put into the dictionary. + + if( uiCurrDictNum != FLM_DICT_CONTAINER) + { + continue; + } + + // Create an LFILE for each index and container. + + if( pDictRec->getFieldID( pvField) == FLM_INDEX_TAG || + pDictRec->getFieldID( pvField) == FLM_CONTAINER_TAG) + { + pvField = pDictRec->root(); + if( RC_BAD( rc = flmLFileCreate( pDb, &TempLFile, uiDrn, + ((pDictRec->getFieldID( pvField) == FLM_INDEX_TAG) + ? (FLMUINT)LF_INDEX + : (FLMUINT)LF_CONTAINER)))) + { + goto Exit; + } + + uiLFileCount++; + } + } + +Done_Getting_Dict: + + // Create the FDICT again, this time with the dictionary pcode. + + if( RC_BAD( rc = fdictCreateNewDict( pDb))) + { + goto Exit; + } + +Exit: + + if( bFileOpen) + { + pDictFileHdl->Close(); + } + + if( pDictFileHdl) + { + pDictFileHdl->Release(); + } + + if( pDictRec) + { + pDictRec->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Creates a new dictionary for a database. + This occurs when on database create and on a dictionary change. +****************************************************************************/ +RCODE fdictCreateNewDict( + FDB * pDb) +{ + RCODE rc = FERR_OK; + + // Unlink the DB from the current FDICT, if any. + + if( pDb->pDict) + { + f_mutexLock( gv_FlmSysData.hShareMutex); + flmUnlinkFdbFromDict( pDb); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + } + + // Allocate a new FDICT structure for the new dictionary we + // are going to create. + + if( RC_BAD( rc = fdictRebuild( pDb))) + { + goto Exit; + } + + // Update the FDB structure to indicate that the dictionary + // was updated. + + pDb->uiFlags |= FDB_UPDATED_DICTIONARY; + +Exit: + + // If we allocated an FDICT and there was an error, free the FDICT. + + if( (RC_BAD( rc)) && (pDb->pDict)) + { + flmFreeDict( pDb->pDict); + pDb->pDict = NULL; + } + + return( rc); +} + +/**************************************************************************** +Desc: Add a new field, container or index definition to the dictionary. +****************************************************************************/ +RCODE flmAddRecordToDict( + FDB * pDb, + FlmRecord * pRecord, + FLMUINT uiDictId, + FLMBOOL bRereadLFiles) +{ + RCODE rc = FERR_OK; + TDICT tDict; + FLMBOOL bTDictInitialized = FALSE; + + if( RC_BAD( rc = fdictCopySkeletonDict( pDb))) + { + goto Exit; + } + + bTDictInitialized = TRUE; + if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictProcessRec( &tDict, pRecord, uiDictId))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictBuildTables( &tDict, bRereadLFiles, TRUE))) + { + goto Exit; + } + + pDb->uiFlags |= FDB_UPDATED_DICTIONARY; + +Exit: + + if( bTDictInitialized) + { + GedPoolFree( &tDict.pool); + } + + // If we allocated an FDICT and there was an error, free the FDICT. + + if( (RC_BAD( rc)) && (pDb->pDict)) + { + flmFreeDict( pDb->pDict); + pDb->pDict = NULL; + } + + return( rc); +} + +/**************************************************************************** +Desc: Add an index a dictionary record to the container LFILE and the + index LFILE. +****************************************************************************/ +RCODE fdictRecUpdate( + FDB * pDb, + LFILE * pDictContLFile, + LFILE * pDictIxLFile, + FLMUINT * puiDrnRV, + FlmRecord * pNewRec, + FlmRecord * pOldRec, + FLMBOOL bRebuildOp) +{ + RCODE rc = FERR_OK; + FLMUINT uiDrn = *puiDrnRV; + FLMBOOL bAllocatedID; + void * pvField; + FLMBYTE * pucKeyField = NULL; + FLMUINT32 ui32BufLen; + FLMUINT uiEncType; + + bAllocatedID = FALSE; + + // Make sure we are using a valid DRN + + if( (uiDrn >= FLM_RESERVED_TAG_NUMS) && + (uiDrn != 0xFFFFFFFF)) + { + pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; + pDb->Diag.uiDrn = uiDrn; + rc = RC_SET( FERR_BAD_DICT_DRN); + goto Exit; + } + + // Allocate an unused DRN, if one has not been allocated. + + if( (pNewRec) && ((!uiDrn) || (uiDrn == 0xFFFFFFFF))) + { + FLMBOOL bAllocAtEnd = (!uiDrn) ? TRUE : FALSE; + + bAllocatedID = TRUE; + if( bAllocAtEnd) + { + if( RC_BAD( rc = FSGetNextDrn( pDb, pDictContLFile, FALSE, &uiDrn))) + { + goto Exit; + } + } + else + { + // Scott 12/99: This must not be called any more. + // The code merged ITT values into the table. + + flmAssert(0); + } + + // Verify that we are not at our highest possible dictionary DRN. + + if( uiDrn >= FLM_RESERVED_TAG_NUMS) + { + rc = RC_SET( FERR_NO_MORE_DRNS); + goto Exit; + } + } + + // The following code makes sure that the DRN and name have not already been + // used, if adding. It also makes sure that there is no conflict in + // the type/name index. It checks the entire shared dictionary + // hierarchy if necessary - child and parent - to ensure no + // conflicts. + + if( pNewRec) + { + // Check for ID conflicts in the dictionary being added to + + if( (!pOldRec) && (!bAllocatedID)) + { + if( RC_BAD( rc = DDCheckIDConflict( pDb, pDictContLFile, uiDrn))) + { + if( (rc == FERR_ID_RESERVED) || (rc == FERR_DUPLICATE_DICT_REC)) + { + pvField = pNewRec->root(); + if( (rc == FERR_DUPLICATE_DICT_REC) && + (pNewRec->getFieldID( pvField) == FLM_RESERVED_TAG)) + { + rc = RC_SET( FERR_CANNOT_RESERVE_ID); + } + pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; + pDb->Diag.uiDrn = uiDrn; + } + goto Exit; + } + } + + // Check for name conflicts in the dictionary being added to + + if (pNewRec) + { + if (RC_BAD( rc = DDCheckNameConflict( pDb, pDictIxLFile, pNewRec, + uiDrn, pOldRec))) + goto Exit; + } + } + + if (!pOldRec && pNewRec) + { + // If this is an encryption definition record, we need to generate + // a new key. + + if (pNewRec->getFieldID( pNewRec->root()) == FLM_ENCDEF_TAG && + !bRebuildOp && !(pDb->uiFlags & FDB_REPLAYING_RFL)) + { + F_CCS Ccs; + + // If we are running in limited mode, we will not be able to complete + // this operation. + + if( pDb->pFile->bInLimitedMode) + { + rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); + goto Exit; + } + + // Should not have a key yet. + + if( pNewRec->find(pNewRec->root(), + FLM_KEY_TAG) != NULL) + { + rc = RC_SET( FERR_CANNOT_SET_KEY); + goto Exit; + } + + if( (pvField = pNewRec->find( pNewRec->root(), + FLM_TYPE_TAG)) == NULL) + { + rc = RC_SET( FERR_MISSING_ENC_TYPE); + goto Exit; + } + + if( RC_BAD( rc = DDGetEncType( pNewRec, pvField, &uiEncType))) + { + goto Exit; + } + + if( RC_BAD( rc = Ccs.init( FALSE, uiEncType))) + { + goto Exit; + } + + if( RC_BAD( rc = Ccs.generateEncryptionKey())) + { + goto Exit; + } + + if( RC_BAD( rc = Ccs.getKeyToStore( &pucKeyField, &ui32BufLen, + NULL, pDb->pFile->pDbWrappingKey))) + { + goto Exit; + } + + // Create the key field + + if( RC_BAD( rc = pNewRec->insert( pNewRec->root(), INSERT_LAST_CHILD, + FLM_KEY_TAG, FLM_TEXT_TYPE, &pvField))) + { + goto Exit; + } + + // Set the value of the new field + + if( RC_BAD( rc = pNewRec->setNative( pvField, + (const char *)pucKeyField))) + { + goto Exit; + } + } + } + + // Delete the old record and its index entries, if any + + if( pOldRec) + { + // Delete the old record's index entries + + if( RC_BAD( rc = DDIxDictRecord( pDb, pDictIxLFile, uiDrn, + pOldRec, KREF_DELETE_FLAG))) + { + goto Exit; + } + + // Delete the old record - unless it is a modify + + if( !pNewRec) + { + if( RC_BAD( rc = FSRecUpdate( pDb, pDictContLFile, NULL, uiDrn, + REC_UPD_DELETE))) + { + goto Exit; + } + } + } + + // Add the new record, if any + + if( pNewRec) + { + // Add the record's index keys + + if( RC_BAD( rc = DDIxDictRecord( pDb, pDictIxLFile, uiDrn, + pNewRec, 0))) + { + goto Exit; + } + + // Add or modify the record itself + + if( RC_BAD( rc = FSRecUpdate( pDb, pDictContLFile, pNewRec, + uiDrn, (FLMUINT)((pOldRec) + ? (FLMUINT)REC_UPD_MODIFY + : (FLMUINT)REC_UPD_ADD)))) + { + goto Exit; + } + } + +Exit: + + if( RC_OK( rc)) + { + *puiDrnRV = uiDrn; + } + + if (pucKeyField) + { + f_free( &pucKeyField); + } + + return( rc); +} + +/**************************************************************************** +Desc: Creates a collated type/name key for a dictionary record. +****************************************************************************/ +FSTATIC RCODE DDMakeDictIxKey( + FDB * pDb, + FlmRecord * pRecord, + FLMBYTE * pKeyBuf, + FLMUINT * puiKeyLenRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiElmLen; + FLMUINT uiKeyLen = 0; + void * pvField = pRecord->root(); + const FLMBYTE * pExportPtr; + + // Collate the name + + pExportPtr = pRecord->getDataPtr( pvField), + uiElmLen = MAX_KEY_SIZ - uiKeyLen; + + if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, + pExportPtr, pRecord->getDataLength( pvField), FLM_TEXT_TYPE, + uiElmLen, NULL, NULL, pDb->pFile->FileHdr.uiDefaultLanguage, + FALSE, FALSE, FALSE, NULL))) + { + goto Exit; + } + + uiKeyLen += uiElmLen; + +Exit: + + *puiKeyLenRV = uiKeyLen; + return( rc); +} + +/**************************************************************************** +Desc: Checks to make sure a dictionary name has not already been used. +****************************************************************************/ +FSTATIC RCODE DDCheckNameConflict( + FDB * pDb, + LFILE * pDictIxLFile, + FlmRecord * pNewRec, + FLMUINT uiDrn, + FlmRecord * pOldRec) +{ + RCODE rc = FERR_OK; + BTSK StackArray[ BH_MAX_LEVELS]; + BTSK * pStack; + FLMBYTE BtKeyBuf[ MAX_KEY_SIZ]; + FLMBYTE IxKeyBuf[ MAX_KEY_SIZ]; + FLMUINT uiKeyLen; + void * pvField; + + FSInitStackCache( &StackArray [0], BH_MAX_LEVELS); + + if (RC_BAD( rc = DDMakeDictIxKey( pDb, pNewRec, IxKeyBuf, &uiKeyLen))) + { + goto Exit; + } + + StackArray[0].pKeyBuf = BtKeyBuf; + pStack = StackArray; + + if (RC_BAD( rc = FSBtSearch( pDb, pDictIxLFile, &pStack, + IxKeyBuf, uiKeyLen, 0L))) + { + goto Exit; + } + + if (pStack->uiCmpStatus == BT_EQ_KEY) + { + FLMUINT uiElmDoman; + DIN_STATE DinState; + FLMUINT uiFoundDrn; + + // If this is an ADD (!pOldRec), or the record found is different than + // the one being updated, we have a problem. + + uiFoundDrn = FSRefFirst( pStack, &DinState, &uiElmDoman); + if ((!pOldRec) || (uiFoundDrn != uiDrn)) + { + pvField = pNewRec->root(); + pDb->Diag.uiInfoFlags |= FLM_DIAG_DRN; + pDb->Diag.uiDrn = uiDrn; + rc = (pNewRec->getFieldID( pvField) == FLM_RESERVED_TAG) + ? RC_SET( FERR_CANNOT_RESERVE_NAME) + : RC_SET( FERR_DUPLICATE_DICT_NAME); + goto Exit; + } + } + +Exit: + + FSReleaseStackCache( StackArray, BH_MAX_LEVELS, FALSE); + return( rc); +} + +/**************************************************************************** +Desc: Checks to make sure a dictionary DRN has not already been used. +****************************************************************************/ +FSTATIC RCODE DDCheckIDConflict( + FDB * pDb, + LFILE * pDictContLFile, + FLMUINT uiDrn) +{ + RCODE rc = FERR_OK; + FlmRecord * pOldRec = NULL; + + // Read to see if there is an existing record. + // NOTE: Deliberately not bringing into cache if not found. + + if( RC_BAD( rc = FSReadRecord( pDb, pDictContLFile, uiDrn, + &pOldRec, NULL, NULL))) + { + if (rc == FERR_NOT_FOUND) + { + rc = FERR_OK; + } + else + { + goto Exit; + } + } + + if( pOldRec) + { + void * pvField = pOldRec->root(); + + rc = ( pOldRec->getFieldID( pvField) == FLM_RESERVED_TAG) + ? RC_SET( FERR_ID_RESERVED) + : RC_SET( FERR_DUPLICATE_DICT_REC); + } + +Exit: + + if( pOldRec) + { + pOldRec->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: Generate a key for an index record and add or delete it from + the index. +****************************************************************************/ +FSTATIC RCODE DDIxDictRecord( + FDB * pDb, + LFILE * pDictIxLFile, + FLMUINT uiDrn, + FlmRecord * pRecord, + FLMUINT uiFlags) +{ + RCODE rc; + union + { + FLMBYTE KeyBuf [sizeof( KREF_ENTRY) + MAX_KEY_SIZ]; + KREF_ENTRY KrefEntry; + }; + FLMUINT uiKeyLen; + + flmAssert( pDictIxLFile->uiLfNum > 0 && + pDictIxLFile->uiLfNum < FLM_UNREGISTERED_TAGS); // Sanity check + KrefEntry.ui16IxNum = (FLMUINT16)pDictIxLFile->uiLfNum; + KrefEntry.uiDrn = uiDrn; + KrefEntry.uiFlags = uiFlags; + KrefEntry.uiTrnsSeq = 1; + + // Add or delete the key/reference + + if (RC_BAD( rc = DDMakeDictIxKey( pDb, pRecord, + &KeyBuf [sizeof( KREF_ENTRY)], &uiKeyLen))) + { + goto Exit; + } + KrefEntry.ui16KeyLen = (FLMUINT16)uiKeyLen; + + if( RC_BAD( rc = FSRefUpdate( pDb, pDictIxLFile, &KrefEntry))) + { + goto Exit; + } + +Exit: + + return( rc); +} + /*************************************************************************** Desc: Get the field information. Try shared first and then local. ****************************************************************************/ @@ -372,9 +2938,10 @@ RCODE fdictGetNextIXD( } } + // Special case -- return the dictionary index + if( !pIxd && uiIndexNum < FLM_DICT_INDEX) { - // Special case -- return the dictionary index pIxd = pDict->pIxdTbl; } @@ -396,8 +2963,6 @@ RCODE fdictGetNextIXD( Exit: - // Always set the return parm. - if( ppIxd) { *ppIxd = pIxd; @@ -405,3 +2970,1314 @@ Exit: return( rc); } + +/**************************************************************************** +Desc: Rebuild the dictionary tables reading in all dictionary + records. +****************************************************************************/ +RCODE fdictRebuild( + FDB * pDb) +{ + RCODE rc = FERR_OK; + TDICT tDict; + FLMUINT uiCount; + IXD * pIxd; + FLMBOOL bTDictInitialized = FALSE; + FLMBOOL bSuspended; + FLMUINT uiOnlineTransId; + + // Allocate a new FDICT structure for reading the local dictionary + // into memory. + // At this point, pDb better not be pointing to a dictionary. + + flmAssert( pDb->pDict == NULL); + if( RC_BAD( rc = flmAllocDict( &pDb->pDict))) + { + goto Exit; + } + + if( !pDb->pDict->pLFileTbl) + { + // Read the local dictionary into memory. + + if( RC_BAD(rc = fdictReadLFiles( pDb, pDb->pDict))) + { + goto Exit; + } + + // For a database create the LFiles still are not created. + + if( pDb->pDict->pLFileTbl->uiLfNum == 0) + { + goto Exit; + } + } + + bTDictInitialized = TRUE; + if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictProcessAllDictRecs( pDb, &tDict))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictBuildTables( &tDict, FALSE, FALSE))) + { + goto Exit; + } + + // Loop through the IXD and set the uiLastDrnIndexed value. + + uiCount = pDb->pDict->uiIxdCnt; + for( pIxd = pDb->pDict->pIxdTbl; uiCount--; pIxd++) + { + // Ignore any errors in case we are rebuilding. + + if( RC_BAD( flmGetIxTrackerInfo( pDb, pIxd->uiIndexNum, + &pIxd->uiLastContainerIndexed, + &pIxd->uiLastDrnIndexed, &uiOnlineTransId, &bSuspended))) + { + goto Exit; + } + + if( bSuspended) + { + pIxd->uiFlags |= (IXD_SUSPENDED | IXD_OFFLINE); + } + else if( uiOnlineTransId == TRANS_ID_OFFLINE) + { + pIxd->uiFlags |= IXD_OFFLINE; + } + } + +Exit: + + if( bTDictInitialized) + { + GedPoolFree( &tDict.pool); + } + + return( rc ); +} + +/**************************************************************************** +Desc: Initializes and sets up a TDICT structure. +****************************************************************************/ +RCODE fdictInitTDict( + FDB * pDb, + TDICT * pTDict) +{ + RCODE rc = FERR_OK; + + f_memset( pTDict, 0, sizeof( TDICT)); // Set elements to zeros. + GedSmartPoolInit( &pTDict->pool, &g_TDictPoolStats); + + pTDict->pDb = pDb; + pTDict->uiVersionNum = pDb->pFile->FileHdr.uiVersionNum; + pTDict->uiDefaultLanguage = + pDb->pFile->FileHdr.uiDefaultLanguage; + pTDict->pDict = pDb->pDict; + + + if( RC_BAD(rc = fdictGetContainer( pDb->pDict, FLM_DICT_CONTAINER, + &pTDict->pLFile ))) + goto Exit; +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Build all of the dictionary tables given the temporary dictionary + (pTDict) that was built in ddprep. +Note: There are two ways this will be called. The first is when + we are building a dictionary from scratch. The second is ONLY + when a new field definition or container is added, or an index's + state is changed. +****************************************************************************/ +RCODE fdictBuildTables( + TDICT * pTDict, + FLMBOOL bRereadLFiles, + FLMBOOL bNewDict) +{ + RCODE rc = FERR_OK; + DDENTRY * pEntry; + TFIELD * pTField; + FLMUINT uiEntryNum; + TENCDEF * pTEncDef; + + if( RC_BAD( rc = fdictReallocAllTables( pTDict))) + { + goto Exit; + } + + // Go through and add each new item to the dictionary. + + for( pEntry = pTDict->pFirstEntry + ; pEntry + ; pEntry = pEntry->pNextEntry ) + { + uiEntryNum = pEntry->uiEntryNum; + + switch( pEntry->uiType) + { + case 0: // Field + { + pTField = (TFIELD *) pEntry->vpDef; + fdictAddItem( pTDict, uiEntryNum, pTField->uiFldInfo); + break; + } + + case ITT_INDEX_TYPE: + { + fdictAddItem( pTDict, uiEntryNum, ITT_INDEX_TYPE); + if( RC_BAD( rc = fdictAddIndex( pTDict, pEntry ))) + { + goto Exit; + } + break; + } + + case ITT_CONTAINER_TYPE: + { + fdictAddItem( pTDict, uiEntryNum, ITT_CONTAINER_TYPE); + // rc = fdictAddLFile( pTDict, pEntry ); Already done. + break; + } + + case ITT_ENCDEF_TYPE: + { + if (!pTDict->pDb->pFile) + { + flmAssert( 0); + rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); + goto Exit; + } + else + { + fdictAddItem( pTDict, uiEntryNum, ITT_ENCDEF_TYPE); + + pTEncDef = (TENCDEF *) pEntry->vpDef; + // Need to add a new CCS. + if (RC_BAD( rc = fdictAddNewCCS(pTDict, pTEncDef, uiEntryNum))) + { + goto Exit; + } + } + break; + } + + default: + { + break; + } + } + } + + if( pTDict->uiNewIfds || bNewDict) + { + if( RC_BAD( rc = fdictFixupIfdPointers( pTDict->pDict, + bNewDict ? 0 : (pTDict->uiTotalIfds - pTDict->uiNewIfds)))) + { + goto Exit; + } + } + + if( bRereadLFiles) + { + if( RC_BAD( rc = fdictReadLFiles( pTDict->pDb, pTDict->pDict))) + { + goto Exit; + } + } + + if( RC_BAD( rc = fdictFixupLFileTbl( pTDict->pDict))) + { + goto Exit; + } + +Exit: + + return( rc ); +} + +/**************************************************************************** +Desc: Fixup pointers in tables of copied dictionary. This is called after + a copy of one dictionary to another, or after a dictionary's tables + have been reallocated. +****************************************************************************/ +FSTATIC void fdictFixupPointers( + FDICT * pNewDict, + FDICT * pOldDict + ) +{ + FLMUINT uiPos; + FLMUINT uiOffset; + LFILE * pOldLFile; + LFILE * pNewLFile; + IFD * pOldIfd; + IFD * pNewIfd; + IXD * pOldIxd; + IXD * pNewIxd; + ITT * pOldItt; + ITT * pNewItt; + + // Fixup anything that points to LFILE entries. + + if (pNewDict->pLFileTbl && pNewDict->pLFileTbl != pOldDict->pLFileTbl) + { + + // Fixup pItt->pvItem pointers for indexes and containers + + for (uiPos = 0, pOldItt = pOldDict->pIttTbl, + pNewItt = pNewDict->pIttTbl; + uiPos < pOldDict->uiIttCnt; + uiPos++, pOldItt++, pNewItt++) + { + if (ITT_IS_CONTAINER( pOldItt) || ITT_IS_INDEX( pOldItt)) + { + if (pOldItt->pvItem) + { + LFILE * pTmpLFile; + + pTmpLFile = (LFILE *)(pOldItt->pvItem); + uiOffset = (FLMUINT)(pTmpLFile - pOldDict->pLFileTbl); + pTmpLFile = pNewDict->pLFileTbl + uiOffset; + pNewItt->pvItem = (void *)pTmpLFile; + } + else + { + flmAssert( pNewItt->pvItem == NULL); + } + } + else if (ITT_IS_ENCDEF( pOldItt)) + { + if (pOldItt->pvItem) + { + pNewItt->pvItem = pOldItt->pvItem; + ((F_CCS *)pNewItt->pvItem)->AddRef(); + } + else + { + flmAssert( pNewItt->pvItem == NULL); + } + } + } + } + + // Fixup anything that points to IXD entries + + if (pNewDict->pIxdTbl && pNewDict->pIxdTbl != pOldDict->pIxdTbl) + { + + // Fixup pLFile->pIxd pointers + + for (uiPos = 0, pOldLFile = pOldDict->pLFileTbl, + pNewLFile = pNewDict->pLFileTbl; + uiPos < pOldDict->uiLFileCnt; + uiPos++, pOldLFile++, pNewLFile++) + { + if (pOldLFile->pIxd) + { + uiOffset = (FLMUINT)(pOldLFile->pIxd - pOldDict->pIxdTbl); + pNewLFile->pIxd = pNewDict->pIxdTbl + uiOffset; + } + else + { + flmAssert( pNewLFile->pIxd == NULL); + } + } + + // Fixup pIfd->pIxd pointers + + for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, + pNewIfd = pNewDict->pIfdTbl; + uiPos < pOldDict->uiIfdCnt; + uiPos++, pOldIfd++, pNewIfd++) + { + if (pOldIfd->pIxd) + { + uiOffset = (FLMUINT)(pOldIfd->pIxd - pOldDict->pIxdTbl); + pNewIfd->pIxd = pNewDict->pIxdTbl + uiOffset; + } + else + { + flmAssert( pNewIfd->pIxd == NULL); + } + } + } + + // Fixup anything that points to IFD entries + + if (pNewDict->pIfdTbl && pNewDict->pIfdTbl != pOldDict->pIfdTbl) + { + + // Fixup pIfd->pNextInChain pointers + + for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, + pNewIfd = pNewDict->pIfdTbl; + uiPos < pOldDict->uiIfdCnt; + uiPos++, pOldIfd++, pNewIfd++) + { + if (pOldIfd->pNextInChain) + { + uiOffset = (FLMUINT)(pOldIfd->pNextInChain - pOldDict->pIfdTbl); + pNewIfd->pNextInChain = pNewDict->pIfdTbl + uiOffset; + } + else + { + flmAssert( pNewIfd->pNextInChain == NULL); + } + } + + // Fixup pIxd->pFirstIfd pointers + + for (uiPos = 0, pOldIxd = pOldDict->pIxdTbl, + pNewIxd = pNewDict->pIxdTbl; + uiPos < pOldDict->uiIxdCnt; + uiPos++, pOldIxd++, pNewIxd++) + { + if (pOldIxd->pFirstIfd) + { + uiOffset = (FLMUINT)(pOldIxd->pFirstIfd - pOldDict->pIfdTbl); + pNewIxd->pFirstIfd = pNewDict->pIfdTbl + uiOffset; + } + else + { + flmAssert( pNewIxd->pFirstIfd == NULL); + } + } + + // Fixup pItt->pvItem pointers + + for (uiPos = 0, pOldItt = pOldDict->pIttTbl, + pNewItt = pNewDict->pIttTbl; + uiPos < pOldDict->uiIttCnt; + uiPos++, pOldItt++, pNewItt++) + { + if (ITT_IS_FIELD( pOldItt)) + { + if (pOldItt->pvItem) + { + IFD * pTmpIfd; + + pTmpIfd = (IFD *)(pOldItt->pvItem); + uiOffset = (FLMUINT)(pTmpIfd - pOldDict->pIfdTbl); + pTmpIfd = pNewDict->pIfdTbl + uiOffset; + pNewItt->pvItem = (void *)pTmpIfd; + } + else + { + flmAssert( pNewItt->pvItem == NULL); + } + } + } + } + + // Fixup anything that points to field path entries + + if (pNewDict->pFldPathsTbl && pNewDict->pFldPathsTbl != pOldDict->pFldPathsTbl) + { + + // Fixup pIfd->pFieldPathCToP and pIfd->pFieldPathPToC pointers + + for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, + pNewIfd = pNewDict->pIfdTbl; + uiPos < pOldDict->uiIfdCnt; + uiPos++, pOldIfd++, pNewIfd++) + { + if (pOldIfd->pFieldPathCToP) + { + uiOffset = (FLMUINT)(pOldIfd->pFieldPathCToP - pOldDict->pFldPathsTbl); + pNewIfd->pFieldPathCToP = pNewDict->pFldPathsTbl + uiOffset; + } + else + { + flmAssert( pNewIfd->pFieldPathCToP == NULL); + } + if (pOldIfd->pFieldPathPToC) + { + uiOffset = (FLMUINT)(pOldIfd->pFieldPathPToC - pOldDict->pFldPathsTbl); + pNewIfd->pFieldPathPToC = pNewDict->pFldPathsTbl + uiOffset; + } + else + { + flmAssert( pNewIfd->pFieldPathPToC == NULL); + } + } + + } +} + +/**************************************************************************** +Desc: Allocate all of the dictionary tables based on the counts that + were incremented in pTDict. Coded to add new fields, indexes or + container, but not to modify or delete anything! +****************************************************************************/ +FSTATIC RCODE fdictReallocAllTables( + TDICT * pTDict) +{ + RCODE rc = FERR_OK; + FDICT OldDict; + FDICT * pDict = pTDict->pDict; + + // Save a copy of the old dictionary's pointers and counters + // Easiest way to do this is to simply copy the structure. + + f_memcpy( &OldDict, pDict, sizeof( FDICT)); + + if( pTDict->pLastEntry + && pTDict->pLastEntry->uiEntryNum >= pDict->uiIttCnt + && pTDict->pLastEntry->uiEntryNum < FLM_RESERVED_TAG_NUMS) + { + ITT * pItt; + FLMUINT uiNewCount; + + uiNewCount = pTDict->pLastEntry->uiEntryNum + 1 - pDict->uiIttCnt; + if (uiNewCount) + { + + // Must fake out so that we don't lose the old table. + + pDict->pIttTbl = NULL; + if( RC_BAD( rc = fdictReallocTbl( sizeof( ITT), pDict->uiIttCnt, + uiNewCount, (void **) &pDict->pIttTbl))) + { + goto Exit; + } + pTDict->uiTotalItts = pDict->uiIttCnt + uiNewCount; + + // Copy the table to the new location (because of fake out above) + + if( OldDict.uiIttCnt) + { + f_memcpy( pDict->pIttTbl, OldDict.pIttTbl, + sizeof( ITT) * OldDict.uiIttCnt); + } + + // Initialize the new items to empty. + + pItt = pDict->pIttTbl + pDict->uiIttCnt; + for( ;uiNewCount--; pItt++) + { + pItt->uiType = ITT_EMPTY_SLOT; + pItt->pvItem = NULL; + } + } + } + + if (pTDict->uiNewIxds) + { + + // Must fake out so that we don't lose the old table. + + pDict->pIxdTbl = NULL; + if( RC_BAD( rc = fdictReallocTbl( sizeof( IXD), pDict->uiIxdCnt, + pTDict->uiNewIxds, (void **)&pDict->pIxdTbl))) + { + goto Exit; + } + pTDict->uiTotalIxds = pDict->uiIxdCnt + pTDict->uiNewIxds; + + // Copy the table to the new location (because of fake out above) + + if( OldDict.uiIxdCnt) + { + f_memcpy( pDict->pIxdTbl, OldDict.pIxdTbl, + sizeof( IXD) * OldDict.uiIxdCnt); + } + } + + if (pTDict->uiNewIfds) + { + + // Must fake out so that we don't lose the old table. + + pDict->pIfdTbl = NULL; + if( RC_BAD( rc = fdictReallocTbl( sizeof( IFD), pDict->uiIfdCnt, + pTDict->uiNewIfds, (void **)&pDict->pIfdTbl))) + { + goto Exit; + } + pTDict->uiTotalIfds = pDict->uiIfdCnt + pTDict->uiNewIfds; + + // Copy the table to the new location (because of fake out above) + + if( OldDict.uiIfdCnt) + { + f_memcpy( pDict->pIfdTbl, OldDict.pIfdTbl, + sizeof( IFD) * OldDict.uiIfdCnt); + } + } + + if (pTDict->uiNewFldPaths) + { + + // Must fake out so that we don't lose the old table. + + pDict->pFldPathsTbl = NULL; + if( RC_BAD( rc = fdictReallocTbl( sizeof( FLMUINT), pDict->uiFldPathsCnt, + pTDict->uiNewFldPaths, (void **)&pDict->pFldPathsTbl))) + { + goto Exit; + } + pTDict->uiTotalFldPaths = pDict->uiFldPathsCnt + pTDict->uiNewFldPaths; + + // Copy the table to the new location (because of fake out above) + + if( OldDict.uiFldPathsCnt) + { + f_memcpy( pDict->pFldPathsTbl, OldDict.pFldPathsTbl, + sizeof( FLMUINT) * OldDict.uiFldPathsCnt); + } + } + + fdictFixupPointers( pDict, &OldDict); + +Exit: + + // Free any old tables where a new table was allocated. + + if (OldDict.pLFileTbl != pDict->pLFileTbl) + { + f_free( &OldDict.pLFileTbl); + } + if (OldDict.pIttTbl != pDict->pIttTbl) + { + f_free( &OldDict.pIttTbl); + } + if (OldDict.pIxdTbl != pDict->pIxdTbl) + { + f_free( &OldDict.pIxdTbl); + } + if (OldDict.pIfdTbl != pDict->pIfdTbl) + { + f_free( &OldDict.pIfdTbl); + } + if (OldDict.pFldPathsTbl != pDict->pFldPathsTbl) + { + f_free( &OldDict.pFldPathsTbl); + } + + return( rc ); +} + + +/**************************************************************************** +Desc: Allocate or reallocate a table. +****************************************************************************/ +FSTATIC RCODE fdictReallocTbl( + FLMUINT uiElementSize, + FLMUINT uiTblSize, + FLMUINT uiAddElements, + void ** ppvTblRV) +{ + RCODE rc = FERR_OK; + + // Does the table need to grow? + + if( uiAddElements) + { + if( *ppvTblRV) + { + if( RC_BAD( rc = f_recalloc( + uiElementSize * (uiTblSize + uiAddElements), + ppvTblRV))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = f_calloc( + uiElementSize * (uiTblSize + uiAddElements), + ppvTblRV))) + { + goto Exit; + } + } + } + +Exit: + + return( rc ); +} + +/**************************************************************************** +Desc: Add a new item to the item type table. +****************************************************************************/ +FSTATIC void fdictAddItem( + TDICT * pTDict, + FLMUINT uiFieldNum, + FLMUINT uiFieldType) +{ + FDICT * pDict = pTDict->pDict; + ITT * pItt; + + if( uiFieldNum < FLM_RESERVED_TAG_NUMS) + { + pItt = pDict->pIttTbl + uiFieldNum; + pItt->uiType = uiFieldType; + pItt->pvItem = NULL; + + if( uiFieldNum >= pDict->uiIttCnt) + { + pDict->uiIttCnt = uiFieldNum + 1; + } + } +} + +/**************************************************************************** +Desc: Add the new IXD, IFD, field paths and LFILE for the index. +****************************************************************************/ +FSTATIC RCODE fdictAddIndex( + TDICT * pTDict, + DDENTRY * pEntry) +{ + RCODE rc = FERR_OK; + FDICT * pDict = pTDict->pDict; + FLMUINT uiIndexNum = pEntry->uiEntryNum; + IXD * pIxd; + IFD * pIfd; + FLMUINT * pFirstPToCFld; + FLMUINT * pFirstCToPFld; + FLMUINT * pCurFld; + FLMUINT * pTempFld; + TIXD * pTIxd; + TIFD * pTIfd; + TIFP * pTIfp; + + // The index numbers in the IXD array do not need to be in any order. + // Just add all of the index information to the end of the table. + + pIxd = pDict->pIxdTbl + pDict->uiIxdCnt++; + pIxd->uiIndexNum = uiIndexNum; + + pTIxd = (TIXD *) pEntry->vpDef; + pIxd->uiContainerNum = pTIxd->uiContainerNum; + pIxd->uiNumFlds = pTIxd->uiNumFlds; + pIxd->uiFlags = pTIxd->uiFlags; + pIxd->uiLanguage = pTIxd->uiLanguage; + pIxd->uiLastContainerIndexed = 0xFFFFFFFF; + pIxd->uiLastDrnIndexed = DRN_LAST_MARKER; + pIxd->uiEncId = pTIxd->uiEncId; + + // Setup the IFD elements and the field paths. + + pIxd->pFirstIfd = pIfd = pDict->pIfdTbl + pDict->uiIfdCnt; + pDict->uiIfdCnt += pIxd->uiNumFlds; + + for( pTIfd = pTIxd->pNextTIfd; pTIfd; pIfd++, pTIfd = pTIfd->pNextTIfd) + { + // This is a good place to set the IFD_LAST flag. + // Could/Should be done in ddprep.c + + if( pTIfd->pNextTIfd == NULL) + pTIfd->uiFlags |= IFD_LAST; + + pIfd->uiIndexNum = uiIndexNum; + pIfd->pIxd = pIxd; + pIfd->uiFlags = pTIfd->uiFlags; + pIfd->uiLimit = pTIfd->uiLimit; + pIfd->uiCompoundPos = pTIfd->uiCompoundPos; + + // The pTIfp->pNextTIfp are linked from parent to child. + pTIfp = pTIfd->pTIfp; + pCurFld = pDict->pFldPathsTbl + pDict->uiFldPathsCnt; + pFirstPToCFld = pFirstCToPFld = pCurFld; + + pIfd->pFieldPathPToC = pFirstPToCFld; + + do + { + *pCurFld++ = pTIfp->uiFldNum; + pTIfp = pTIfp->pNextTIfp; + + } while( pTIfp); + + pIfd->uiFldNum = *(pCurFld-1); + pTempFld = pCurFld - 1; + + // Null Terminate + *pCurFld++ = 0; + + pTIfp = pTIfd->pTIfp; + if( pTIfp->pNextTIfp) // If more than one field make the CToP path. + { + pFirstCToPFld = pCurFld; + while( pTempFld != pFirstPToCFld) + { + *pCurFld++ = *pTempFld--; + } + *pCurFld++ = *pTempFld; + *pCurFld++ = 0; + } + pIfd->pFieldPathCToP = pFirstCToPFld; + pDict->uiFldPathsCnt += pCurFld - pFirstPToCFld; + } + + return( rc ); +} + +/**************************************************************************** +Desc: Fixup the IFD chain and the pIfd->pIxd pointers. +****************************************************************************/ +FSTATIC RCODE fdictFixupIfdPointers( + FDICT * pDict, + FLMUINT uiIfdStartOffset) +{ + RCODE rc = FERR_OK; + FLMUINT uiCount; + IFD * pIfd; + ITT * pItt; + ITT * pIttTbl = pDict->pIttTbl; + + // Go through the IFD list and setup the pNextInChain pointers + // making sure that the required fields are first. + + for( uiCount = pDict->uiIfdCnt - uiIfdStartOffset, + pIfd = pDict->pIfdTbl + uiIfdStartOffset; + uiCount; uiCount--, pIfd++) + { + IFD * pPrevInChain; + IFD * pTempIfd; + + if( pIfd->uiFldNum >= pDict->uiIttCnt) + { + if( pIfd->uiFldNum < FLM_RESERVED_TAG_NUMS) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + continue; + } + else + { + pItt = pIttTbl + pIfd->uiFldNum; + if( !ITT_IS_FIELD( pItt)) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + } + + // Move the field type to the pIfd->uiFlags + IFD_SET_FIELD_TYPE( pIfd, ITT_FLD_GET_TYPE( pItt)); + + // Visit: We could verify all of the fields in the field path. + // Need to include 'any', 'use', 'parent' tags as valid tags. + + if( !pItt->pvItem) + { + pItt->pvItem = (void *) pIfd; + } + else + { + // Follow the chain and index at the front or rear depending on + // if the field is required within the set. + + pTempIfd = (IFD *) pItt->pvItem; + if( (pIfd->uiFlags & IFD_REQUIRED_IN_SET) + || !(pTempIfd->uiFlags & IFD_REQUIRED_IN_SET)) + { + pIfd->pNextInChain = pTempIfd; + pItt->pvItem = (void *) pIfd; + } + else + { + // Not required in set and first IFD is required in set. + // Look for first not required IFD in the chain. + + pPrevInChain = pTempIfd; + pTempIfd = pTempIfd->pNextInChain; + + for( ; pTempIfd; pTempIfd = pTempIfd->pNextInChain) + { + if( !(pTempIfd->uiFlags & IFD_REQUIRED_IN_SET)) + break; + pPrevInChain = pTempIfd; + } + pIfd->pNextInChain = pPrevInChain->pNextInChain; + pPrevInChain->pNextInChain = pIfd; + } + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Fixup the ITT pointers into the LFILE elements and all of + the IXD pointers in the LDICT. +****************************************************************************/ +RCODE fdictFixupLFileTbl( + FDICT * pDict) +{ + RCODE rc = FERR_OK; + FLMUINT uiCount; + LFILE * pLFile; + IXD * pIxd; + ITT * pItt; + ITT * pIttTbl = pDict->pIttTbl; + FLMUINT uiIttCnt = pDict->uiIttCnt; + + for( uiCount = pDict->uiLFileCnt, pLFile = pDict->pLFileTbl + ; uiCount; uiCount--, pLFile++) + { + + if( pLFile->uiLfNum != FLM_DATA_CONTAINER + && pLFile->uiLfNum != FLM_DICT_CONTAINER + && pLFile->uiLfNum != FLM_DICT_INDEX + && pLFile->uiLfNum != FLM_TRACKER_CONTAINER) + { + pItt = pIttTbl + pLFile->uiLfNum; + + if( uiIttCnt <= pLFile->uiLfNum || + (pLFile->uiLfType == LF_CONTAINER && !ITT_IS_CONTAINER( pItt))) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + if( pLFile->uiLfType == LF_INDEX && !ITT_IS_INDEX( pItt)) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + + pItt->pvItem = pLFile; + } + else if( pLFile->uiLfNum == FLM_DICT_INDEX) + { + // The first IXD should be the dictionary index. + + if( pDict->pIxdTbl && pDict->pIxdTbl->uiIndexNum == FLM_DICT_INDEX) + { + pLFile->pIxd = pDict->pIxdTbl; + } + } + } + + // Now that all of the indexes/containers in the ITT table point + // to the LFILE entries, fixup the LFILE to point to the IXD entries. + + for( uiCount = pDict->uiIxdCnt, pIxd = pDict->pIxdTbl; + uiCount; uiCount--, pIxd++) + { + if( uiIttCnt <= pIxd->uiIndexNum) + { + if( pIxd->uiIndexNum != FLM_DICT_INDEX) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + } + else + { + pItt = pIttTbl + pIxd->uiIndexNum; + pLFile = (LFILE *) pItt->pvItem; + + if( !pLFile) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + pLFile->pIxd = pIxd; + } + + // Verify that the pIxd->uiContainerNum is actually a container. + // A value of 0 means that the index is on ALL containers. + + if (pIxd->uiContainerNum) + { + if( uiIttCnt <= pIxd->uiContainerNum) + { + if( pIxd->uiContainerNum != FLM_DATA_CONTAINER + && pIxd->uiContainerNum != FLM_DICT_CONTAINER + && pIxd->uiContainerNum != FLM_TRACKER_CONTAINER) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + } + else + { + pItt = pIttTbl + pIxd->uiContainerNum; + if( !ITT_IS_CONTAINER( pItt)) + { + rc = RC_SET( FERR_BAD_REFERENCE); + goto Exit; + } + } + } + } + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Add a new CCS reference to the item type table. If a key is included + we can use it, otherwise we will have to generate one. +****************************************************************************/ +FSTATIC RCODE fdictAddNewCCS( + TDICT * pTDict, + TENCDEF * pTEncDef, + FLMUINT uiRecNum) +{ + RCODE rc = FERR_OK; + FDICT * pDict = pTDict->pDict; + ITT * pItt; + F_CCS * pCcs = NULL; + FDB * pDb = pTDict->pDb; + F_CCS * pDbWrappingKey; + + if( uiRecNum >= FLM_RESERVED_TAG_NUMS) + { + goto Exit; + } + + if (!pDb->pFile->bInLimitedMode) + { + + pDbWrappingKey = pDb->pFile->pDbWrappingKey; + + flmAssert( pTEncDef); + + if ((pCcs = f_new F_CCS) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + // Setup the F_CCS. + if (RC_BAD( rc = pCcs->init( FALSE, pTEncDef->uiAlgType ))) + { + goto Exit; + } + + if (!pTEncDef->uiLength) + { + flmAssert( 0); + rc = RC_SET( FERR_MISSING_ENC_KEY); + goto Exit; + } + + // We need to set the key information. This also unwraps the key and stores the + // handle. + + if( RC_BAD( rc = pCcs->setKeyFromStore( pTEncDef->pucKeyInfo, + (FLMUINT32)pTEncDef->uiLength, NULL, pDbWrappingKey))) + { + goto Exit; + } + } + + // Save the CCS object in the ITT table. + + pItt = pDict->pIttTbl + uiRecNum; + pItt->pvItem = (void *)pCcs; + pCcs = NULL; + + if( uiRecNum >= pDict->uiIttCnt) + { + pDict->uiIttCnt = uiRecNum + 1; + } + +Exit: + + if (pCcs) + { + delete pCcs; + } + + return( rc); + +} + +/**************************************************************************** +Desc: Copies an existing dictionary to a new dictionary. This does not + fix up all of the ITT's pvItem pointers (including the + pFirstIfd pointer of fields in the ITT table). To clone the + dictionary, call fdictCloneDict. +****************************************************************************/ +RCODE fdictCopySkeletonDict( + FDB * pDb) +{ + RCODE rc = FERR_OK; + FDICT * pNewDict = NULL; + FDICT * pOldDict = pDb->pDict; + FLMUINT uiTblSize; + FLMUINT uiPos; + LFILE * pLFile; + IXD * pIxd; + ITT * pItt; + ITT * pNewIttTbl = NULL; + FLMUINT uiNewIttTblLen = 0; + LFILE * pNewDictIndexLFile = NULL; + FLMUINT * pOldFieldPathsTbl = NULL; + FLMUINT * pNewFieldPathsTbl = NULL; + + if( RC_BAD( rc = f_calloc( (FLMUINT)sizeof( FDICT), &pNewDict))) + { + goto Exit; + } + + pNewDict->pNext = pNewDict->pPrev = NULL; + pNewDict->pFile = NULL; + pNewDict->uiUseCount = 1; + + // Nothing to do is not a legal state. + if( !pOldDict) + { + flmAssert( pOldDict != NULL); + pDb->pDict = pNewDict; + goto Exit; + } + + // ITT Table + + if( (uiTblSize = pNewDict->uiIttCnt = pOldDict->uiIttCnt) != 0) + { + if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( ITT), &pNewDict->pIttTbl))) + { + goto Exit; + } + pNewIttTbl = pNewDict->pIttTbl; + uiNewIttTblLen = uiTblSize; + f_memcpy( pNewDict->pIttTbl, pOldDict->pIttTbl, + uiTblSize * sizeof( ITT)); + + // Clear out all of the pointer values. + pItt = pNewDict->pIttTbl; + for( uiPos = 0; uiPos < uiTblSize; uiPos++, pItt++) + { + if ( pItt->uiType == ITT_ENCDEF_TYPE && !pDb->pFile->bInLimitedMode) + { + flmAssert( pItt->pvItem); + ((F_CCS *)pItt->pvItem)->AddRef(); + } + else + { + pItt->pvItem = NULL; + } + } + } + + // LFILE Table + + if( (uiTblSize = pNewDict->uiLFileCnt = pOldDict->uiLFileCnt) != 0) + { + if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( LFILE), + &pNewDict->pLFileTbl))) + { + goto Exit; + } + f_memcpy( pNewDict->pLFileTbl, pOldDict->pLFileTbl, + uiTblSize * sizeof( LFILE)); + + for( pLFile = pNewDict->pLFileTbl; uiTblSize--; pLFile++) + { + if( pLFile->uiLfNum < FLM_RESERVED_TAG_NUMS) + { + // WARNING: The code must make a new LFILE + // before the dictionary is aware of it. + + if( pLFile->uiLfNum < uiNewIttTblLen) + { + pItt = pNewIttTbl + pLFile->uiLfNum; + pItt->pvItem = (void *) pLFile; + } + } + else if( pLFile->uiLfNum == FLM_DICT_INDEX) + { + pNewDictIndexLFile = pLFile; + } + } + } + + // IXD Table + + if( (uiTblSize = pNewDict->uiIxdCnt = pOldDict->uiIxdCnt) != 0) + { + if( RC_BAD( rc = f_alloc( + uiTblSize * sizeof( IXD), &pNewDict->pIxdTbl))) + { + goto Exit; + } + f_memcpy( pNewDict->pIxdTbl, pOldDict->pIxdTbl, + uiTblSize * sizeof( IXD)); + + // Fixup all of the pointers to the IXD. + + for( pIxd = pNewDict->pIxdTbl; uiTblSize--; pIxd++) + { + if( pIxd->uiIndexNum != FLM_DICT_INDEX) + { + pItt = pNewIttTbl + pIxd->uiIndexNum; + pLFile = (LFILE *) pItt->pvItem; + pLFile->pIxd = pIxd; + } + else if( pNewDictIndexLFile) + { + pNewDictIndexLFile->pIxd = pIxd; + } + } + } + + // Field Paths Table + + if( (uiTblSize = pNewDict->uiFldPathsCnt = pOldDict->uiFldPathsCnt) != 0) + { + if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( FLMUINT), + &pNewDict->pFldPathsTbl))) + { + goto Exit; + } + f_memcpy( pNewDict->pFldPathsTbl, pOldDict->pFldPathsTbl, + uiTblSize * sizeof( FLMUINT)); + + pOldFieldPathsTbl = pOldDict->pFldPathsTbl; + pNewFieldPathsTbl = pNewDict->pFldPathsTbl; + } + + // IFD Table + + if( (uiTblSize = pNewDict->uiIfdCnt = pOldDict->uiIfdCnt) != 0) + { + IFD * pIfd; + FLMUINT uiLastIndexNum; + FLMUINT uiOffset; + + if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( IFD), + &pNewDict->pIfdTbl))) + { + goto Exit; + } + f_memcpy( pNewDict->pIfdTbl, pOldDict->pIfdTbl, + uiTblSize * sizeof( IFD)); + + // Fixup all pFirstIfd pointers, backlinks to the pIxd and fldPathTbls. + // Set all of the IfdChain values to NULL to be fixed up later. + pIfd = pNewDict->pIfdTbl; + uiLastIndexNum = 0; + + for( uiPos = 0; uiPos < uiTblSize; uiPos++, pIfd++) + { + pIfd->pNextInChain = NULL; + + if( pIfd->uiIndexNum != FLM_DICT_INDEX) + { + pItt = pNewIttTbl + pIfd->uiIndexNum; + pLFile = (LFILE *) pItt->pvItem; + pIxd = pLFile->pIxd; + } + else + { + pIxd = pNewDictIndexLFile->pIxd; + } + + pIfd->pIxd = pIxd; + if( uiLastIndexNum != pIfd->uiIndexNum) + { + pIxd->pFirstIfd = pIfd; + uiLastIndexNum = pIfd->uiIndexNum; + } + + // Fixup the field paths. + + flmAssert( pNewFieldPathsTbl != NULL); + uiOffset = pIfd->pFieldPathCToP - pOldFieldPathsTbl; + pIfd->pFieldPathCToP = pNewFieldPathsTbl + uiOffset; + + uiOffset = pIfd->pFieldPathPToC - pOldFieldPathsTbl; + pIfd->pFieldPathPToC = pNewFieldPathsTbl + uiOffset; + } + } + + f_mutexLock( gv_FlmSysData.hShareMutex); + flmUnlinkFdbFromDict( pDb); + f_mutexUnlock( gv_FlmSysData.hShareMutex); + pDb->pDict = pNewDict; + pNewDict = NULL; + +Exit: + + if( RC_BAD( rc) && pNewDict) + { + // Undo all of the allocations on the new table. + if( pNewDict->pLFileTbl) + { + f_free( &pNewDict->pLFileTbl); + } + if( pNewDict->pIttTbl) + { + f_free( &pNewDict->pIttTbl); + } + if( pNewDict->pIxdTbl) + { + f_free( &pNewDict->pIxdTbl); + } + if( pNewDict->pIfdTbl) + { + f_free( &pNewDict->pIfdTbl); + } + if( pNewDict->pFldPathsTbl) + { + f_free( &pNewDict->pFldPathsTbl); + } + f_free( &pNewDict); + } + + return( rc); +} + +/**************************************************************************** +Desc: Creates a new version of the current dictionary and fixes up all + pointers +****************************************************************************/ +RCODE fdictCloneDict( + FDB * pDb) +{ + RCODE rc = FERR_OK; + TDICT tDict; + FLMBOOL bTDictInitialized = FALSE; + + if( RC_BAD( rc = fdictCopySkeletonDict( pDb))) + { + goto Exit; + } + + bTDictInitialized = TRUE; + if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) + { + goto Exit; + } + + if( RC_BAD( rc = fdictBuildTables( &tDict, FALSE, TRUE))) + { + goto Exit; + } + + pDb->uiFlags |= FDB_UPDATED_DICTIONARY; + +Exit: + + if( bTDictInitialized) + { + GedPoolFree( &tDict.pool); + } + + // If we allocated an FDICT and there was an error, free the FDICT. + + if( (RC_BAD( rc)) && (pDb->pDict)) + { + flmFreeDict( pDb->pDict); + pDb->pDict = NULL; + } + + return( rc); +} diff --git a/flaim/src/fdictbld.cpp b/flaim/src/fdictbld.cpp deleted file mode 100644 index faa3f1d..0000000 --- a/flaim/src/fdictbld.cpp +++ /dev/null @@ -1,1369 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Build dicitionary tables. -// Tabs: 3 -// -// Copyright (c) 1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fdictbld.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC POOL_STATS g_TDictPoolStats = {0,0}; - - -FSTATIC void fdictFixupPointers( - FDICT * pNewDict, - FDICT * pOldDict); - -FSTATIC RCODE fdictReallocAllTables( - TDICT * pTDict); - -FSTATIC RCODE fdictReallocTbl( - FLMUINT uiElementSize, - FLMUINT uiTblSize, - FLMUINT uiAddElements, - void ** ppvTblRV); - -FSTATIC void fdictAddItem( - TDICT * pTDict, - FLMUINT uiFieldNum, - FLMUINT uiFieldType); - -FSTATIC RCODE fdictAddIndex( - TDICT * pTDict, - DDENTRY * pEntry); - -FSTATIC RCODE fdictFixupIfdPointers( - FDICT * pDict, - FLMUINT uiIfdStartOffset); - -FSTATIC RCODE fdictAddNewCCS( - TDICT * pTDict, - TENCDEF * pTEncDef, - FLMUINT uiRecNum); -/**************************************************************************** -Desc: Rebuild the dictionary tables reading in all dictionary - records. -****************************************************************************/ -RCODE fdictRebuild( - FDB * pDb) -{ - RCODE rc = FERR_OK; - TDICT tDict; - FLMUINT uiCount; - IXD_p pIxd; - FLMBOOL bTDictInitialized = FALSE; - FLMBOOL bSuspended; - FLMUINT uiOnlineTransId; - - // Allocate a new FDICT structure for reading the local dictionary - // into memory. - // At this point, pDb better not be pointing to a dictionary. - - flmAssert( pDb->pDict == NULL); - if( RC_BAD( rc = flmAllocDict( &pDb->pDict))) - { - goto Exit; - } - - if( !pDb->pDict->pLFileTbl) - { - // Read the local dictionary into memory. - - if( RC_BAD(rc = fdictReadLFiles( pDb, pDb->pDict))) - { - goto Exit; - } - - // For a database create the LFiles still are not created. - - if( pDb->pDict->pLFileTbl->uiLfNum == 0) - { - goto Exit; - } - } - - bTDictInitialized = TRUE; - if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictProcessAllDictRecs( pDb, &tDict))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictBuildTables( &tDict, FALSE, FALSE))) - { - goto Exit; - } - - // Loop through the IXD and set the uiLastDrnIndexed value. - - uiCount = pDb->pDict->uiIxdCnt; - for( pIxd = pDb->pDict->pIxdTbl; uiCount--; pIxd++) - { - // Ignore any errors in case we are rebuilding. - - if( RC_BAD( flmGetIxTrackerInfo( pDb, pIxd->uiIndexNum, - &pIxd->uiLastContainerIndexed, - &pIxd->uiLastDrnIndexed, &uiOnlineTransId, &bSuspended))) - { - goto Exit; - } - - if( bSuspended) - { - pIxd->uiFlags |= (IXD_SUSPENDED | IXD_OFFLINE); - } - else if( uiOnlineTransId == TRANS_ID_OFFLINE) - { - pIxd->uiFlags |= IXD_OFFLINE; - } - } - -Exit: - - if( bTDictInitialized) - { - GedPoolFree( &tDict.pool); - } - - return( rc ); -} - -/**************************************************************************** -Desc: Initializes and sets up a TDICT structure. -****************************************************************************/ -RCODE fdictInitTDict( - FDB * pDb, - TDICT * pTDict) -{ - RCODE rc = FERR_OK; - - f_memset( pTDict, 0, sizeof( TDICT)); // Set elements to zeros. - GedSmartPoolInit( &pTDict->pool, &g_TDictPoolStats); - - pTDict->pDb = pDb; - pTDict->uiVersionNum = pDb->pFile->FileHdr.uiVersionNum; - pTDict->uiDefaultLanguage = - pDb->pFile->FileHdr.uiDefaultLanguage; - pTDict->pDict = pDb->pDict; - - - if( RC_BAD(rc = fdictGetContainer( pDb->pDict, FLM_DICT_CONTAINER, - &pTDict->pLFile ))) - goto Exit; -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Build all of the dictionary tables given the temporary dictionary - (pTDict) that was built in ddprep. -Note: There are two ways this will be called. The first is when - we are building a dictionary from scratch. The second is ONLY - when a new field definition or container is added, or an index's - state is changed. -****************************************************************************/ -RCODE fdictBuildTables( - TDICT * pTDict, - FLMBOOL bRereadLFiles, - FLMBOOL bNewDict) -{ - RCODE rc = FERR_OK; - DDENTRY * pEntry; - TFIELD * pTField; - FLMUINT uiEntryNum; - TENCDEF * pTEncDef; - - if( RC_BAD( rc = fdictReallocAllTables( pTDict))) - { - goto Exit; - } - - // Go through and add each new item to the dictionary. - - for( pEntry = pTDict->pFirstEntry - ; pEntry - ; pEntry = pEntry->pNextEntry ) - { - uiEntryNum = pEntry->uiEntryNum; - - switch( pEntry->uiType) - { - case 0: // Field - { - pTField = (TFIELD *) pEntry->vpDef; - fdictAddItem( pTDict, uiEntryNum, pTField->uiFldInfo); - break; - } - - case ITT_INDEX_TYPE: - { - fdictAddItem( pTDict, uiEntryNum, ITT_INDEX_TYPE); - if( RC_BAD( rc = fdictAddIndex( pTDict, pEntry ))) - { - goto Exit; - } - break; - } - - case ITT_CONTAINER_TYPE: - { - fdictAddItem( pTDict, uiEntryNum, ITT_CONTAINER_TYPE); - // rc = fdictAddLFile( pTDict, pEntry ); Already done. - break; - } - - case ITT_ENCDEF_TYPE: - { - if (!pTDict->pDb->pFile) - { - flmAssert( 0); - rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); - goto Exit; - } - else - { - fdictAddItem( pTDict, uiEntryNum, ITT_ENCDEF_TYPE); - - pTEncDef = (TENCDEF *) pEntry->vpDef; - // Need to add a new CCS. - if (RC_BAD( rc = fdictAddNewCCS(pTDict, pTEncDef, uiEntryNum))) - { - goto Exit; - } - } - break; - } - - default: - { - break; - } - } - } - - if( pTDict->uiNewIfds || bNewDict) - { - if( RC_BAD( rc = fdictFixupIfdPointers( pTDict->pDict, - bNewDict ? 0 : (pTDict->uiTotalIfds - pTDict->uiNewIfds)))) - { - goto Exit; - } - } - - if( bRereadLFiles) - { - if( RC_BAD( rc = fdictReadLFiles( pTDict->pDb, pTDict->pDict))) - { - goto Exit; - } - } - - if( RC_BAD( rc = fdictFixupLFileTbl( pTDict->pDict))) - { - goto Exit; - } - -Exit: - - return( rc ); -} - -/**************************************************************************** -Desc: Fixup pointers in tables of copied dictionary. This is called after - a copy of one dictionary to another, or after a dictionary's tables - have been reallocated. -****************************************************************************/ -FSTATIC void fdictFixupPointers( - FDICT * pNewDict, - FDICT * pOldDict - ) -{ - FLMUINT uiPos; - FLMUINT uiOffset; - LFILE * pOldLFile; - LFILE * pNewLFile; - IFD * pOldIfd; - IFD * pNewIfd; - IXD * pOldIxd; - IXD * pNewIxd; - ITT * pOldItt; - ITT * pNewItt; - - // Fixup anything that points to LFILE entries. - - if (pNewDict->pLFileTbl && pNewDict->pLFileTbl != pOldDict->pLFileTbl) - { - - // Fixup pItt->pvItem pointers for indexes and containers - - for (uiPos = 0, pOldItt = pOldDict->pIttTbl, - pNewItt = pNewDict->pIttTbl; - uiPos < pOldDict->uiIttCnt; - uiPos++, pOldItt++, pNewItt++) - { - if (ITT_IS_CONTAINER( pOldItt) || ITT_IS_INDEX( pOldItt)) - { - if (pOldItt->pvItem) - { - LFILE * pTmpLFile; - - pTmpLFile = (LFILE *)(pOldItt->pvItem); - uiOffset = (FLMUINT)(pTmpLFile - pOldDict->pLFileTbl); - pTmpLFile = pNewDict->pLFileTbl + uiOffset; - pNewItt->pvItem = (void *)pTmpLFile; - } - else - { - flmAssert( pNewItt->pvItem == NULL); - } - } - else if (ITT_IS_ENCDEF( pOldItt)) - { - if (pOldItt->pvItem) - { - pNewItt->pvItem = pOldItt->pvItem; - ((F_CCS *)pNewItt->pvItem)->AddRef(); - } - else - { - flmAssert( pNewItt->pvItem == NULL); - } - } - } - } - - // Fixup anything that points to IXD entries - - if (pNewDict->pIxdTbl && pNewDict->pIxdTbl != pOldDict->pIxdTbl) - { - - // Fixup pLFile->pIxd pointers - - for (uiPos = 0, pOldLFile = pOldDict->pLFileTbl, - pNewLFile = pNewDict->pLFileTbl; - uiPos < pOldDict->uiLFileCnt; - uiPos++, pOldLFile++, pNewLFile++) - { - if (pOldLFile->pIxd) - { - uiOffset = (FLMUINT)(pOldLFile->pIxd - pOldDict->pIxdTbl); - pNewLFile->pIxd = pNewDict->pIxdTbl + uiOffset; - } - else - { - flmAssert( pNewLFile->pIxd == NULL); - } - } - - // Fixup pIfd->pIxd pointers - - for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, - pNewIfd = pNewDict->pIfdTbl; - uiPos < pOldDict->uiIfdCnt; - uiPos++, pOldIfd++, pNewIfd++) - { - if (pOldIfd->pIxd) - { - uiOffset = (FLMUINT)(pOldIfd->pIxd - pOldDict->pIxdTbl); - pNewIfd->pIxd = pNewDict->pIxdTbl + uiOffset; - } - else - { - flmAssert( pNewIfd->pIxd == NULL); - } - } - } - - // Fixup anything that points to IFD entries - - if (pNewDict->pIfdTbl && pNewDict->pIfdTbl != pOldDict->pIfdTbl) - { - - // Fixup pIfd->pNextInChain pointers - - for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, - pNewIfd = pNewDict->pIfdTbl; - uiPos < pOldDict->uiIfdCnt; - uiPos++, pOldIfd++, pNewIfd++) - { - if (pOldIfd->pNextInChain) - { - uiOffset = (FLMUINT)(pOldIfd->pNextInChain - pOldDict->pIfdTbl); - pNewIfd->pNextInChain = pNewDict->pIfdTbl + uiOffset; - } - else - { - flmAssert( pNewIfd->pNextInChain == NULL); - } - } - - // Fixup pIxd->pFirstIfd pointers - - for (uiPos = 0, pOldIxd = pOldDict->pIxdTbl, - pNewIxd = pNewDict->pIxdTbl; - uiPos < pOldDict->uiIxdCnt; - uiPos++, pOldIxd++, pNewIxd++) - { - if (pOldIxd->pFirstIfd) - { - uiOffset = (FLMUINT)(pOldIxd->pFirstIfd - pOldDict->pIfdTbl); - pNewIxd->pFirstIfd = pNewDict->pIfdTbl + uiOffset; - } - else - { - flmAssert( pNewIxd->pFirstIfd == NULL); - } - } - - // Fixup pItt->pvItem pointers - - for (uiPos = 0, pOldItt = pOldDict->pIttTbl, - pNewItt = pNewDict->pIttTbl; - uiPos < pOldDict->uiIttCnt; - uiPos++, pOldItt++, pNewItt++) - { - if (ITT_IS_FIELD( pOldItt)) - { - if (pOldItt->pvItem) - { - IFD * pTmpIfd; - - pTmpIfd = (IFD *)(pOldItt->pvItem); - uiOffset = (FLMUINT)(pTmpIfd - pOldDict->pIfdTbl); - pTmpIfd = pNewDict->pIfdTbl + uiOffset; - pNewItt->pvItem = (void *)pTmpIfd; - } - else - { - flmAssert( pNewItt->pvItem == NULL); - } - } - } - } - - // Fixup anything that points to field path entries - - if (pNewDict->pFldPathsTbl && pNewDict->pFldPathsTbl != pOldDict->pFldPathsTbl) - { - - // Fixup pIfd->pFieldPathCToP and pIfd->pFieldPathPToC pointers - - for (uiPos = 0, pOldIfd = pOldDict->pIfdTbl, - pNewIfd = pNewDict->pIfdTbl; - uiPos < pOldDict->uiIfdCnt; - uiPos++, pOldIfd++, pNewIfd++) - { - if (pOldIfd->pFieldPathCToP) - { - uiOffset = (FLMUINT)(pOldIfd->pFieldPathCToP - pOldDict->pFldPathsTbl); - pNewIfd->pFieldPathCToP = pNewDict->pFldPathsTbl + uiOffset; - } - else - { - flmAssert( pNewIfd->pFieldPathCToP == NULL); - } - if (pOldIfd->pFieldPathPToC) - { - uiOffset = (FLMUINT)(pOldIfd->pFieldPathPToC - pOldDict->pFldPathsTbl); - pNewIfd->pFieldPathPToC = pNewDict->pFldPathsTbl + uiOffset; - } - else - { - flmAssert( pNewIfd->pFieldPathPToC == NULL); - } - } - - } -} - -/**************************************************************************** -Desc: Allocate all of the dictionary tables based on the counts that - were incremented in pTDict. Coded to add new fields, indexes or - container, but not to modify or delete anything! -****************************************************************************/ -FSTATIC RCODE fdictReallocAllTables( - TDICT * pTDict) -{ - RCODE rc = FERR_OK; - FDICT OldDict; - FDICT * pDict = pTDict->pDict; - - // Save a copy of the old dictionary's pointers and counters - // Easiest way to do this is to simply copy the structure. - - f_memcpy( &OldDict, pDict, sizeof( FDICT)); - - if( pTDict->pLastEntry - && pTDict->pLastEntry->uiEntryNum >= pDict->uiIttCnt - && pTDict->pLastEntry->uiEntryNum < FLM_RESERVED_TAG_NUMS) - { - ITT * pItt; - FLMUINT uiNewCount; - - uiNewCount = pTDict->pLastEntry->uiEntryNum + 1 - pDict->uiIttCnt; - if (uiNewCount) - { - - // Must fake out so that we don't lose the old table. - - pDict->pIttTbl = NULL; - if( RC_BAD( rc = fdictReallocTbl( sizeof( ITT), pDict->uiIttCnt, - uiNewCount, (void **) &pDict->pIttTbl))) - { - goto Exit; - } - pTDict->uiTotalItts = pDict->uiIttCnt + uiNewCount; - - // Copy the table to the new location (because of fake out above) - - if( OldDict.uiIttCnt) - { - f_memcpy( pDict->pIttTbl, OldDict.pIttTbl, - sizeof( ITT) * OldDict.uiIttCnt); - } - - // Initialize the new items to empty. - - pItt = pDict->pIttTbl + pDict->uiIttCnt; - for( ;uiNewCount--; pItt++) - { - pItt->uiType = ITT_EMPTY_SLOT; - pItt->pvItem = NULL; - } - } - } - - if (pTDict->uiNewIxds) - { - - // Must fake out so that we don't lose the old table. - - pDict->pIxdTbl = NULL; - if( RC_BAD( rc = fdictReallocTbl( sizeof( IXD), pDict->uiIxdCnt, - pTDict->uiNewIxds, (void **)&pDict->pIxdTbl))) - { - goto Exit; - } - pTDict->uiTotalIxds = pDict->uiIxdCnt + pTDict->uiNewIxds; - - // Copy the table to the new location (because of fake out above) - - if( OldDict.uiIxdCnt) - { - f_memcpy( pDict->pIxdTbl, OldDict.pIxdTbl, - sizeof( IXD) * OldDict.uiIxdCnt); - } - } - - if (pTDict->uiNewIfds) - { - - // Must fake out so that we don't lose the old table. - - pDict->pIfdTbl = NULL; - if( RC_BAD( rc = fdictReallocTbl( sizeof( IFD), pDict->uiIfdCnt, - pTDict->uiNewIfds, (void **)&pDict->pIfdTbl))) - { - goto Exit; - } - pTDict->uiTotalIfds = pDict->uiIfdCnt + pTDict->uiNewIfds; - - // Copy the table to the new location (because of fake out above) - - if( OldDict.uiIfdCnt) - { - f_memcpy( pDict->pIfdTbl, OldDict.pIfdTbl, - sizeof( IFD) * OldDict.uiIfdCnt); - } - } - - if (pTDict->uiNewFldPaths) - { - - // Must fake out so that we don't lose the old table. - - pDict->pFldPathsTbl = NULL; - if( RC_BAD( rc = fdictReallocTbl( sizeof( FLMUINT), pDict->uiFldPathsCnt, - pTDict->uiNewFldPaths, (void **)&pDict->pFldPathsTbl))) - { - goto Exit; - } - pTDict->uiTotalFldPaths = pDict->uiFldPathsCnt + pTDict->uiNewFldPaths; - - // Copy the table to the new location (because of fake out above) - - if( OldDict.uiFldPathsCnt) - { - f_memcpy( pDict->pFldPathsTbl, OldDict.pFldPathsTbl, - sizeof( FLMUINT) * OldDict.uiFldPathsCnt); - } - } - - fdictFixupPointers( pDict, &OldDict); - -Exit: - - // Free any old tables where a new table was allocated. - - if (OldDict.pLFileTbl != pDict->pLFileTbl) - { - f_free( &OldDict.pLFileTbl); - } - if (OldDict.pIttTbl != pDict->pIttTbl) - { - f_free( &OldDict.pIttTbl); - } - if (OldDict.pIxdTbl != pDict->pIxdTbl) - { - f_free( &OldDict.pIxdTbl); - } - if (OldDict.pIfdTbl != pDict->pIfdTbl) - { - f_free( &OldDict.pIfdTbl); - } - if (OldDict.pFldPathsTbl != pDict->pFldPathsTbl) - { - f_free( &OldDict.pFldPathsTbl); - } - - return( rc ); -} - - -/**************************************************************************** -Desc: Allocate or reallocate a table. -****************************************************************************/ -FSTATIC RCODE fdictReallocTbl( - FLMUINT uiElementSize, - FLMUINT uiTblSize, - FLMUINT uiAddElements, - void ** ppvTblRV) -{ - RCODE rc = FERR_OK; - - // Does the table need to grow? - - if( uiAddElements) - { - if( *ppvTblRV) - { - if( RC_BAD( rc = f_recalloc( - uiElementSize * (uiTblSize + uiAddElements), - ppvTblRV))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = f_calloc( - uiElementSize * (uiTblSize + uiAddElements), - ppvTblRV))) - { - goto Exit; - } - } - } - -Exit: - - return( rc ); -} - -/**************************************************************************** -Desc: Add a new item to the item type table. -****************************************************************************/ -FSTATIC void fdictAddItem( - TDICT * pTDict, - FLMUINT uiFieldNum, - FLMUINT uiFieldType) -{ - FDICT * pDict = pTDict->pDict; - ITT * pItt; - - if( uiFieldNum < FLM_RESERVED_TAG_NUMS) - { - pItt = pDict->pIttTbl + uiFieldNum; - pItt->uiType = uiFieldType; - pItt->pvItem = NULL; - - if( uiFieldNum >= pDict->uiIttCnt) - { - pDict->uiIttCnt = uiFieldNum + 1; - } - } -} - -/**************************************************************************** -Desc: Add the new IXD, IFD, field paths and LFILE for the index. -****************************************************************************/ -FSTATIC RCODE fdictAddIndex( - TDICT * pTDict, - DDENTRY * pEntry) -{ - RCODE rc = FERR_OK; - FDICT * pDict = pTDict->pDict; - FLMUINT uiIndexNum = pEntry->uiEntryNum; - IXD * pIxd; - IFD * pIfd; - FLMUINT * pFirstPToCFld; - FLMUINT * pFirstCToPFld; - FLMUINT * pCurFld; - FLMUINT * pTempFld; - TIXD * pTIxd; - TIFD * pTIfd; - TIFP * pTIfp; - - // The index numbers in the IXD array do not need to be in any order. - // Just add all of the index information to the end of the table. - - pIxd = pDict->pIxdTbl + pDict->uiIxdCnt++; - pIxd->uiIndexNum = uiIndexNum; - - pTIxd = (TIXD *) pEntry->vpDef; - pIxd->uiContainerNum = pTIxd->uiContainerNum; - pIxd->uiNumFlds = pTIxd->uiNumFlds; - pIxd->uiFlags = pTIxd->uiFlags; - pIxd->uiLanguage = pTIxd->uiLanguage; - pIxd->uiLastContainerIndexed = 0xFFFFFFFF; - pIxd->uiLastDrnIndexed = DRN_LAST_MARKER; - pIxd->uiEncId = pTIxd->uiEncId; - - // Setup the IFD elements and the field paths. - - pIxd->pFirstIfd = pIfd = pDict->pIfdTbl + pDict->uiIfdCnt; - pDict->uiIfdCnt += pIxd->uiNumFlds; - - for( pTIfd = pTIxd->pNextTIfd; pTIfd; pIfd++, pTIfd = pTIfd->pNextTIfd) - { - // This is a good place to set the IFD_LAST flag. - // Could/Should be done in ddprep.c - - if( pTIfd->pNextTIfd == NULL) - pTIfd->uiFlags |= IFD_LAST; - - pIfd->uiIndexNum = uiIndexNum; - pIfd->pIxd = pIxd; - pIfd->uiFlags = pTIfd->uiFlags; - pIfd->uiLimit = pTIfd->uiLimit; - pIfd->uiCompoundPos = pTIfd->uiCompoundPos; - - // The pTIfp->pNextTIfp are linked from parent to child. - pTIfp = pTIfd->pTIfp; - pCurFld = pDict->pFldPathsTbl + pDict->uiFldPathsCnt; - pFirstPToCFld = pFirstCToPFld = pCurFld; - - pIfd->pFieldPathPToC = pFirstPToCFld; - - do - { - *pCurFld++ = pTIfp->uiFldNum; - pTIfp = pTIfp->pNextTIfp; - - } while( pTIfp); - - pIfd->uiFldNum = *(pCurFld-1); - pTempFld = pCurFld - 1; - - // Null Terminate - *pCurFld++ = 0; - - pTIfp = pTIfd->pTIfp; - if( pTIfp->pNextTIfp) // If more than one field make the CToP path. - { - pFirstCToPFld = pCurFld; - while( pTempFld != pFirstPToCFld) - { - *pCurFld++ = *pTempFld--; - } - *pCurFld++ = *pTempFld; - *pCurFld++ = 0; - } - pIfd->pFieldPathCToP = pFirstCToPFld; - pDict->uiFldPathsCnt += pCurFld - pFirstPToCFld; - } - - return( rc ); -} - -/**************************************************************************** -Desc: Fixup the IFD chain and the pIfd->pIxd pointers. -****************************************************************************/ -FSTATIC RCODE fdictFixupIfdPointers( - FDICT * pDict, - FLMUINT uiIfdStartOffset) -{ - RCODE rc = FERR_OK; - FLMUINT uiCount; - IFD * pIfd; - ITT * pItt; - ITT * pIttTbl = pDict->pIttTbl; - - // Go through the IFD list and setup the pNextInChain pointers - // making sure that the required fields are first. - - for( uiCount = pDict->uiIfdCnt - uiIfdStartOffset, - pIfd = pDict->pIfdTbl + uiIfdStartOffset; - uiCount; uiCount--, pIfd++) - { - IFD * pPrevInChain; - IFD * pTempIfd; - - if( pIfd->uiFldNum >= pDict->uiIttCnt) - { - if( pIfd->uiFldNum < FLM_RESERVED_TAG_NUMS) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - continue; - } - else - { - pItt = pIttTbl + pIfd->uiFldNum; - if( !ITT_IS_FIELD( pItt)) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - } - - // Move the field type to the pIfd->uiFlags - IFD_SET_FIELD_TYPE( pIfd, ITT_FLD_GET_TYPE( pItt)); - - // Visit: We could verify all of the fields in the field path. - // Need to include 'any', 'use', 'parent' tags as valid tags. - - if( !pItt->pvItem) - { - pItt->pvItem = (void *) pIfd; - } - else - { - // Follow the chain and index at the front or rear depending on - // if the field is required within the set. - - pTempIfd = (IFD *) pItt->pvItem; - if( (pIfd->uiFlags & IFD_REQUIRED_IN_SET) - || !(pTempIfd->uiFlags & IFD_REQUIRED_IN_SET)) - { - pIfd->pNextInChain = pTempIfd; - pItt->pvItem = (void *) pIfd; - } - else - { - // Not required in set and first IFD is required in set. - // Look for first not required IFD in the chain. - - pPrevInChain = pTempIfd; - pTempIfd = pTempIfd->pNextInChain; - - for( ; pTempIfd; pTempIfd = pTempIfd->pNextInChain) - { - if( !(pTempIfd->uiFlags & IFD_REQUIRED_IN_SET)) - break; - pPrevInChain = pTempIfd; - } - pIfd->pNextInChain = pPrevInChain->pNextInChain; - pPrevInChain->pNextInChain = pIfd; - } - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Fixup the ITT pointers into the LFILE elements and all of - the IXD pointers in the LDICT. -****************************************************************************/ -RCODE fdictFixupLFileTbl( - FDICT * pDict) -{ - RCODE rc = FERR_OK; - FLMUINT uiCount; - LFILE * pLFile; - IXD * pIxd; - ITT * pItt; - ITT * pIttTbl = pDict->pIttTbl; - FLMUINT uiIttCnt = pDict->uiIttCnt; - - for( uiCount = pDict->uiLFileCnt, pLFile = pDict->pLFileTbl - ; uiCount; uiCount--, pLFile++) - { - - if( pLFile->uiLfNum != FLM_DATA_CONTAINER - && pLFile->uiLfNum != FLM_DICT_CONTAINER - && pLFile->uiLfNum != FLM_DICT_INDEX - && pLFile->uiLfNum != FLM_TRACKER_CONTAINER) - { - pItt = pIttTbl + pLFile->uiLfNum; - - if( uiIttCnt <= pLFile->uiLfNum || - (pLFile->uiLfType == LF_CONTAINER && !ITT_IS_CONTAINER( pItt))) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - if( pLFile->uiLfType == LF_INDEX && !ITT_IS_INDEX( pItt)) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - - pItt->pvItem = pLFile; - } - else if( pLFile->uiLfNum == FLM_DICT_INDEX) - { - // The first IXD should be the dictionary index. - - if( pDict->pIxdTbl && pDict->pIxdTbl->uiIndexNum == FLM_DICT_INDEX) - { - pLFile->pIxd = pDict->pIxdTbl; - } - } - } - - // Now that all of the indexes/containers in the ITT table point - // to the LFILE entries, fixup the LFILE to point to the IXD entries. - - for( uiCount = pDict->uiIxdCnt, pIxd = pDict->pIxdTbl; - uiCount; uiCount--, pIxd++) - { - if( uiIttCnt <= pIxd->uiIndexNum) - { - if( pIxd->uiIndexNum != FLM_DICT_INDEX) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - } - else - { - pItt = pIttTbl + pIxd->uiIndexNum; - pLFile = (LFILE *) pItt->pvItem; - - if( !pLFile) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - pLFile->pIxd = pIxd; - } - - // Verify that the pIxd->uiContainerNum is actually a container. - // A value of 0 means that the index is on ALL containers. - - if (pIxd->uiContainerNum) - { - if( uiIttCnt <= pIxd->uiContainerNum) - { - if( pIxd->uiContainerNum != FLM_DATA_CONTAINER - && pIxd->uiContainerNum != FLM_DICT_CONTAINER - && pIxd->uiContainerNum != FLM_TRACKER_CONTAINER) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - } - else - { - pItt = pIttTbl + pIxd->uiContainerNum; - if( !ITT_IS_CONTAINER( pItt)) - { - rc = RC_SET( FERR_BAD_REFERENCE); - goto Exit; - } - } - } - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Add a new CCS reference to the item type table. If a key is included - we can use it, otherwise we will have to generate one. -****************************************************************************/ -FSTATIC RCODE fdictAddNewCCS( - TDICT * pTDict, - TENCDEF * pTEncDef, - FLMUINT uiRecNum) -{ - RCODE rc = FERR_OK; - FDICT * pDict = pTDict->pDict; - ITT * pItt; - F_CCS * pCcs = NULL; - FDB * pDb = pTDict->pDb; - F_CCS * pDbWrappingKey; - - if( uiRecNum >= FLM_RESERVED_TAG_NUMS) - { - goto Exit; - } - - if (!pDb->pFile->bInLimitedMode) - { - - pDbWrappingKey = pDb->pFile->pDbWrappingKey; - - flmAssert( pTEncDef); - - if ((pCcs = f_new F_CCS) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Setup the F_CCS. - if (RC_BAD( rc = pCcs->init( FALSE, pTEncDef->uiAlgType ))) - { - goto Exit; - } - - if (!pTEncDef->uiLength) - { - flmAssert( 0); - rc = RC_SET( FERR_MISSING_ENC_KEY); - goto Exit; - } - - // We need to set the key information. This also unwraps the key and stores the - // handle. - - if( RC_BAD( rc = pCcs->setKeyFromStore( pTEncDef->pucKeyInfo, - (FLMUINT32)pTEncDef->uiLength, NULL, pDbWrappingKey))) - { - goto Exit; - } - } - - // Save the CCS object in the ITT table. - - pItt = pDict->pIttTbl + uiRecNum; - pItt->pvItem = (void *)pCcs; - pCcs = NULL; - - if( uiRecNum >= pDict->uiIttCnt) - { - pDict->uiIttCnt = uiRecNum + 1; - } - -Exit: - - if (pCcs) - { - delete pCcs; - } - - return( rc); - -} - -/**************************************************************************** -Desc: Copies an existing dictionary to a new dictionary. This does not - fix up all of the ITT's pvItem pointers (including the - pFirstIfd pointer of fields in the ITT table). To clone the - dictionary, call fdictCloneDict. -****************************************************************************/ -RCODE fdictCopySkeletonDict( - FDB * pDb) -{ - RCODE rc = FERR_OK; - FDICT * pNewDict = NULL; - FDICT * pOldDict = pDb->pDict; - FLMUINT uiTblSize; - FLMUINT uiPos; - LFILE * pLFile; - IXD * pIxd; - ITT * pItt; - ITT * pNewIttTbl = NULL; - FLMUINT uiNewIttTblLen = 0; - LFILE * pNewDictIndexLFile = NULL; - FLMUINT * pOldFieldPathsTbl = NULL; - FLMUINT * pNewFieldPathsTbl = NULL; - - if( RC_BAD( rc = f_calloc( (FLMUINT)sizeof( FDICT), &pNewDict))) - { - goto Exit; - } - - pNewDict->pNext = pNewDict->pPrev = NULL; - pNewDict->pFile = NULL; - pNewDict->uiUseCount = 1; - - // Nothing to do is not a legal state. - if( !pOldDict) - { - flmAssert( pOldDict != NULL); - pDb->pDict = pNewDict; - goto Exit; - } - - // ITT Table - - if( (uiTblSize = pNewDict->uiIttCnt = pOldDict->uiIttCnt) != 0) - { - if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( ITT), &pNewDict->pIttTbl))) - { - goto Exit; - } - pNewIttTbl = pNewDict->pIttTbl; - uiNewIttTblLen = uiTblSize; - f_memcpy( pNewDict->pIttTbl, pOldDict->pIttTbl, - uiTblSize * sizeof( ITT)); - - // Clear out all of the pointer values. - pItt = pNewDict->pIttTbl; - for( uiPos = 0; uiPos < uiTblSize; uiPos++, pItt++) - { - if ( pItt->uiType == ITT_ENCDEF_TYPE && !pDb->pFile->bInLimitedMode) - { - flmAssert( pItt->pvItem); - ((F_CCS *)pItt->pvItem)->AddRef(); - } - else - { - pItt->pvItem = NULL; - } - } - } - - // LFILE Table - - if( (uiTblSize = pNewDict->uiLFileCnt = pOldDict->uiLFileCnt) != 0) - { - if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( LFILE), - &pNewDict->pLFileTbl))) - { - goto Exit; - } - f_memcpy( pNewDict->pLFileTbl, pOldDict->pLFileTbl, - uiTblSize * sizeof( LFILE)); - - for( pLFile = pNewDict->pLFileTbl; uiTblSize--; pLFile++) - { - if( pLFile->uiLfNum < FLM_RESERVED_TAG_NUMS) - { - // WARNING: The code must make a new LFILE - // before the dictionary is aware of it. - - if( pLFile->uiLfNum < uiNewIttTblLen) - { - pItt = pNewIttTbl + pLFile->uiLfNum; - pItt->pvItem = (void *) pLFile; - } - } - else if( pLFile->uiLfNum == FLM_DICT_INDEX) - { - pNewDictIndexLFile = pLFile; - } - } - } - - // IXD Table - - if( (uiTblSize = pNewDict->uiIxdCnt = pOldDict->uiIxdCnt) != 0) - { - if( RC_BAD( rc = f_alloc( - uiTblSize * sizeof( IXD), &pNewDict->pIxdTbl))) - { - goto Exit; - } - f_memcpy( pNewDict->pIxdTbl, pOldDict->pIxdTbl, - uiTblSize * sizeof( IXD)); - - // Fixup all of the pointers to the IXD. - - for( pIxd = pNewDict->pIxdTbl; uiTblSize--; pIxd++) - { - if( pIxd->uiIndexNum != FLM_DICT_INDEX) - { - pItt = pNewIttTbl + pIxd->uiIndexNum; - pLFile = (LFILE *) pItt->pvItem; - pLFile->pIxd = pIxd; - } - else if( pNewDictIndexLFile) - { - pNewDictIndexLFile->pIxd = pIxd; - } - } - } - - // Field Paths Table - - if( (uiTblSize = pNewDict->uiFldPathsCnt = pOldDict->uiFldPathsCnt) != 0) - { - if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( FLMUINT), - &pNewDict->pFldPathsTbl))) - { - goto Exit; - } - f_memcpy( pNewDict->pFldPathsTbl, pOldDict->pFldPathsTbl, - uiTblSize * sizeof( FLMUINT)); - - pOldFieldPathsTbl = pOldDict->pFldPathsTbl; - pNewFieldPathsTbl = pNewDict->pFldPathsTbl; - } - - // IFD Table - - if( (uiTblSize = pNewDict->uiIfdCnt = pOldDict->uiIfdCnt) != 0) - { - IFD * pIfd; - FLMUINT uiLastIndexNum; - FLMUINT uiOffset; - - if( RC_BAD( rc = f_alloc( uiTblSize * sizeof( IFD), - &pNewDict->pIfdTbl))) - { - goto Exit; - } - f_memcpy( pNewDict->pIfdTbl, pOldDict->pIfdTbl, - uiTblSize * sizeof( IFD)); - - // Fixup all pFirstIfd pointers, backlinks to the pIxd and fldPathTbls. - // Set all of the IfdChain values to NULL to be fixed up later. - pIfd = pNewDict->pIfdTbl; - uiLastIndexNum = 0; - - for( uiPos = 0; uiPos < uiTblSize; uiPos++, pIfd++) - { - pIfd->pNextInChain = NULL; - - if( pIfd->uiIndexNum != FLM_DICT_INDEX) - { - pItt = pNewIttTbl + pIfd->uiIndexNum; - pLFile = (LFILE *) pItt->pvItem; - pIxd = pLFile->pIxd; - } - else - { - pIxd = pNewDictIndexLFile->pIxd; - } - - pIfd->pIxd = pIxd; - if( uiLastIndexNum != pIfd->uiIndexNum) - { - pIxd->pFirstIfd = pIfd; - uiLastIndexNum = pIfd->uiIndexNum; - } - - // Fixup the field paths. - - flmAssert( pNewFieldPathsTbl != NULL); - uiOffset = pIfd->pFieldPathCToP - pOldFieldPathsTbl; - pIfd->pFieldPathCToP = pNewFieldPathsTbl + uiOffset; - - uiOffset = pIfd->pFieldPathPToC - pOldFieldPathsTbl; - pIfd->pFieldPathPToC = pNewFieldPathsTbl + uiOffset; - } - } - - f_mutexLock( gv_FlmSysData.hShareMutex); - flmUnlinkFdbFromDict( pDb); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - pDb->pDict = pNewDict; - pNewDict = NULL; - -Exit: - - if( RC_BAD( rc) && pNewDict) - { - // Undo all of the allocations on the new table. - if( pNewDict->pLFileTbl) - { - f_free( &pNewDict->pLFileTbl); - } - if( pNewDict->pIttTbl) - { - f_free( &pNewDict->pIttTbl); - } - if( pNewDict->pIxdTbl) - { - f_free( &pNewDict->pIxdTbl); - } - if( pNewDict->pIfdTbl) - { - f_free( &pNewDict->pIfdTbl); - } - if( pNewDict->pFldPathsTbl) - { - f_free( &pNewDict->pFldPathsTbl); - } - f_free( &pNewDict); - } - - return( rc); -} - -/**************************************************************************** -Desc: Creates a new version of the current dictionary and fixes up all - pointers -****************************************************************************/ -RCODE fdictCloneDict( - FDB * pDb) -{ - RCODE rc = FERR_OK; - TDICT tDict; - FLMBOOL bTDictInitialized = FALSE; - - if( RC_BAD( rc = fdictCopySkeletonDict( pDb))) - { - goto Exit; - } - - bTDictInitialized = TRUE; - if( RC_BAD( rc = fdictInitTDict( pDb, &tDict))) - { - goto Exit; - } - - if( RC_BAD( rc = fdictBuildTables( &tDict, FALSE, TRUE))) - { - goto Exit; - } - - pDb->uiFlags |= FDB_UPDATED_DICTIONARY; - -Exit: - - if( bTDictInitialized) - { - GedPoolFree( &tDict.pool); - } - - // If we allocated an FDICT and there was an error, free the FDICT. - - if( (RC_BAD( rc)) && (pDb->pDict)) - { - flmFreeDict( pDb->pDict); - pDb->pDict = NULL; - } - - return( rc); -} diff --git a/flaim/src/fdir.h b/flaim/src/fdir.h index 540a5cd..831b47b 100644 --- a/flaim/src/fdir.h +++ b/flaim/src/fdir.h @@ -34,7 +34,7 @@ typedef F_DirHdl * F_DirHdl_p; #if defined( FLM_WIN) - typedef struct + typedef struct F_IO_FIND_DATA { HANDLE findHandle; WIN32_FIND_DATA findBuffer; @@ -52,7 +52,7 @@ typedef F_DirHdl * F_DirHdl_p; #elif defined( FLM_UNIX) - typedef struct _DirInfo + typedef struct F_IO_FIND_DATA { mode_t mode_flag; struct stat FileStat; diff --git a/flaim/src/fdynsset.h b/flaim/src/fdynsset.h index 0639afc..12d2188 100644 --- a/flaim/src/fdynsset.h +++ b/flaim/src/fdynsset.h @@ -61,7 +61,7 @@ typedef int (* FDYNSET_COMPARE_FUNC_p)( const void * vpData2, size_t UserValue); -typedef struct +typedef struct FixedBlkHdr { FLMUINT uiBlkAddr; FLMUINT uiPrevBlkAddr; @@ -468,7 +468,10 @@ public: FBtreeRoot * pNewRoot); }; -typedef struct +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct FBTREE_CACHE { FLMUINT uiBlkAddr; FLMUINT uiLRUValue; diff --git a/flaim/src/fexpimp.cpp b/flaim/src/fexpimp.cpp deleted file mode 100644 index bb5051d..0000000 --- a/flaim/src/fexpimp.cpp +++ /dev/null @@ -1,599 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Export/Import support functions. -// Tabs: 3 -// -// Copyright (c) 1995-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fexpimp.cpp 12319 2006-01-19 15:52:23 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define BINARY_GED_HEADER_LEN 8 - -static FLMBYTE FlmBinaryGedHeader [BINARY_GED_HEADER_LEN] - = { 0xFF, 'F', 'L', 'M', 'D', 'I', 'C', 'T' }; - -static FLMBYTE FlmBinaryRecHeader [BINARY_GED_HEADER_LEN] - = { 0xFF, 'F', 'L', 'M', 'R', 'E', 'C', 'S' }; - -/* Local function prototypes. */ - -FSTATIC RCODE expWrite( - EXP_IMP_INFO_p pExpImpInfo, - const FLMBYTE * pData, - FLMUINT uiDataLen); - -FSTATIC RCODE impRead( - EXP_IMP_INFO_p pExpImpInfo, - FLMBYTE * pData, - FLMUINT uiDataLen, - FLMUINT * puiBytesReadRV); - -/**************************************************************************** -Desc: Initializes the export/import information for reading or writing. -****************************************************************************/ -RCODE expImpInit( - F_FileHdl * pFileHdl, /* File we are going to be exporting to or - importing from. */ - FLMUINT uiFlag, /* Flag indicating whether we are exporting - or importing and what kind of data. - EXPIMP_IMPORT_DICTIONARY - EXPIMP_EXPORT_DICTIONARY - EXPIMP_IMPORT_EXPORT_GEDCOM */ - EXP_IMP_INFO_p pExpImpInfoRV /* Export/Import info. structure that is - to be initialized. */ - ) -{ - RCODE rc; - - f_memset( pExpImpInfoRV, 0, sizeof( EXP_IMP_INFO)); - pExpImpInfoRV->pFileHdl = pFileHdl; - pExpImpInfoRV->bDictRecords = (uiFlag == EXPIMP_IMPORT_EXPORT_GEDCOM) - ? FALSE : TRUE; - - /* Allocate a buffer for reading or writing. */ - - pExpImpInfoRV->uiBufSize = (uiFlag == EXPIMP_IMPORT_EXPORT_GEDCOM) - ? (FLMUINT) 2048 : (FLMUINT) 32768; - for (;;) - { - if( RC_BAD( rc = f_alloc( - pExpImpInfoRV->uiBufSize, &pExpImpInfoRV->pBuf))) - { - pExpImpInfoRV->uiBufSize -= 512; - if (pExpImpInfoRV->uiBufSize < 1024) - { - pExpImpInfoRV->uiBufSize = 0; - goto Exit; - } - } - else - break; - } - - /* If writing, output the header data. If reading, seek past it. */ - - if( uiFlag == EXPIMP_EXPORT_DICTIONARY) - { - - /* Write out the header data. */ - - rc = expWrite( pExpImpInfoRV, FlmBinaryGedHeader, - BINARY_GED_HEADER_LEN); - } - else if( uiFlag == EXPIMP_IMPORT_DICTIONARY) - { - rc = pFileHdl->Seek( (FLMUINT)BINARY_GED_HEADER_LEN, - F_IO_SEEK_SET, &pExpImpInfoRV->uiFilePos); - } - else - { - rc = expWrite( pExpImpInfoRV, FlmBinaryRecHeader, - BINARY_GED_HEADER_LEN); - } -Exit: - if (RC_BAD( rc)) - expImpFree( pExpImpInfoRV); - return( rc); -} - -/**************************************************************************** -Desc: Frees up the buffers used to do reading/writing during an export or - import. -****************************************************************************/ -void expImpFree( - EXP_IMP_INFO_p pExpImpInfo /* Export/Import information. */ - ) -{ - if (pExpImpInfo->pBuf) - f_free( &pExpImpInfo->pBuf); - f_memset( pExpImpInfo, 0, sizeof( EXP_IMP_INFO)); -} - -/**************************************************************************** -Desc: Flush the current export buffer to disk. -****************************************************************************/ -RCODE expFlush( - EXP_IMP_INFO_p pExpImpInfo ) /* Export/Import information. */ -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesWritten; - - if( (pExpImpInfo->uiBufUsed) && (pExpImpInfo->bBufDirty)) - { - if( RC_BAD( rc = pExpImpInfo->pFileHdl->Write( - pExpImpInfo->uiFilePos, - pExpImpInfo->uiBufUsed, pExpImpInfo->pBuf, &uiBytesWritten))) - goto Exit; - if( uiBytesWritten < pExpImpInfo->uiBufUsed) - { - rc = RC_SET( FERR_IO_DISK_FULL); - goto Exit; - } - pExpImpInfo->uiFilePos += uiBytesWritten; - pExpImpInfo->uiCurrBuffOffset = - pExpImpInfo->uiBufUsed = 0; - pExpImpInfo->bBufDirty = FALSE; - } -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Seek to an absolute offset in the export/import file. -****************************************************************************/ -RCODE expImpSeek( - EXP_IMP_INFO_p pExpImpInfo, /* Export/Import information. */ - FLMUINT uiSeekPos /* Absolute offset to seek to. */ - ) -{ - RCODE rc = FERR_OK; - - if ((uiSeekPos >= pExpImpInfo->uiFilePos) && - (uiSeekPos < pExpImpInfo->uiFilePos + (FLMUINT)pExpImpInfo->uiBufUsed)) - { - pExpImpInfo->uiCurrBuffOffset = - (FLMUINT)(uiSeekPos - pExpImpInfo->uiFilePos); - } - else - { - if (pExpImpInfo->bBufDirty) - { - if (RC_BAD( rc = expFlush( pExpImpInfo))) - goto Exit; - } - pExpImpInfo->uiFilePos = uiSeekPos; - pExpImpInfo->uiBufUsed = pExpImpInfo->uiCurrBuffOffset = 0; - } -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Writes data to the export file via the export buffer. -****************************************************************************/ -FSTATIC RCODE expWrite( - EXP_IMP_INFO_p pExpImpInfo, - const FLMBYTE * pData, - FLMUINT uiDataLen) -{ - RCODE rc = FERR_OK; - FLMUINT uiCopyLen; - - while( uiDataLen) - { - if ((uiCopyLen = - (pExpImpInfo->uiBufSize - pExpImpInfo->uiCurrBuffOffset)) > uiDataLen) - uiCopyLen = uiDataLen; - f_memcpy( &pExpImpInfo->pBuf [pExpImpInfo->uiCurrBuffOffset], - pData, uiCopyLen); - pExpImpInfo->bBufDirty = TRUE; - uiDataLen -= uiCopyLen; - pData += uiCopyLen; - pExpImpInfo->uiCurrBuffOffset += uiCopyLen; - if (pExpImpInfo->uiCurrBuffOffset > pExpImpInfo->uiBufUsed) - pExpImpInfo->uiBufUsed = pExpImpInfo->uiCurrBuffOffset; - if (pExpImpInfo->uiCurrBuffOffset == pExpImpInfo->uiBufSize) - { - if (RC_BAD( rc = expFlush( pExpImpInfo))) - goto Exit; - } - } -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Writes one FLAIM record to a binary GEDCOM file. -****************************************************************************/ -RCODE expWriteRec( - EXP_IMP_INFO_p pExpImpInfo, /* Buffer info. for export file. */ - FlmRecord * pRecord, /* record to be written out. */ - FLMUINT uiDrn) /* DRN of GEDCOM record being written out. */ -{ - RCODE rc = FERR_OK; - FLMBYTE TBuf [24]; - FLMUINT uiLen; - FLMUINT uiTagNum; - FLMUINT uiInitLevel; - FLMBOOL bOutputtingRecInfo; - FLMBOOL bRootNode; - FLMUINT uiTmpLen; - FlmRecord * pRec = NULL; - FlmRecord * pRecInfoRec = NULL; - void * pvField; - - if( pExpImpInfo->bDictRecords) - { - // Create a record for the RECINFO information - - if( (pRecInfoRec = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = pRecInfoRec->insertLast( 0, - FLM_RECINFO_TAG, FLM_NUMBER_TYPE, &pvField))) - { - goto Exit; - } - - /* Add the record's DRN to the RECINFO information. */ - - if( RC_BAD( rc = flmAddField( pRecInfoRec, FLM_DRN_TAG, - (void *)&uiDrn, 4, FLM_NUMBER_TYPE))) - goto Exit; - - bOutputtingRecInfo = TRUE; - - /* Output both the REC_INFO GEDCOM tree and the record's GEDCOM tree. */ - - bRootNode = FALSE; - pRec = pRecInfoRec; - } - else - { - /* Output only the GEDCOM tree. */ - - bOutputtingRecInfo = FALSE; - bRootNode = TRUE; - pRec = pRecord; - } - - - for(;;) - { - /* Output each node in the record. */ - - pvField = pRec->root(); - uiInitLevel = pRec->getLevel( pvField); - do - { - uiTagNum = pRec->getFieldID( pvField); - uiLen = pRec->getDataLength( pvField); - UW2FBA( (FLMUINT16)uiTagNum, TBuf); - UW2FBA( (FLMUINT16)uiLen, &TBuf[ 2]); - TBuf[ 4] = (FLMBYTE)( pRec->getLevel( pvField) - uiInitLevel); - TBuf[ 5] = (FLMBYTE)( pRec->getDataType( pvField)); - - /* Add on the record source information for the root node. */ - - uiTmpLen = 6; - if( bRootNode) - { - // UD2FBA( pRec->getDatabaseID(), &TBuf[ 6]); <== hDb not supported - UW2FBA( (FLMUINT16)pRec->getContainerID(), &TBuf[ 14]); - UD2FBA( pRec->getID(), &TBuf[ 16]); - uiTmpLen = 20; - - bRootNode = FALSE; - } - - if( RC_BAD( rc = expWrite( pExpImpInfo, TBuf, uiTmpLen))) - goto Exit; - - if( uiLen) - { - const FLMBYTE * pvData = pRec->getDataPtr( pvField); - - if( RC_BAD( rc = expWrite( pExpImpInfo, pvData, uiLen))) - { - goto Exit; - } - } - - pvField = pRec->next( pvField); - - } while( pvField && (pRec->getLevel( pvField) > uiInitLevel)); - - /* Output a zero tag number to indicate end of GEDCOM record. */ - - UW2FBA( 0, TBuf); - if( RC_BAD( rc = expWrite( pExpImpInfo, TBuf, 2))) - goto Exit; - - /* Set things up to output the record after the REC_INFO. */ - - if( !bOutputtingRecInfo) - break; - bOutputtingRecInfo = FALSE; - bRootNode = TRUE; - pRec = pRecord; - } - -Exit: - - if( pRecInfoRec) - { - pRecInfoRec->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: Reads data from the import file via the import buffer. -****************************************************************************/ -FSTATIC RCODE impRead( - EXP_IMP_INFO_p pExpImpInfo, /* Export/Import information. */ - FLMBYTE * pData, /* Buffer where data is to be read into. */ - FLMUINT uiDataLen, /* Length of data to be read in. */ - FLMUINT * puiBytesReadRV) /* Returns amount of data read in. */ -{ - RCODE rc = FERR_OK; - FLMUINT uiCopyLen; - FLMUINT uiBytesRead = 0; - - while (uiDataLen) - { - - /* See if we need to read some more data into the import buffer. */ - - if (pExpImpInfo->uiCurrBuffOffset == pExpImpInfo->uiBufUsed) - { - - /* If we have a dirty buffer, flush it out first. */ - - if (pExpImpInfo->bBufDirty) - { - if (RC_BAD( rc = expFlush( pExpImpInfo))) - goto Exit; - } - else - { - pExpImpInfo->uiFilePos += (FLMUINT)pExpImpInfo->uiBufUsed; - pExpImpInfo->uiBufUsed = pExpImpInfo->uiCurrBuffOffset = 0; - } - if (RC_BAD( rc = pExpImpInfo->pFileHdl->Read( - pExpImpInfo->uiFilePos, - pExpImpInfo->uiBufSize, - pExpImpInfo->pBuf, - &pExpImpInfo->uiBufUsed))) - { - if ((rc == FERR_IO_END_OF_FILE) && (pExpImpInfo->uiBufUsed)) - rc = FERR_OK; - else - goto Exit; - } - } - - /* Copy from the import buffer to the data buffer. */ - - if ((uiCopyLen = - (pExpImpInfo->uiBufUsed - pExpImpInfo->uiCurrBuffOffset)) > uiDataLen) - uiCopyLen = uiDataLen; - f_memcpy( pData, &pExpImpInfo->pBuf [pExpImpInfo->uiCurrBuffOffset], - uiCopyLen); - uiDataLen -= uiCopyLen; - uiBytesRead += uiCopyLen; - pData += uiCopyLen; - pExpImpInfo->uiCurrBuffOffset += uiCopyLen; - } -Exit: - *puiBytesReadRV = uiBytesRead; - return( rc); -} - -/**************************************************************************** -Desc: Reads one GEDCOM record from an export/import file. -****************************************************************************/ -RCODE impReadRec( - EXP_IMP_INFO_p pExpImpInfo, /* Export/Import information. */ - FlmRecord ** ppRecordRV) /* Returns record that was read in. */ -{ - RCODE rc = FERR_OK; - FLMBYTE TBuf [24]; - FLMUINT uiLen; - FLMUINT uiTagNum; - FLMUINT uiRecInfoDrn = 0; - FLMUINT uiDictID; - FLMBOOL bHaveRecInfo = FALSE; - FLMBOOL bHaveDictID = FALSE; - FLMUINT uiLevel; - FLMUINT uiType; - FLMBOOL bGettingRecInfo; - FLMUINT uiBytesRead; - FLMUINT uiTmpLen; - FlmRecord * pRecord = NULL; - void * pvField; - - bGettingRecInfo = (pExpImpInfo->bDictRecords) ? TRUE : FALSE; - - /* Read each node in the REC_INFO (if dictionary) and then the record. */ - - for (;;) - { - if (RC_BAD( rc = impRead( pExpImpInfo, TBuf, 2, &uiBytesRead))) - { - if ((rc == FERR_IO_END_OF_FILE) && (uiBytesRead == 0) && - ((!bGettingRecInfo) || (!bHaveRecInfo))) - { - rc = RC_SET( FERR_END); - } - goto Exit; - } - - /* A tag number of zero means we are at the end of the record. */ - - uiTagNum = FB2UW( TBuf); - if (!uiTagNum) - { - if (bGettingRecInfo) - { - bGettingRecInfo = FALSE; - continue; - } - else - break; - } - uiTmpLen = ((!bGettingRecInfo) && (!pRecord)) - ? 18 - : 4; - if (RC_BAD( rc = impRead( pExpImpInfo, TBuf, uiTmpLen, &uiBytesRead))) - goto Exit; - uiLen = FB2UW( TBuf); - uiLevel = TBuf [2]; - uiType = TBuf [3]; - - if( !pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pRecord->setContainerID( FB2UW( &TBuf[ 12])); - pRecord->setID( FB2UD( &TBuf[ 14])); - } - - if( RC_BAD( rc = pRecord->insertLast( uiLevel, uiTagNum, uiType, &pvField))) - { - goto Exit; - } - - if( uiLen) - { - FLMBYTE * pValue; - - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, uiType, - uiLen, 0, 0, 0, &pValue, NULL))) - { - goto Exit; - } - - if( RC_BAD( rc = impRead( pExpImpInfo, pValue, uiLen, &uiBytesRead))) - goto Exit; - } - - /* Link the node into the tree. */ - - if( bGettingRecInfo) - { - switch( uiTagNum) - { - case FLM_RECINFO_TAG: - bHaveRecInfo = TRUE; - break; - case FLM_DRN_TAG: - if( RC_BAD( rc = pRecord->getUINT( pvField, &uiRecInfoDrn))) - goto Exit; - break; - case FLM_DICT_SEQ_TAG: - if( RC_BAD( rc = pRecord->getUINT( pvField, &uiDictID))) - goto Exit; - bHaveDictID = TRUE; - break; - } - } - } - -Exit: - if( RC_OK( rc)) - { - *ppRecordRV = pRecord; - } - else - { - if( pRecord) - { - pRecord->Release(); - } - - *ppRecordRV = NULL; - } - return( rc); -} - -/**************************************************************************** -Desc: Tests to see if a file is a binary export/import file. After the - call is over, we return the file position to whatever location - it was at before this call was made. -****************************************************************************/ -RCODE impFileIsExpImp( - F_FileHdl * pFileHdl, /* Open file handle. */ - FLMBOOL * pbFileIsBinaryRV) /* Returns TRUE or FALSE to indicate if - file is a binary GEDCOM file. */ -{ - RCODE rc = FERR_OK; - FLMUINT uiCurrPos; - FLMUINT uiIgnore; - FLMBYTE byHeader [BINARY_GED_HEADER_LEN]; - FLMUINT uiBytesRead; - - *pbFileIsBinaryRV = FALSE; - - /* Save current position so we can return to it. */ - - if (RC_BAD( rc = pFileHdl->Seek( (FLMUINT)0, F_IO_SEEK_CUR, &uiCurrPos))) - goto Exit; - - /* Read the file's header information. */ - - if (RC_BAD( rc = pFileHdl->Read( (FLMUINT)0, BINARY_GED_HEADER_LEN, - byHeader, &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - uiBytesRead = 0; - rc = FERR_OK; - } - else - { - goto Exit; - } - } - - if( (uiBytesRead == BINARY_GED_HEADER_LEN) && - ((f_memcmp( byHeader, FlmBinaryGedHeader, BINARY_GED_HEADER_LEN) == 0) || - (f_memcmp( byHeader, FlmBinaryRecHeader, BINARY_GED_HEADER_LEN) == 0))) - { - *pbFileIsBinaryRV = TRUE; - } - - /* Reset the file position to where it was before. */ - - rc = pFileHdl->Seek( uiCurrPos, F_IO_SEEK_SET, &uiIgnore); - -Exit: - return( rc); -} - - diff --git a/flaim/src/ffilehdl.cpp b/flaim/src/ffilehdl.cpp index 410673e..ac4748c 100644 --- a/flaim/src/ffilehdl.cpp +++ b/flaim/src/ffilehdl.cpp @@ -291,19 +291,6 @@ Exit: return( rc); } -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_FileHdlMgr::InsertNew( - F_MutexRef * pMutexRef, - F_FileHdlImp * pFileHdl) -{ - pMutexRef->Lock(); - m_ListMgr.InsertAtEnd( FHM_USED_LIST, (F_ListItem *)pFileHdl); - pMutexRef->Unlock(); - return( FERR_OK); -} - /**************************************************************************** Desc: Make the specified F_FileHdlImp available for someone else to use. ****************************************************************************/ diff --git a/flaim/src/ffilehdl.h b/flaim/src/ffilehdl.h index 03a76f5..5879d25 100644 --- a/flaim/src/ffilehdl.h +++ b/flaim/src/ffilehdl.h @@ -39,8 +39,6 @@ class F_FileHdlPage; class F_ListMgr; class F_MutexRef; -typedef F_FileHdlMgr * F_FileHdlMgr_p; - #define FHM_AVAIL_LIST 0 #define FHM_USED_LIST 1 #define FHM_LNODE_COUNT 2 @@ -48,7 +46,7 @@ typedef F_FileHdlMgr * F_FileHdlMgr_p; RCODE flmCloseAllFiles(); RCODE DetermineLockMgr( - FFILE_p pFile, + FFILE * pFile, F_FileHdlImp * pFileHdl); RCODE flmCopyPartial( @@ -217,9 +215,15 @@ private: FLMBOOL bReadOnlyFlag, // TRUE if looking for read only file F_FileHdlImp ** ppFileHdl); // [out] returned F_FileHdlImp object. - RCODE InsertNew( + FINLINE RCODE InsertNew( F_MutexRef * pMutexRef, - F_FileHdlImp * pFileHdl); // FileHdl to add to this manager. + F_FileHdlImp * pFileHdl) // FileHdl to add to this manager. + { + pMutexRef->Lock(); // ENTER CRITICAL SECTION + m_ListMgr.InsertAtEnd( FHM_USED_LIST, (F_ListItem *)pFileHdl); + pMutexRef->Unlock(); // EXIT CRITICAL SECTION + return( FERR_OK); + } RCODE MakeAvailAndRelease( // Make the specified F_FileHdlImp available for // someone else to use. diff --git a/flaim/src/ffilehdr.cpp b/flaim/src/ffilehdr.cpp index ca8ba99..011b42c 100644 --- a/flaim/src/ffilehdr.cpp +++ b/flaim/src/ffilehdr.cpp @@ -1,365 +1,405 @@ -//------------------------------------------------------------------------- -// Desc: Database header routines. -// Tabs: 3 -// -// Copyright (c) 1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: ffilehdr.cpp 12256 2006-01-19 14:37:14 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/******************************************************************** -Desc: Initializes the file prefix for the .db database file. -*********************************************************************/ -void flmSetFilePrefix( - FLMBYTE * pPrefix, - FLMUINT uiMajorVer, - FLMUINT uiMinorVer) -{ - f_memset( pPrefix, 0, 16); - pPrefix [0] = 0xFF; - pPrefix [1] = f_toascii('W'); - pPrefix [2] = f_toascii('P'); - pPrefix [3] = f_toascii('C'); - - UD2FBA( (FLMUINT32)16, &pPrefix [4]); - - // Fill these out with the old NDS values so FUSION code will work. - - pPrefix [8] = 0xF3; // old wp product type - pPrefix [9] = 0x01; // old wp file type - pPrefix [10] = (FLMBYTE)uiMajorVer; - pPrefix [11] = (FLMBYTE)uiMinorVer; - - // Bytes 12 and 13 are the encryption key - - pPrefix [12] = pPrefix [13] = 0; - - // Bytes 14 and 15 point are the offset to file specific packets - - pPrefix [14] = pPrefix [15] = 0; -} - -/******************************************************************** -Desc: This routine adjusts the block size that is passe in (wBlkSize) - to the nearest valid block size. -*********************************************************************/ -FLMUINT flmAdjustBlkSize( - FLMUINT uiBlkSize) -{ - FLMUINT uiTmpBlkSize; - - uiTmpBlkSize = MIN_BLOCK_SIZE; - while( (uiBlkSize > uiTmpBlkSize) && (uiTmpBlkSize < MAX_BLOCK_SIZE)) - { - uiTmpBlkSize <<= 1; - } - - return( uiTmpBlkSize); -} - -/*************************************************************************** -Desc: This routine extracts and verifies the information within - the file header. -*****************************************************************************/ -RCODE flmGetFileHdrInfo( - FLMBYTE * pPrefixBuf, /* Buffer containing file prefix - information. */ - FLMBYTE * pFileHdrBuf, /* Buffer containing file header - information. */ - FILE_HDR_p pFileHdrRV) /* Returns file header information. */ -{ - RCODE rc = FERR_OK; - FLMUINT uiVersionNum; - FLMUINT uiTmpBlkSize; - - /* Get the create options. */ - - pFileHdrRV->uiBlockSize = (FLMUINT)FB2UW( &pFileHdrBuf [DB_BLOCK_SIZE]); - pFileHdrRV->uiAppMajorVer = pPrefixBuf [10]; - pFileHdrRV->uiAppMinorVer = pPrefixBuf [11]; - pFileHdrRV->uiDefaultLanguage = pFileHdrBuf [DB_DEFAULT_LANGUAGE]; - pFileHdrRV->uiVersionNum = uiVersionNum = - ((FLMUINT16)(pFileHdrBuf [FLM_VER_POS] - ASCII_ZERO) * 100 + - (FLMUINT16)(pFileHdrBuf [FLM_MINOR_VER_POS] - ASCII_ZERO) * 10 + - (FLMUINT16)(pFileHdrBuf [FLM_SMINOR_VER_POS] - ASCII_ZERO)); - - uiTmpBlkSize = pFileHdrRV->uiBlockSize; - if( !VALID_BLOCK_SIZE( uiTmpBlkSize)) - { - uiTmpBlkSize = flmAdjustBlkSize( pFileHdrRV->uiBlockSize); - } - - // Get other log header elements. - - pFileHdrRV->uiFirstLFHBlkAddr = - (FLMUINT)FB2UD( &pFileHdrBuf [DB_1ST_LFH_ADDR]); - - // See if it is: 1) a WordPerfect file, 2) a FLAIM file, - // and 3) if the block size is valid. - - if( (pPrefixBuf [1] != f_toascii('W')) || - (pPrefixBuf [2] != f_toascii('P')) || - (pPrefixBuf [3] != f_toascii('C')) || - (!VALID_BLOCK_SIZE( pFileHdrRV->uiBlockSize))) - { - rc = RC_SET( FERR_NOT_FLAIM); - goto Exit; - } - - if( pFileHdrBuf [FLAIM_NAME_POS ] != f_toascii( FLAIM_NAME[0]) || - pFileHdrBuf [FLAIM_NAME_POS + 1 ] != f_toascii( FLAIM_NAME[1]) || - pFileHdrBuf [FLAIM_NAME_POS + 2 ] != f_toascii( FLAIM_NAME[2]) || - pFileHdrBuf [FLAIM_NAME_POS + 3 ] != f_toascii( FLAIM_NAME[3]) || - pFileHdrBuf [FLAIM_NAME_POS + 4 ] != f_toascii( FLAIM_NAME[4])) - { - rc = RC_SET( FERR_NOT_FLAIM); - goto Exit; - } - - pFileHdrRV->uiSigBitsInBlkSize = flmGetSigBits( pFileHdrRV->uiBlockSize); - - // Check the FLAIM version number - - if( RC_BAD( rc = flmCheckVersionNum( uiVersionNum))) - { - goto Exit; - } - - f_memcpy( pFileHdrRV->ucFileHdr, pFileHdrBuf, FLM_FILE_HEADER_SIZE); - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: This routine initializes a FILE_HDR structure from the - create options that are passed in. It also initializes the - file header buffer (pFileHdrBuf) that will be written to disk. -*********************************************************************/ -void flmInitFileHdrInfo( - CREATE_OPTS * pCreateOpts, - FILE_HDR_p pFileHdr, - FLMBYTE * pFileHdrBuf - ) -{ - f_memset( pFileHdrBuf, 0, FLM_FILE_HEADER_SIZE); - - // If pCreateOpts is non-NULL, copy it into the file header. - - if (pCreateOpts) - { - pFileHdr->uiBlockSize = pCreateOpts->uiBlockSize; - pFileHdr->uiDefaultLanguage = pCreateOpts->uiDefaultLanguage; - pFileHdr->uiAppMajorVer = pCreateOpts->uiAppMajorVer; - pFileHdr->uiAppMinorVer = pCreateOpts->uiAppMinorVer; - } - else - { - - // If pCreateOpts is NULL, initialize some default values. - - pFileHdr->uiBlockSize = DEFAULT_BLKSIZ; - pFileHdr->uiDefaultLanguage = DEFAULT_LANG; - pFileHdr->uiAppMajorVer = - pFileHdr->uiAppMinorVer = 0; - } - - // Only allow database to be created with current version number - - pFileHdr->uiVersionNum = FLM_CURRENT_VERSION_NUM; - f_memcpy( &pFileHdrBuf [FLM_VER_POS], (FLMBYTE *)FLM_CURRENT_VER_STR, - FLM_VER_LEN); - - // Round block size up to nearest legal block size. - - pFileHdr->uiBlockSize = - flmAdjustBlkSize( pFileHdr->uiBlockSize); - - pFileHdr->uiSigBitsInBlkSize = flmGetSigBits( pFileHdr->uiBlockSize); - f_memcpy( &pFileHdrBuf [FLAIM_NAME_POS], (FLMBYTE *)FLAIM_NAME, - FLAIM_NAME_LEN); - - pFileHdrBuf [DB_DEFAULT_LANGUAGE] = - (FLMBYTE)pFileHdr->uiDefaultLanguage; - UW2FBA( (FLMUINT16)pFileHdr->uiBlockSize, - &pFileHdrBuf [DB_BLOCK_SIZE]); - pFileHdr->uiFirstLFHBlkAddr = FSBlkAddress(1, 0); - UD2FBA( pFileHdr->uiFirstLFHBlkAddr, &pFileHdrBuf [DB_1ST_LFH_ADDR]); - - if (pFileHdr->uiVersionNum < FLM_VER_4_3) - { - - // Things to maintain for backward compatibility - pre 4.3. - - FLMUINT uiFirstPcodeAddr = pFileHdr->uiFirstLFHBlkAddr + - pFileHdr->uiBlockSize; - - UD2FBA( pFileHdr->uiBlockSize, &pFileHdrBuf [DB_INIT_LOG_SEG_ADDR]); - UD2FBA( DB_LOG_HEADER_START, &pFileHdrBuf [DB_LOG_HEADER_ADDR]); - UD2FBA( uiFirstPcodeAddr, &pFileHdrBuf [DB_1ST_PCODE_ADDR]); - } - - f_memcpy( pFileHdr->ucFileHdr, pFileHdrBuf, FLM_FILE_HEADER_SIZE); -} - -/*************************************************************************** -Desc: This routine reads and verifies the information contained in the - file header and log header of a FLAIM database. This routine - is called by both FlmDbOpen and flmGetHdrInfo. -*****************************************************************************/ -RCODE flmReadAndVerifyHdrInfo( - DB_STATS * pDbStats, - F_FileHdl * pFileHdl, - FLMBYTE * pReadBuf, - FILE_HDR_p pFileHdrRV, - LOG_HDR_p pLogHdrRV, - FLMBYTE * pLogHdr) -{ - RCODE rc = FERR_OK; - RCODE rc0; - RCODE rc1; - FLMBYTE * pBuf; - FLMBYTE * pucLogHdr; - FLMUINT uiBytesRead; - FLMUINT uiVersionNum; - - // Read the fixed information area - - f_memset( pReadBuf, 0, 2048); - - rc0 = pFileHdl->Read( 1L, 2047, &pReadBuf [1], &uiBytesRead); - - // Increment bytes read - to account for byte zero, which - // was not really read in. - - uiBytesRead++; - pBuf = pReadBuf; - *pBuf = 0xFF; - - // Before doing any checking, get whatever we can from the - // first 2048 bytes. For the flmGetHdrInfo routine, we want - // to get whatever we can from the headers, even if it is - // invalid. - - rc1 = flmGetFileHdrInfo( pBuf, &pBuf[ FLAIM_HEADER_START], pFileHdrRV); - - // Get the log header information - - pucLogHdr = &pBuf[ DB_LOG_HEADER_START]; - - if( pLogHdr) - { - f_memcpy( pLogHdr, pucLogHdr, LOG_HEADER_SIZE); - } - - flmGetLogHdrInfo( pucLogHdr, pLogHdrRV); - - // Take the version from the log header if non-zero. - // Storing the version in the log header is new to 40 code base. - - uiVersionNum = FB2UW( &pucLogHdr[ LOG_FLAIM_VERSION]); - if( uiVersionNum) - { - pFileHdrRV->uiVersionNum = uiVersionNum; - } - - // If there is not enough data to satisfy the read, this - // is probably not a FLAIM file. - - if( RC_BAD( rc0)) - { - if( rc0 != FERR_IO_END_OF_FILE) - { - if( pDbStats) - { - pDbStats->uiReadErrors++; - } - - rc = rc0; - goto Exit; - } - - if( uiBytesRead < 2048) - { - rc = RC_SET( FERR_NOT_FLAIM); - goto Exit; - } - } - - // See if we got any other errors where we might want to retry - // the read. - - if( RC_BAD( rc1)) - { - rc = rc1; - goto Exit; - } - - // Verify the checksums in the log header - - if( lgHdrCheckSum( pucLogHdr, TRUE) != 0) - { - rc = RC_SET( FERR_BLOCK_CHECKSUM); - goto Exit; - } - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: Write the version number to disk and flush the write to disk. -*****************************************************************************/ -RCODE flmWriteVersionNum( - F_SuperFileHdl_p pSFileHdl, - FLMUINT uiVersionNum) -{ - RCODE rc = FERR_OK; - FLMUINT uiWriteBytes; - FLMBYTE szVersionStr[ 8]; - - if( RC_BAD( rc = flmCheckVersionNum( uiVersionNum))) - { - flmAssert( 0); - goto Exit; - } - - szVersionStr[ 0] = (FLMBYTE)(uiVersionNum / 100) + '0'; - szVersionStr[ 1] = '.'; - szVersionStr[ 2] = (FLMBYTE)((uiVersionNum % 100) / 10) + '0'; - szVersionStr[ 3] = (FLMBYTE)(uiVersionNum % 10) + '0'; - szVersionStr[ 4] = 0; - - if (RC_OK( rc = pSFileHdl->WriteHeader( - FLAIM_HEADER_START + FLM_VER_POS, FLM_VER_LEN, - szVersionStr, &uiWriteBytes))) - { - if (RC_BAD( rc = pSFileHdl->Flush())) - { - goto Exit; - } - } - -Exit: - - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Database header routines. +// Tabs: 3 +// +// Copyright (c) 1995-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: ffilehdr.cpp 12256 2006-01-19 14:37:14 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +/******************************************************************** +Desc: Initializes the file prefix for the .db database file. +*********************************************************************/ +void flmSetFilePrefix( + FLMBYTE * pPrefix, + FLMUINT uiMajorVer, + FLMUINT uiMinorVer) +{ + f_memset( pPrefix, 0, 16); + pPrefix [0] = 0xFF; + pPrefix [1] = f_toascii('W'); + pPrefix [2] = f_toascii('P'); + pPrefix [3] = f_toascii('C'); + + UD2FBA( (FLMUINT32)16, &pPrefix [4]); + + pPrefix [8] = 0xF3; // old product type + pPrefix [9] = 0x01; // old file type + pPrefix [10] = (FLMBYTE)uiMajorVer; + pPrefix [11] = (FLMBYTE)uiMinorVer; + + // Bytes 12 and 13 are the encryption key (not used) + + pPrefix [12] = 0; + pPrefix [13] = 0; + + // Bytes 14 and 15 point are the offset to file specific packets + + pPrefix [14] = 0; + pPrefix [15] = 0; +} + +/******************************************************************** +Desc: This routine adjusts the block size to the nearest valid + block size. +*********************************************************************/ +FLMUINT flmAdjustBlkSize( + FLMUINT uiBlkSize) +{ + FLMUINT uiTmpBlkSize; + + uiTmpBlkSize = MIN_BLOCK_SIZE; + while( (uiBlkSize > uiTmpBlkSize) && (uiTmpBlkSize < MAX_BLOCK_SIZE)) + { + uiTmpBlkSize <<= 1; + } + + return( uiTmpBlkSize); +} + +/*************************************************************************** +Desc: This routine extracts and verifies the information within + the file header. +*****************************************************************************/ +RCODE flmGetFileHdrInfo( + FLMBYTE * pPrefixBuf, + FLMBYTE * pFileHdrBuf, + FILE_HDR * pFileHdrRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiVersionNum; + FLMUINT uiTmpBlkSize; + + // Get the create options + + pFileHdrRV->uiBlockSize = (FLMUINT)FB2UW( &pFileHdrBuf [DB_BLOCK_SIZE]); + pFileHdrRV->uiAppMajorVer = pPrefixBuf [10]; + pFileHdrRV->uiAppMinorVer = pPrefixBuf [11]; + pFileHdrRV->uiDefaultLanguage = pFileHdrBuf [DB_DEFAULT_LANGUAGE]; + pFileHdrRV->uiVersionNum = uiVersionNum = + ((FLMUINT16)(pFileHdrBuf [FLM_FILE_FORMAT_VER_POS] - ASCII_ZERO) * 100 + + (FLMUINT16)(pFileHdrBuf [FLM_MINOR_VER_POS] - ASCII_ZERO) * 10 + + (FLMUINT16)(pFileHdrBuf [FLM_SMINOR_VER_POS] - ASCII_ZERO)); + + uiTmpBlkSize = pFileHdrRV->uiBlockSize; + if( !VALID_BLOCK_SIZE( uiTmpBlkSize)) + { + uiTmpBlkSize = flmAdjustBlkSize( pFileHdrRV->uiBlockSize); + } + + // Get other log header elements. + + pFileHdrRV->uiFirstLFHBlkAddr = + (FLMUINT)FB2UD( &pFileHdrBuf [DB_1ST_LFH_ADDR]); + + // See if this looks like a valid database + + if( (pPrefixBuf [1] != f_toascii('W')) || + (pPrefixBuf [2] != f_toascii('P')) || + (pPrefixBuf [3] != f_toascii('C')) || + (!VALID_BLOCK_SIZE( pFileHdrRV->uiBlockSize))) + { + rc = RC_SET( FERR_NOT_FLAIM); + goto Exit; + } + + if( pFileHdrBuf [FLAIM_NAME_POS ] != f_toascii( FLAIM_NAME[0]) || + pFileHdrBuf [FLAIM_NAME_POS + 1 ] != f_toascii( FLAIM_NAME[1]) || + pFileHdrBuf [FLAIM_NAME_POS + 2 ] != f_toascii( FLAIM_NAME[2]) || + pFileHdrBuf [FLAIM_NAME_POS + 3 ] != f_toascii( FLAIM_NAME[3]) || + pFileHdrBuf [FLAIM_NAME_POS + 4 ] != f_toascii( FLAIM_NAME[4])) + { + rc = RC_SET( FERR_NOT_FLAIM); + goto Exit; + } + + pFileHdrRV->uiSigBitsInBlkSize = flmGetSigBits( pFileHdrRV->uiBlockSize); + + // Check the FLAIM version number + + if( RC_BAD( rc = flmCheckVersionNum( uiVersionNum))) + { + goto Exit; + } + + f_memcpy( pFileHdrRV->ucFileHdr, pFileHdrBuf, FLM_FILE_HEADER_SIZE); + +Exit: + + return( rc); +} + +/******************************************************************** +Desc: This routine initializes a FILE_HDR structure from the + create options that are passed in. It also initializes the + file header buffer (pFileHdrBuf) that will be written to disk. +*********************************************************************/ +void flmInitFileHdrInfo( + CREATE_OPTS * pCreateOpts, + FILE_HDR * pFileHdr, + FLMBYTE * pFileHdrBuf) +{ + f_memset( pFileHdrBuf, 0, FLM_FILE_HEADER_SIZE); + + // If pCreateOpts is non-NULL, copy it into the file header. + + if (pCreateOpts) + { + pFileHdr->uiBlockSize = pCreateOpts->uiBlockSize; + pFileHdr->uiDefaultLanguage = pCreateOpts->uiDefaultLanguage; + pFileHdr->uiAppMajorVer = pCreateOpts->uiAppMajorVer; + pFileHdr->uiAppMinorVer = pCreateOpts->uiAppMinorVer; + } + else + { + + // If pCreateOpts is NULL, initialize some default values. + + pFileHdr->uiBlockSize = DEFAULT_BLKSIZ; + pFileHdr->uiDefaultLanguage = DEFAULT_LANG; + pFileHdr->uiAppMajorVer = + pFileHdr->uiAppMinorVer = 0; + } + + // Only allow database to be created with current version number + + pFileHdr->uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM; + f_memcpy( &pFileHdrBuf [FLM_FILE_FORMAT_VER_POS], + (FLMBYTE *)FLM_CUR_FILE_FORMAT_VER_STR, + FLM_FILE_FORMAT_VER_LEN); + + // Round block size up to nearest legal block size. + + pFileHdr->uiBlockSize = + flmAdjustBlkSize( pFileHdr->uiBlockSize); + + pFileHdr->uiSigBitsInBlkSize = flmGetSigBits( pFileHdr->uiBlockSize); + f_memcpy( &pFileHdrBuf [FLAIM_NAME_POS], (FLMBYTE *)FLAIM_NAME, + FLAIM_NAME_LEN); + + pFileHdrBuf [DB_DEFAULT_LANGUAGE] = + (FLMBYTE)pFileHdr->uiDefaultLanguage; + UW2FBA( (FLMUINT16)pFileHdr->uiBlockSize, + &pFileHdrBuf [DB_BLOCK_SIZE]); + pFileHdr->uiFirstLFHBlkAddr = FSBlkAddress(1, 0); + UD2FBA( pFileHdr->uiFirstLFHBlkAddr, &pFileHdrBuf [DB_1ST_LFH_ADDR]); + + if (pFileHdr->uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + + // Things to maintain for backward compatibility - pre 4.3. + + FLMUINT uiFirstPcodeAddr = pFileHdr->uiFirstLFHBlkAddr + + pFileHdr->uiBlockSize; + + UD2FBA( pFileHdr->uiBlockSize, &pFileHdrBuf [DB_INIT_LOG_SEG_ADDR]); + UD2FBA( DB_LOG_HEADER_START, &pFileHdrBuf [DB_LOG_HEADER_ADDR]); + UD2FBA( uiFirstPcodeAddr, &pFileHdrBuf [DB_1ST_PCODE_ADDR]); + } + + f_memcpy( pFileHdr->ucFileHdr, pFileHdrBuf, FLM_FILE_HEADER_SIZE); +} + +/*************************************************************************** +Desc: This routine reads and verifies the information contained in the + file header and log header of a FLAIM database. This routine + is called by both FlmDbOpen and flmGetHdrInfo. +*****************************************************************************/ +RCODE flmReadAndVerifyHdrInfo( + DB_STATS * pDbStats, + F_FileHdl * pFileHdl, + FLMBYTE * pReadBuf, + FILE_HDR * pFileHdrRV, + LOG_HDR * pLogHdrRV, + FLMBYTE * pLogHdr) +{ + RCODE rc = FERR_OK; + RCODE rc0; + RCODE rc1; + FLMBYTE * pBuf; + FLMBYTE * pucLogHdr; + FLMUINT uiBytesRead; + FLMUINT uiVersionNum; + + // Read the fixed information area + + f_memset( pReadBuf, 0, 2048); + + rc0 = pFileHdl->Read( 1L, 2047, &pReadBuf [1], &uiBytesRead); + + // Increment bytes read - to account for byte zero, which + // was not really read in. + + uiBytesRead++; + pBuf = pReadBuf; + *pBuf = 0xFF; + + // Before doing any checking, get whatever we can from the + // first 2048 bytes. For the flmGetHdrInfo routine, we want + // to get whatever we can from the headers, even if it is + // invalid. + + rc1 = flmGetFileHdrInfo( pBuf, &pBuf[ FLAIM_HEADER_START], pFileHdrRV); + + // Get the log header information + + pucLogHdr = &pBuf[ DB_LOG_HEADER_START]; + + if( pLogHdr) + { + f_memcpy( pLogHdr, pucLogHdr, LOG_HEADER_SIZE); + } + + if( pLogHdrRV) + { + flmGetLogHdrInfo( pucLogHdr, pLogHdrRV); + } + + // Take the version from the log header if non-zero. + // Storing the version in the log header is new to 40 code base. + + uiVersionNum = FB2UW( &pucLogHdr[ LOG_FLAIM_VERSION]); + if( uiVersionNum) + { + pFileHdrRV->uiVersionNum = uiVersionNum; + } + + // If there is not enough data to satisfy the read, this + // is probably not a FLAIM file. + + if( RC_BAD( rc0)) + { + if( rc0 != FERR_IO_END_OF_FILE) + { + if( pDbStats) + { + pDbStats->uiReadErrors++; + } + + rc = rc0; + goto Exit; + } + + if( uiBytesRead < 2048) + { + rc = RC_SET( FERR_NOT_FLAIM); + goto Exit; + } + } + + // See if we got any other errors where we might want to retry + // the read. + + if( RC_BAD( rc1)) + { + rc = rc1; + goto Exit; + } + + // Verify the checksums in the log header + + if( lgHdrCheckSum( pucLogHdr, TRUE) != 0) + { + rc = RC_SET( FERR_BLOCK_CHECKSUM); + goto Exit; + } + +Exit: + + return( rc); +} + +/*************************************************************************** +Desc: Write the version number to disk and flush the write to disk. +*****************************************************************************/ +RCODE flmWriteVersionNum( + F_SuperFileHdl * pSFileHdl, + FLMUINT uiVersionNum) +{ + RCODE rc = FERR_OK; + FLMUINT uiWriteBytes; + FLMBYTE szVersionStr[ 8]; + + if( RC_BAD( rc = flmCheckVersionNum( uiVersionNum))) + { + flmAssert( 0); + goto Exit; + } + + szVersionStr[ 0] = (FLMBYTE)(uiVersionNum / 100) + '0'; + szVersionStr[ 1] = '.'; + szVersionStr[ 2] = (FLMBYTE)((uiVersionNum % 100) / 10) + '0'; + szVersionStr[ 3] = (FLMBYTE)(uiVersionNum % 10) + '0'; + szVersionStr[ 4] = 0; + + if (RC_OK( rc = pSFileHdl->WriteHeader( + FLAIM_HEADER_START + FLM_FILE_FORMAT_VER_POS, + FLM_FILE_FORMAT_VER_LEN, + szVersionStr, &uiWriteBytes))) + { + if (RC_BAD( rc = pSFileHdl->Flush())) + { + goto Exit; + } + } + +Exit: + + return( rc); +} + +/*************************************************************************** +Desc: This routine reads the header information in a FLAIM database, + verifies the password, and returns the file header and log + header information. +*****************************************************************************/ +RCODE flmGetHdrInfo( + F_SuperFileHdl * pSFileHdl, /* Pointer to file handle. */ + FILE_HDR * pFileHdrRV, /* Returns file header information. */ + LOG_HDR * pLogHdrRV, /* Returns log header information. */ + FLMBYTE * pLogHdr + ) +{ + RCODE rc = FERR_OK; + FLMBYTE * pBuf = NULL; + F_FileHdlImp * pCFileHdl; + + if (RC_BAD( rc = f_alloc( 2048, &pBuf))) + { + goto Exit; + } + + if( RC_BAD( rc = pSFileHdl->GetFileHdl( 0, FALSE, &pCFileHdl))) + { + goto Exit; + } + + rc = flmReadAndVerifyHdrInfo( NULL, pCFileHdl, + pBuf, pFileHdrRV, pLogHdrRV, pLogHdr); + +Exit: + + if( pBuf) + { + f_free( &pBuf); + } + + return( rc); +} diff --git a/flaim/src/filesys.h b/flaim/src/filesys.h index 47856ab..cbe982e 100644 --- a/flaim/src/filesys.h +++ b/flaim/src/filesys.h @@ -1,1506 +1,1547 @@ -//------------------------------------------------------------------------- -// Desc: Definitions for internal database structure. -// Tabs: 3 -// -// Copyright (c) 1990-1993,1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: filesys.h 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#ifndef FILESYS_H -#define FILESYS_H - -#include "flaimsys.h" - -#include "fpackon.h" -// IMPORTANT NOTE: No other include files should follow this one except -// for fpackoff.h - -/** -*** B-tree ELEMENT Definitions -*** -*** Portable element definitions are the basic unit of storage within -*** any b-tree block. The new format has changed to support longer -*** keys up to 1023 bytes long. -*** -*** KEY: -*** BBE - B-tree Block Element -*** BNE - B-tree Non-leaf element -*** BUE - B-tree Unknown Element - don't know if leaf or non-leaf -*** -*** CONT - the element 'does' continue to the next element -*** DOMAIN- for the new reference set organization in non-leaf blks -*** PKC - number of bytes used in the previous key (PKC) -*** KL - key Length - # of bytes to represent the right most key info -*** RL - number of bytes in the record portion of the element -*** KEY - starts the key bounded by KEY_LEN -*** CHILD_BLK - Three byte address of the childs block (non-leaf elms) -*** -*** LEAF ELEMENT FORMAT -**/ - - /* BYTE 0 - BITS 0,1 - First and last element markers */ - - #define BBE_FIRST_FLAG 0x80 /* First element in a list */ - #define BBE_LAST_FLAG 0x40 /* Last element in a list */ - - #define BBE_IS_FIRST(elm) ((*(elm)) & BBE_FIRST_FLAG ) - #define BBE_NOT_FIRST(elm) (!((*(elm)) & BBE_FIRST_FLAG )) - #define BBE_SET_FIRST(elm) ((*(elm)) |= BBE_FIRST_FLAG) - #define BBE_CLR_FIRST(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_FIRST_FLAG))) - - #define BBE_IS_LAST(elm) ((*(elm)) & BBE_LAST_FLAG ) - #define BBE_NOT_LAST(elm) (!((*(elm)) & BBE_LAST_FLAG )) - #define BBE_SET_LAST(elm) ((*(elm)) |= (FLMBYTE)(BBE_LAST_FLAG)) - #define BBE_CLR_LAST(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_LAST_FLAG))) - - #define BBE_IS_FIRST_LAST(e) ((*(e)) & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) - - #define BBE_MIDDLE_FLAG (BBE_FIRST_FLAG|BBE_LAST_FLAG) - #define BBE_IS_MIDDLE(elm) (!((*(elm)) & (BBE_MIDDLE_FLAG))) - #define BBE_SET_MIDDLE(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_MIDDLE_FLAG))) - - /* BYTE 0 - BITS 2,3 - Key Length High Bits */ - - #define BBE_KL_HBITS 0x30 /* High bits for key length */ - - /* BYTE 0 - BITS 4,5,6,7 - Previous Key Count - [0..15] */ - - #define BBE_PKC 0 - #define BBE_PKC_MAX 0x0F - - /* BBE_SET_PKC should clear out all other values */ - - #define BBE_SET_PKC(elm,val) ((*(elm)) = (FLMBYTE)(BBE_PKC_MAX & (val))) - #define BBE_CHK_PKC(val) (((val) <= BBE_PKC_MAX) ? val : BBE_PKC_MAX) - #define BBE_GET_PKC(elm) ((*(elm)) & BBE_PKC_MAX) - #define BBE_GETR_PKC(elm) (*(elm) & 0x3F) /* Get raw value with KL_HBITS */ - - /* BYTE 1 - Key Length */ - - #define BBE_KL 1 - /* RAW MODE - used for fast value grabs */ - #define BBE_SETR_KL(elm,val) ((elm)[BBE_KL] = (val)) - #define BBE_KL_SHIFT_BITS 4 - - #define BBE_SET_KL(elm,val) \ - { \ - if( (val) > 0xFF) \ - *(elm) |= (FLMBYTE)(((val) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS); \ - (elm)[BBE_KL] = (FLMBYTE) (val); \ - } - - /* RAW MODE */ - #define BBE_GETR_KL(elm) ((elm)[BBE_KL]) - #define BBE_GET_KL(elm) (((*(elm) & BBE_KL_HBITS) << BBE_KL_SHIFT_BITS) + \ - (elm)[BBE_KL]) - - /* BYTE 2 - Record Length */ - - #define BBE_RL 2 - #define BBE_SET_RL(elm,val) (((elm)[BBE_RL]) = (FLMBYTE)(val)) - #define BBE_GET_RL(elm) ( (elm)[BBE_RL]) - - /* BYTE 3 - KEY */ - - #define BBE_KEY 3 - - /* #define BBE_LEM_LEN 3 - defined in filesys.h */ - - /** - *** Non-leaf element format - **/ - - /* BYTE 0 - BIT 0 - DOMAIN FLAG */ - - #define BNE_DOMAIN 0x80 - #define BNE_IS_DOMAIN(elm) ((*(elm)) & BNE_DOMAIN) - #define BNE_SET_DOMAIN(elm) ((*(elm)) |= BNE_DOMAIN) - #define BNE_CLR_DOMAIN(elm) ((*(elm)) = *(elm) & (~(BNE_DOMAIN))) - #define BNE_DOMAIN_LEN 3 - - /* BYTE 0 - BITS 1,2 */ - - /* Use BBE_KL_HBITS codes */ - - /* BYTE 0 - Bits 3,4,5,6,7 */ - - /* Use BBE_xxx_PKC macros */ - - /* BYTE 1 */ - - /* Use BBE_xxx_KL macros */ - - /* BYTES 2-5 - CHILD BLOCK ADDRESS - 4 byte number */ - - #define BNE_CHILD_BLOCK 2 - #define BNE_CHILD_COUNT 6 - - /* BYTE 6 or 10 - Start of Key */ - #define BNE_KEY_START 6 - #define BNE_KEY_COUNTS_START 10 - - #define BNE_DATA_CHILD_BLOCK 4 - #define BNE_DATA_OVHD 8 - - - /* The domain value in 3-byte high-low format will follow the key */ - -/************************************************* -*** -*** GENERAL MANIPULATION MACROS -*** -*** LEN - Length of element -*** REC_OFS - Offset into the record portion (skip the key) -*** REC_PTR - Address of where record portion starts -*** KEY_OFS - Offset into where the key starts -*** -**************************************************/ - - /** - *** Compute the complete length of a leaf and non-leaf element - **/ - - #define BBE_LEN(elm) (BBE_GET_RL(elm) + BBE_GET_KL(elm) + BBE_KEY) - - #define BNE_LEN(stack,elm) (BBE_GET_KL(elm) + stack->uiElmOvhd + \ - (BNE_IS_DOMAIN(elm) ? BNE_DOMAIN_LEN : 0)) - - #define BBE_REC_OFS(elm) (BBE_GET_KL(elm) + BBE_KEY) - - #define BBE_REC_PTR(elm) (&(elm)[ BBE_REC_OFS(elm) ] ) - - - -/** -*** Record OPCODE's used in the storage of data record field values. -*** All opcodes are prefixed by FOP which is Field OPcode. -*** l = bits used to represent the storage length of the field value -*** ab = bit flags for number of bytes for TAG_NUM and LENGTH -*** ffff = 4 bits are used for the field type (0..15) -*** vvv = value of levels to shift out to (0..7) -*** c = The context flag - 0 is sibling - 1 is child -*** z = bits used for a compressed tNum (field number) -*** VALUE = value portion of the field -*** x = future large field (over 64K) flag -*** i = ID is 2 bytes (0) or 4 bytes long -*** o = Local field number - Version 1.2 -**/ - - #define FOP_STANDARD 0 /* Use 1 left bit 0cll llll - zzzz zzzz - VALUE */ - #define FOP_IS_STANDARD(p) (! (*(p) & 0x80) ) - #define FSTA_MAX_FLD_NUM 0xFF - #define FSTA_MAX_FLD_LEN 0x3F /* 63 */ - #define FSTA_LEVEL(p) ((*p) & 0x40) - #define FSTA_FLD_LEN(p) ((*p) & 0x3F) - #define FSTA_FLD_NUM(p) (*(p+1)) - #define FSTA_OVHD 2 - - #define FOP_GET_FLD_FLAGS(p) ((*p) & 0x07) - #define FOP_2BYTE_FLDNUM(bv) ((bv) & 0x02) - #define FOP_2BYTE_FLDLEN(bv) ((bv) & 0x01) - #define FOP_LOCAL_FLDNUM(bv) ((bv) & 0x04) - - - #define FOP_TAGGED 0x80 /* Use 4 left bits 1000 coab - 0000 ffff - tNum | LENGTH | VALUE*/ - #define FOP_IS_TAGGED(p) ((*(p) & 0xF0) == FOP_TAGGED) - #define FTAG_LEVEL(p) ((*p) & 0x08) - #define FTAG_FLD_TYPE(p) ((*(p+1)) & 0x0F) - #define FTAG_OVHD 2 - #define FTAG_LOCAL_FLAG 0x04 - - #define FOP_OPEN 0x90 /* Use 4 left bits 1001 cxab - tNum | LENGTH | VALUE*/ - #define FOP_IS_OPEN(p) ((*(p) & 0xF0) == FOP_OPEN) - #define FOPE_LEVEL(p) ((*p) & 0x08) - - - #define FOP_SET_LEVEL 0xA0 /* Use 5 left bits 1010 0vvv */ - #define FOP_IS_SET_LEVEL(p) ((*(p) & 0xF8) == FOP_SET_LEVEL) - #define FOP_LEVEL_MAX 0x07 - #define FSLEV_GET(p) (*(p) & FOP_LEVEL_MAX) - - - #define FOP_NO_VALUE 0xA8 /* Use 5 left bits 1010 1ca0 - a = 0 FLD_NUM=1 byte - a = 1 FLD_NUM=2 byte */ - #define FOP_IS_NO_VALUE(p) ((*(p) & 0xF8) == FOP_NO_VALUE) - #define FNOV_LEVEL(p) ((*p) & 0x04) - #define FNOV_OVHD 2 - - #define FOP_RECORD_INFO 0xB0 /* Use 7 bits 1011 000b - LENGTH (1 or 2 bytes) - VALUE */ - #define FOP_IS_RECORD_INFO(p) ((*(p) & 0xFE) == FOP_RECORD_INFO) - - #define FOP_ENCRYPTED 0xE0 /* Use 7 left bits 1110 000c - ffff abab - tNum | LENGTH | eNum | eLENGTH | eVALUE */ - #define FOP_IS_ENCRYPTED(p) ((*(p) & 0xFE) == FOP_ENCRYPTED) - #define FENC_LEVEL(p) ((*p) & 0x01) - #define FENC_FLD_TYPE(p) (((*(p+1)) & 0xF0) >> 4) - #define FENC_TAG_SZ(p) (((*(p+1)) & 0x08) >> 3) - #define FENC_LEN_SZ(p) (((*(p+1)) & 0x04) >> 2) - #define FENC_ETAG_SZ(p) (((*(p+1)) & 0x02) >> 1) - #define FENC_ELEN_SZ(p) ((*(p+1)) & 0x01) - - #define DIN_KEY_SIZ 4 - #define ELM_DIN_OVHD (BBE_KEY+DIN_KEY_SIZ)/* Database record overhead */ - - #define MAX_REC_ELM 250 /* Max length of record portion */ - #define MAX_FLD_OVHD 10 /* Max field overhead + 2 to spare */ - /* Supports up to 64K fields*/ - -/* -*** SEN - Simple Encoded Number -*** -*** This is the variable length numbering system that can store -*** up to a 36 bit number in 1 to 5 bytes. -*** The SEN is the backbone to the index reference list compression -*** and the standard format for other functions that need to represent -*** a number in a variable number of bytes. -*/ - - #define SEN_1B_CODE 0x00 /* SEN 1 byte code */ - #define SEN_1B_VAL 127 /* Max 1 byte value - 7 bits */ - - #define SEN_2B_CODE 0x80 /* SEN 2 byte code */ - #define SEN_2B_CMSK 0xC0 /* Mask to check for code */ - #define SEN_2B_VAL 16383 /* Max 2 byte value - 14 bits */ - #define SEN_2B_MASK 0x3F - - #define SEN_3B_CODE 0xC0 /* SEN 3 byte code */ - #define SEN_3B_CMSK 0xF0 /* Mask to check for code */ - #define SEN_3B_VAL 1048575 /* Max 3 byte value - 20 bits */ - #define SEN_3B_MASK 0x0F - - #define SEN_4B_CODE 0xD0 /* SEN 4 byte code */ - #define SEN_4B_CMSK 0xF0 /* Mask to check for code */ - #define SEN_4B_VAL 268435455 /* Max 4 byte value - 28 bits */ - #define SEN_4B_MASK 0x0F - - #define SEN_5B_CODE 0xE0 /* SEN 5 byte code */ - #define SEN_5B_CMSK 0xF0 /* Mask to check for code */ - #define SEN_5B_MASK 0x0F - - #define SEN_FLAG 0xF0 /* Flag that contains some meaning */ - - #define SEN_MAX_SIZ 7 /* A -2,000,000,000 is biggest SEN */ - - #define SEN_DOMAIN 0xFC /* A domain in SEN format follows */ - #define SEN_UPDATE_VER 0xFD /* Future */ - - -/** -*** DIN - Dual Integer Numbers -**/ - - #define DIN_ONE_RUN_LV 0xF0 /* Lowest value for one runs */ - - #define DIN_MAX_1B_ONE_RUN 9 /* Maximum one byte one run value */ - - #define DIN_ONE_RUN_HV 0xF8 /* High value for one runs */ - - - #define DIN_IS_ONE_RUN(b) (((b)==1) || \ - (((b) >= DIN_ONE_RUN_LV) && ((b) <= DIN_ONE_RUN_HV))) - - #define DIN_IS_REAL_ONE_RUN(b) \ - (((b) >= DIN_ONE_RUN_LV) && ((b) <= DIN_ONE_RUN_HV)) - -/* -*** Reference Set Definitions -*** -*/ - -/** -*** The reference set maximums are computed from the most bytes that -*** contain the maximum number of items that can exist within a -*** single domain. -*** The REF_SET_MAX_SIZ must contain more than one domain or the -*** set compression is not working as designed. -*** The minimum value of REF_SET_MAX_SIZ should >= 180. The worst pattern -*** is 02 01 02 01 02 01 = total must be > 256. 170 references + overhead -*** -*** REF_SET_FIRST_MAX is not used at this point. -**/ - - #define REF_SET_MAX_SIZ 180 /* 170 references + extra stuff */ - #define REF_SPLIT_50_50 50 /* Be really conservative */ - #define REF_SPLIT_90_10 0 /* Split at first break */ - - #define SPLIT_90_10 0 - #define SPLIT_50_50 1 - - - -/*************************************************************** -** -** Defined Constants that the File system cares about -** -****************************************************************/ - - // B-tree chain end indicator - - #define BT_END ((FLMUINT)0xFFFFFFFFL) - - // Domains are used for direct access to the index reference sets - - #define DIN_DOMAIN(din) ((din) >> 8) - #define DRN_DOMAIN(drn) ((drn) >> 8) - #define ZERO_DOMAIN ((FLMUINT) 0) - #define MAX_DOMAIN ((FLMUINT) 0x1000000) - - /* - *** - *** B-tree Block Scan Return Codes - *** In bsStatus - */ - - #define BT_EQ_KEY 0 /* Keys are equal */ - #define BT_GT_KEY 1 /* Key is greater than */ - /* Less than should loop until greater*/ - #define BT_LT_KEY 2 /* Not equal - cursor information */ - #define BT_END_OF_DATA 0xFFFF /* Hit the end of the data */ - - #define DRN_LAST_MARKER ((FLMUINT) 0xFFFFFFFF) - #define DRN_LAST_MARKER_LEN 11 - -/**----------------------------------------------------------------------- -*** Block Header Layout -*** Add new block types here. Can support up to 16 different block -*** types at this time. In the future the middle 2 bits of the BH_TYPE -*** will represent a code for the current block size for variable blocks. -***----------------------------------------------------------------------*/ - - #define BH_CHECKSUM_LOW 0 /* Low order bits of checksum. */ - /* Ver 3.0 low byte of blk address used - in the checksum value. */ - #define BH_ADDR 0 /* Block address */ - #define BH_PREV_BLK 4 /* Previous block in the chain */ - - #define BH_NEXT_BLK 8 /* Next block in the chain */ - #define BACKCHAIN_CNT 36 /* Number of chains in a back chain */ - - #define BH_TYPE 12 /* Block type - defined below */ - #define BHT_FREE 0 // Free block - avail list - #define BHT_LEAF 1 // Leaf block - #define BHT_LFH_BLK 4 // LFH Header block - #define BHT_PCODE_BLK 5 // PCODE block - #define BHT_NON_LEAF 6 // Non-leaf block - variable key size - #define BHT_NON_LEAF_DATA 7 // Non-leaf block data block - fixed key size - #define BHT_NON_LEAF_COUNTS 8 // Non-leaf index with counts - - #define BHT_BI_BLK 0x30 - // These bits get ORed in to type if the - // block is a Before Image block that - // should be restored on transaction - // abort. This is only set when a block - // is written to the log, so it only - // needs to be unset when the block is - // read back from the log. - - #define BH_GET_TYPE(blk) \ - (((blk)[BH_TYPE]) & 0x0F ) - - #define BH_SET_BI(blk) \ - (((blk)[BH_TYPE]) |= BHT_BI_BLK) - - #define BH_UNSET_BI(blk) \ - (((blk)[BH_TYPE]) &= (~(BHT_BI_BLK))) - - #define BH_IS_BI(blk) \ - ((((blk)[BH_TYPE]) & BHT_BI_BLK) == BHT_BI_BLK) - - #define BHT_ROOT_BLK 0x80 - - #define BH_IS_ROOT_BLK(blk) \ - (((blk)[BH_TYPE]) & BHT_ROOT_BLK) - - #define BH_SET_ROOT_BLK(blk) \ - ((blk)[BH_TYPE] |= BHT_ROOT_BLK) - -/**---------------------------------------------------------------------- -*** The maximum levels in any b-tree be 8 levels with version 3.x. -*** We will not worry about 2x compatibility problems until we understand -*** what needs to be done on the 2x to 30 conversion. -*** Very long keys in index records (500-1000 bytes) could easily run -*** out of 8 levels, but this is very unlikely at this time. -***----------------------------------------------------------------------*/ - - #define BH_LEVEL 13 /* Block level (B-tree only) */ - - #define BH_MAX_LEVELS 8 /* Max allowable b-tree levels */ - #define MAX_LEVELS BH_MAX_LEVELS - - #define BH_ELM_END 14 /* End of the elements in a block */ - #define BH_BLK_END 14 /* End of the elements in a block */ - - #define BH_TRANS_ID 16 /* Last transaction to update this block */ - #define BH_PREV_TRANS_ID 20 /* Previous transaction to update block */ - #define BH_PREV_BLK_ADDR 24 /* Pointer to previous image of blk */ - #define BH_LOG_FILE_NUM 28 /* Logical file number of block */ - #define BH_ENCRYPTED 30 /* Flag indicating if block is encrypted */ - #define BH_CHECKSUM_HIGH 31 /* High order bits of checksum */ - - #define BH_OVHD 32 /* Overhead in the block header */ - /* NOTE: BH_OVHD MUST ALWAYS BE A MULTIPLE OF 4 FOR ENCRYPTION TO WORK PROPERLY */ - - /* Avail List definitions */ - #define BH_NEXT_BACKCHAIN 4 /* Backchains of avail list - 4 bytes */ - #define BH_PREV_BACKCHAIN0 30 /* Avail blocks as of version 3 not encrypted */ - #define BH_PREV_BACKCHAIN1 13 /* Prev backchain contains 3 bytes */ - #define BH_PREV_BACKCHAIN2 28 /* at different locations in the header */ - #define BH_PREV_BACKCHAIN3 29 /* Level and logical file num are used */ - - - #define BBE_LEM_LEN 3 /* Length of leaf last element marker*/ - /* Should be using stack->bsElmOvhd instead */ - - -/**----------------------------------- -*** GENERAL STACK/BLOCK HEADER MACROS -***----------------------------------*/ - - #define GET_BH_ADDR( pBlk) \ - (FB2UD(&(pBlk)[BH_ADDR])) - - #define SET_BH_ADDR( pBlk, dwAddr) \ - UD2FBA( dwAddr, &(pBlk)[BH_ADDR] ) - - /* Block access from the cache pointer */ - - #define GET_CABLKPTR(stack) \ - ((stack)->pSCache->pucBlk) - - #define CABLK_ELM(stack,elm) \ - ((stack)->pSCache->pucBlk[ (elm) ]) - - /* Block access from the pBlk */ - - #define SET_BLKPTR(stack) \ - ((stack)->pBlk = stack->pSCache->pucBlk) - - #define BLK_PTR(stack) \ - ((stack)->pBlk) - - #define BLK_ELM(stack,elm) \ - ((stack)->pBlk[ (elm) ]) - - #define BLK_ELM_ADDR(stack,elm) \ - (&((stack)->pBlk[ (elm) ])) - - #define CURRENT_ELM(stack) \ - (&((stack)->pBlk[ stack->uiCurElm ])) - - FINLINE void flmCopyDrnKey( - FLMBYTE * pucDest, - FLMBYTE * pucSrc) - { -#ifdef FLM_UNIX - f_memcpy( pucDest, pucSrc, sizeof( FLMUINT32)); -#else - *((FLMUINT32 *)pucDest) = *((FLMUINT32 *)pucSrc); -#endif - } - - /* - *** Resolving the block address into components. - */ - - #define MAX_DATA_FILE_NUM_VER40 0x1FF - #define MAX_LOG_FILE_NUM_VER40 0x3FF - #define MAX_DATA_FILE_NUM_VER43 0x7FF - #define MAX_LOG_FILE_NUM_VER43 0xFFF - - #define MAX_DATA_BLOCK_FILE_NUMBER(uiDbVersion) \ - (FLMUINT)(((uiDbVersion) >= FLM_VER_4_3) \ - ? MAX_DATA_FILE_NUM_VER43 \ - : MAX_DATA_FILE_NUM_VER40) - - #define FIRST_LOG_BLOCK_FILE_NUMBER(uiDbVersion) \ - (FLMUINT)(MAX_DATA_BLOCK_FILE_NUMBER(uiDbVersion) + 1) - - #define MAX_LOG_BLOCK_FILE_NUMBER(uiDbVersion) \ - (FLMUINT)(((uiDbVersion) >= FLM_VER_4_3) \ - ? MAX_LOG_FILE_NUM_VER43 \ - : MAX_LOG_FILE_NUM_VER40) - - #define FSGetFileNumber( uiBlkAddr) \ - ((uiBlkAddr) & MAX_LOG_FILE_NUM_VER43) - - #define FSGetFileOffset( udBlkAddr) \ - ((udBlkAddr) & 0xFFFFF000) - - #define FSBlkAddress( iFileNum, udFileOfs) \ - ((udFileOfs) + (iFileNum)) - - // Max file size and log threshold. - - #define MAX_FILE_SIZE_VER40 ((FLMUINT)0x7FF00000) - #define LOG_THRESHOLD_SIZE ((FLMUINT) 0x40000) - - FINLINE FLMUINT flmGetMaxFileSize( - FLMUINT uiDbVersion, - FLMBYTE * pucLogHdr) - { - FLMUINT uiMaxSize = MAX_FILE_SIZE_VER40; - - if( uiDbVersion >= FLM_VER_4_3) - { - uiMaxSize = ((FLMUINT)FB2UW( &pucLogHdr[ LOG_MAX_FILE_SIZE])) << 16; - if( !uiMaxSize) - { - uiMaxSize = MAX_FILE_SIZE_VER40; - } - } - - return( uiMaxSize); - } - - // Very large threshhold is the size we will allow the physical - // log to grow to before we force a truncation. At the low end, - // it is about 10 megabytes. At the high end it is about - // 1 gigabyte. - - #define LOW_VERY_LARGE_LOG_THRESHOLD_SIZE ((FLMUINT)0xA00000) - #define HIGH_VERY_LARGE_LOG_THRESHOLD_SIZE ((FLMUINT) 0x40000000) - - // RFL_TRUNCATE_SIZE is the size we will let an RFL file grow to - // before we truncate it back. RFL files are only truncated if - // we are configured to delete old RFL files. - - #define RFL_TRUNCATE_SIZE ((FLMUINT)1024 * (FLMUINT)1024 * (FLMUINT)10) - -/**************************************************************************** - Shared Cache Routines -****************************************************************************/ - -void ScaCleanupCache( - FLMUINT uiMaxLockTime); - -void ScaFreeModifiedBlocks( - FDB_p pDb); - -FLMBOOL flmNeededByReadTrans( - FFILE * pFile, - FLMUINT uiLowTransId, - FLMUINT uiHighTransId); - -void ScaReleaseLogBlocks( - FFILE_p pFile); - -RCODE ScaGetBlock( - FDB_p pDb, - LFILE * pLFile, - FLMUINT uiBlkType, - FLMUINT uiBlkAddress, - FLMUINT * puiNumLooksRV, - SCACHE ** ppSCacheRV); - -RCODE ScaCreateBlock( - FDB_p pDb, - LFILE * pLFile, - SCACHE ** ppSCacheRV); - -void ScaHoldCache( - SCACHE * pSCache); - -void ScaReleaseCache( - SCACHE * pSCache, - FLMBOOL bMutexAlreadyLocked); - -RCODE ScaLogPhysBlk( - FDB_p pDb, - SCACHE ** ppSCacheRV); - -RCODE ScaInit( - FLMUINT uiMaxSharedCache); - -RCODE ScaConfig( - FLMUINT uiType, - void * pvValue1, - void * pvValue2); - -void ScaExit( void); - -void ScaFreeFileCache( - FFILE_p pFile); - -RCODE ScaDoCheckpoint( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMBOOL bDoTruncate, - FLMBOOL bForceCheckpoint, - FLMINT iForceReason, - FLMUINT uiCPFileNum, - FLMUINT uiCPOffset); - -RCODE ScaEncryptBlock( - FFILE * pFile, - FLMBYTE * pucBuffer, - FLMUINT uiBufLen, - FLMUINT uiBlockSize); - -RCODE ScaDecryptBlock( - FFILE * pFile, - FLMBYTE * pucBuffer); - -FLMUINT64 FSGetSizeInBytes( - FLMUINT uiMaxFileSize, - FLMUINT uiBlkAddress); - -RCODE FSGetBlock( - FDB_p pDb, - LFILE * pLFile, - FLMUINT uiBlkAddress, - BTSK_p pStack); - -void FSReleaseStackCache( - BTSK_p pStack, - FLMUINT uiNumLevels, - FLMBOOL bMutexAlreadyLocked); - -RCODE FSBlockFree( - FDB_p pDb, - SCACHE * pSCache); - -RCODE FSBlockFixLinks( - FDB_p pDb, - LFILE * pLFile, - SCACHE * pSCache); - -RCODE FSBlockUseNextAvail( - FDB_p pDb, - LFILE * pLFile, - SCACHE ** ppSCacheRV); - -FLMUINT ALGetNBC( - FLMBYTE * pBlkBuf); - -#define ALGetNBC( pBlkBuf) \ - (FB2UD( &pBlkBuf [BH_NEXT_BACKCHAIN])) - -void ALPutNBC( - FLMBYTE * pBlkBuf, - FLMUINT uiAddr); - -#define ALPutNBC(pBlkBuf,uiAddr) \ - (UD2FBA( uiAddr, &(pBlkBuf)[ BH_NEXT_BACKCHAIN])) - -RCODE FSCombineBlks( - FDB_p pDb, - LFILE * lfd, - BTSK ** stackRV); - -FLMUINT FSBlkBuildPKC( - BTSK_p stack, - FLMBYTE * pkcBuf, - FLMUINT uiFlags); - -#define FSBBPKC_BEFORE_CURELM 0 -#define FSBBPKC_AT_CURELM 1 - -RCODE FSBlkMoveElms( - BTSK_p newBlkStk, - FLMBYTE * inElm, - FLMUINT uiInsElmLen, - FLMBYTE * elmPKCBuf); - -FLMUINT FSRefFirst( - BTSK_p stack, - DIN_STATE_p state, - FLMUINT * puiDomainRV); - -RCODE FSNextRecord( - FDB_p pDb, - LFILE * pLFile, - BTSK * pStack); - -RCODE FSRefNext( - FDB_p pDb, - LFILE * lfd, - BTSK_p stk, - DIN_STATE_p state, - FLMUINT * puiDrnRV); - -RCODE FSRefSearch( - BTSK_p stack, - DIN_STATE_p state, - FLMUINT * dinRV); - -FLMUINT DINNextVal( - FLMBYTE * dinPtr, - DIN_STATE_p state); - -FLMUINT SENNextVal( - FLMBYTE ** senPtrRV); - -FLMUINT DINOneRunVal( - FLMBYTE * dinPtr, - DIN_STATE_p state); - -FLMUINT FSGetDomain( - FLMBYTE ** curElmRV, - FLMUINT uiElmOvhd); - -RCODE FSBtPrevElm( - FDB_p pDb, - LFILE * lfd, - BTSK_p stack); - -FLMUINT FSRefLast( - BTSK_p stack, - DIN_STATE_p state, - FLMUINT * domainRV); - -FLMUINT FSGetPrevRef( - FLMBYTE * pCurRef, - DIN_STATE_p pState, - FLMUINT uiTarget); - -RCODE FSRefPrev( - FDB_p pDb, - LFILE * lfd, - BTSK_p stk, - DIN_STATE_p state, - FLMUINT * drnRV); - -RCODE FSBtDelete( - FDB_p pDb, - LFILE * lfd, - BTSK_p * stack); - -RCODE FSDelParentElm( - FDB_p pDb, - LFILE * lfd, - BTSK_p * stackRV); - -RCODE FSNewLastBlkElm( - FDB_p pDb, - LFILE * logDef, - BTSK_p * stackRV, - FLMUINT uiFlags); - -#define FSNLBE_GREATER 0x01 -#define FSNLBE_LESS 0x02 -#define FSNLBE_POSITION 0x04 - -RCODE FSBlkDelElm( - BTSK * stack); - -void FSSetChildBlkAddr( - FLMBYTE * childElmPtr, - FLMUINT uiBlkAddr, - FLMUINT uiElmOvhd); - -RCODE FSBtReplace( - FDB_p pDb, - LFILE * lfd, - BTSK_p * stackRV, - FLMBYTE * elm, - FLMUINT uiElmLen); - -RCODE FSBtInsert( - FDB_p pDb, - LFILE * lfd, - BTSK_p * stackRV, - FLMBYTE * elm, - FLMUINT uiElmLen); - -FLMUINT FSSetElmOvhd( - FLMBYTE * elm, - FLMUINT uiElmOvhd, - FLMUINT pkc, - FLMUINT uiKeyLen, - FLMBYTE * byteOneAddr); - -RCODE FSReadRecord( - FDB_p pDb, - LFILE * pLFile, - FLMUINT drn, - FlmRecord ** ppRecord, - FLMUINT * puiRecTransId, - FLMBOOL * pbMostCurrent); - -RCODE FSReadElement( - FDB_p pDb, - POOL * pPool, - LFILE * pLFile, - FLMUINT drn, - BTSK_p pStack, - FLMBOOL bOkToPreallocSpace, - FlmRecord ** ppRecord, - FLMUINT * puiRecTransId, - FLMBOOL * pbMostCurrent); - -RCODE FSRecUpdate( - FDB_p pDb, - LFILE * lfd, - FlmRecord * pRecord, - FLMUINT drn, - FLMUINT uiAddAppendFlags); - -#define REC_UPD_NEW_RECORD 2 -#define REC_UPD_ADD 1 -#define REC_UPD_MODIFY 0 -#define REC_UPD_DELETE 0 - -RCODE FSGetNextDrn( - FDB_p pDb, - LFILE * lfd, - FLMBOOL bUpdateNextDrn, - FLMUINT * drnRV); - -RCODE FSSetNextDrn( - FDB_p pDb, - BTSK_p stack, - FLMUINT drn, - FLMBOOL bManditory); - -RCODE FSRefUpdate( - FDB * pDb, - LFILE * pLFile, - KREF_ENTRY_p pKref); - -void FSFreeIxCounts( - FDB * pDb); - -RCODE FSCommitIxCounts( - FDB * pDb); - -RCODE FSUpdateBlkCounts( - FDB * pDb, - BTSK * pStack, - FLMUINT uiNewCount); - -RCODE FSUpdateAdjacentBlkCounts( - FDB * pDb, - LFILE * pLFile, - BTSK * pStack, - BTSK * pNextBlkStk); - -RCODE FSChangeCount( - FDB * pDb, - BTSK_p pStack, - FLMBOOL bAddReference); - -RCODE FSChangeBlkCounts( - FDB * pDb, - BTSK * pStack, - FLMINT iDelta); - -RCODE FSGetBtreeRefPosition( - FDB * pDb, - BTSK * pStack, - DIN_STATE * pDinState, - FLMUINT * puiRefPosition); - -RCODE FSPositionSearch( - FDB * pDb, - LFILE * pLFile, - FLMUINT uiRefPosition, - BTSK ** ppStack, - FLMUINT * puiRecordId, - FLMUINT * puiDomain, - DIN_STATE * pDinState); - -RCODE FSPositionScan( - BTSK * pStack, - FLMUINT uiRelativePosition, - FLMUINT * puiRelativePosInElement, - FLMUINT * puiRecordId, - FLMUINT * puiDomain, - DIN_STATE * pDinState); - -RCODE FSPositionToRef( - BTSK * pStack, - FLMUINT uiRelativePosition, - FLMUINT * puiRecordId, - FLMUINT * puiDomain, - DIN_STATE * pDinState); - -RCODE FSSetInsertRef( - FLMBYTE * dest, - FLMBYTE * src, - FLMUINT drn, - FLMUINT * puiSetLenRV); - -RCODE FSSetDeleteRef( - FLMBYTE * dest, - FLMBYTE * src, - FLMUINT drn, - FLMUINT * puiSetLenRV); - -FLMUINT SENValLen( - FLMBYTE * senPtr); - -#define SENValLen(ptr) \ - (SENLenArray[ *(ptr) >> 4 ]) - -FLMUINT SENPutNextVal( - FLMBYTE ** senPtrRV, - FLMUINT senValue ); - -FLMUINT DINPutOneRunVal( - FLMBYTE * dinPtr, - DIN_STATE_p state, - FLMUINT value); - -RCODE FSRefSplit( - FDB * pDb, - LFILE * lfd, - BTSK_p * stkRV, - FLMBYTE * elmBuf, - FLMUINT drn, - FLMUINT uiDeleteFlag, - FLMUINT uiSplitFactor); - -RCODE FSBtSearch( - FDB * pDb, - LFILE * pLFile, - BTSK_p * ppStackRV, - FLMBYTE * pKey, - FLMUINT uiKeyLen, - FLMUINT uiDrnDomain); - -RCODE FSBtSearchEnd( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV, - FLMUINT uiDrn); - -RCODE FSGetRootBlock( - FDB * pDb, - LFILE ** ppLFile, - LFILE * pTmpLFile, - BTSK_p pStack); - -RCODE FSBtScan( - BTSK_p stk, - FLMBYTE * key, - FLMUINT uiKeyLen, - FLMUINT uiDrnDomain); - -RCODE FSBtScanNonLeafData( - BTSK_p pStack, - FLMUINT uiDrn); - -void FSBlkToStack( - BTSK_p stack); - -RCODE FSBtScanTo( - BTSK_p stk, - FLMBYTE * key, - FLMUINT uiKeyLen, - FLMUINT drnDomain); - -RCODE FSBlkNextElm( - BTSK_p stack); - -RCODE FSBtNextElm( - FDB_p pDb, - LFILE * pLFile, - BTSK_p pStack); - -RCODE FSAdjustStack( - FDB_p pDb, - LFILE * pLFile, - BTSK_p stack, - FLMBOOL bMovedNext); - -RCODE FSBlkSplit( - FDB_p pDb, - LFILE * pLFile, - BTSK_p * stkRV, - FLMBYTE * elm, - FLMUINT uiElmLen); - -RCODE dbLock( - FDB_p pDb, - FLMUINT uiMaxLockWait); - -RCODE dbUnlock( - FDB_p pDb); - -RCODE flmLFileInit( - FDB_p pDb, - LFILE * pLFile); - -RCODE flmLFileRead( - FDB_p pDb, - LFILE * pLFile); - -RCODE flmBufferToLFile( - FLMBYTE * pBuf, - LFILE * pLFile, - FLMUINT uiBlkAddress, - FLMUINT uiOffsetInBlk); - -RCODE flmLFileWrite( - FDB_p pDb, - LFILE * pLFile); - -RCODE flmLFileCreate( - FDB_p pDb, - LFILE * pLFile, - FLMUINT uiLfNum, - FLMUINT uiLfType); - -RCODE flmLFileDictUpdate( - FDB_p pDb, - LFILE * pDictLFile, - FLMUINT * puiDrnRV, - FlmRecord * pNewDictRecord, - FlmRecord * pOldDictRecord, - FLMBOOL bDoInBackground, - FLMBOOL bCreateSuspended, - FLMBOOL * pbLogCompleteIndexSet, - FLMBOOL bRebuildOp = FALSE); - -RCODE FSComputeRecordBlocks( - BTSK_p pFromStack, - BTSK_p pUntilStack, - FLMUINT * puiLeafBlocksBetween, - FLMUINT * puiTotalRecords, - FLMBOOL * pbTotalsEstimated); - -RCODE FSComputeIndexCounts( - BTSK_p pFromStack, - BTSK_p pUntilStack, - FLMUINT * puiLeafBlocksBetween, - FLMUINT * puiTotalKeys, - FLMUINT * puiTotalRefs, - FLMBOOL * pbTotalsEstimated); - -FLMUINT FSElementRefCount( - BTSK_p pStack); - -RCODE FSBlockCounts( - BTSK_p pStack, - FLMUINT uiFirstElement, - FLMUINT uiLastElement, - FLMUINT * puiFirstKeyCount, - FLMUINT * puiElementCount, - FLMUINT * puiRefCount); - -RCODE flmWriteLogHdr( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMBYTE * pucLogHdr, - FLMBYTE * pucCPLogHdr, - FLMBOOL bIsCheckpoint); - -RCODE flmPhysRollback( - FDB * pDb, - FLMUINT uiLogEOF, - FLMUINT uiFirstLogBlkAddr, - FLMBOOL bDoingRecovery, - FLMUINT uiMaxTransID); - -RCODE lgFlushLogBuffer( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMBOOL bDoAsync); - -RCODE lgOutputBlock( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE_p pFile, - SCACHE * pLogBlock, - FLMBYTE * pucBlk, - FLMBOOL bDoAsync, - FLMUINT * puiLogEofRV); - -void lgSetSyncCheckpoint( - FFILE_p pFile, - FLMUINT uiCheckpoint, - FLMUINT uiBlkAddress); - -FLMUINT lgHdrCheckSum( - FLMBYTE * pucLogHdr, - FLMBOOL bCompare); - -RCODE FSVersionConversion40( - FDB_p pDb, - FLMUINT uiNewVersion, - STATUS_HOOK fnStatusCallback, - void * pvUserData); - -/* -Desc: Get the previous backchain (PBC) address given an block -Return: Address of PBC -*/ -FINLINE FLMUINT ALGetPBC( - FLMBYTE * pucBlkBuf) -{ - FLMUINT uiPbcAddr; - - uiPbcAddr = ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN1]) << 24; - uiPbcAddr |= ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN2]) << 16; - uiPbcAddr |= ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN3]) << 8; - uiPbcAddr |= (FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN0]; - - return( uiPbcAddr); -} - -/* -Desc: Get the previous backchain (PBC) address given an block -*/ -FINLINE void ALPutPBC( - FLMBYTE * pucBlkBuf, - FLMUINT uiAddr) -{ - pucBlkBuf [BH_PREV_BACKCHAIN1] = (FLMBYTE) (uiAddr >> 24); - pucBlkBuf [BH_PREV_BACKCHAIN2] = (FLMBYTE) (uiAddr >> 16); - pucBlkBuf [BH_PREV_BACKCHAIN3] = (FLMBYTE) (uiAddr >> 8); - - // Code doesn't support old pre 3.0 format - - pucBlkBuf [BH_PREV_BACKCHAIN0] = (FLMBYTE) uiAddr; -} - -/* -Desc: Free Chain - reset the avail block with zeros -*/ -FINLINE void ALResetAvailBlk( - FLMBYTE * pucBlkBuf) -{ - UD2FBA( 0, &pucBlkBuf [BH_NEXT_BACKCHAIN]); - - // This is ok to set the [0] backchain - doubles as encryption value. - - pucBlkBuf [BH_PREV_BACKCHAIN0] = - pucBlkBuf [BH_PREV_BACKCHAIN1] = - pucBlkBuf [BH_PREV_BACKCHAIN2] = - pucBlkBuf [BH_PREV_BACKCHAIN3] = 0; -} - -/* -Desc: Compare 2 PKC buffers -Return: Number of bytes that were equal (from left to right) -*/ -FINLINE FLMUINT FSElmComparePKC( - FLMBYTE * pPkcBuf1, - FLMUINT uiPkcBufLen1, - FLMBYTE * pPkcBuf2, - FLMUINT uiPkcBufLen2) -{ - FLMUINT uiMinBytes = f_min( uiPkcBufLen1, uiPkcBufLen2); - FLMUINT uiEqualBytes = 0; - - while( uiMinBytes--) - { - if( *pPkcBuf1++ != *pPkcBuf2++) - { - break; - } - - uiEqualBytes++; - } - - return( uiEqualBytes); -} - -/* -Desc: Returns the parent element's child block value -Return: Address of child block -*/ -FINLINE FLMUINT FSChildBlkAddr( - BTSK_p pStack) -{ - FLMBYTE * childBlkPtr; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - - if( uiElmOvhd == BNE_KEY_START || uiElmOvhd == BNE_KEY_COUNTS_START) - { - childBlkPtr = BLK_ELM_ADDR( pStack, pStack->uiCurElm + BNE_CHILD_BLOCK ); - return( FB2UD( childBlkPtr)); - } - else if( uiElmOvhd == BNE_DATA_OVHD) - { - childBlkPtr = BLK_ELM_ADDR( pStack, pStack->uiCurElm + BNE_DATA_CHILD_BLOCK ); - return( FB2UD( childBlkPtr)); - } - else - { - flmAssert( 0); - return( BNE_KEY_START); - } -} - -/* -Desc: Release the current block in the 'stack' -Out: pStack->pBlk, pSCache are set to NULL values. -Notes: Supports a NULL block (defined as pSCache == NULL) -*/ -FINLINE void FSReleaseBlock( - BTSK_p pStack, - FLMBOOL bMutexAlreadyLocked) -{ - // Release the current block, if any - - if( pStack->pSCache) - { - ScaReleaseCache( pStack->pSCache, bMutexAlreadyLocked); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - - // NOTE: Do NOT unset pStack->uiBlkAddr. There are cases where we - // will release the block, but come back later and re-get it using - // the block address that is in the stack. - } -} - -/* -Desc: Log the current block. The pointer to the block buffer may - change on the log call. -Out: pStack->pBlk may be changed -*/ -FINLINE RCODE FSLogPhysBlk( - FDB_p pDb, - BTSK_p pStack) -{ - RCODE rc; - - if( RC_OK( rc = ScaLogPhysBlk( pDb, &pStack->pSCache))) - { - pStack->pBlk = pStack->pSCache->pucBlk; - } - else - { - ScaReleaseCache( pStack->pSCache, FALSE); - pStack->pBlk = NULL; - pStack->pSCache = NULL; - } - - return( rc); -} - -/* -Desc: Initialize a stack array for cache access. Set all of the pSCache - pointers in the array to NULL. This will prevent them from being - released if they were never filled with anything. -*/ -FINLINE void FSInitStackCache( - BTSK_p pStack, - FLMUINT uiNumLevels) -{ - while( uiNumLevels--) - { - pStack->pSCache = NULL; - pStack->pBlk = NULL; - pStack->uiBlkAddr = BT_END; - pStack++; - } -} - -/* -Desc: Returns TRUE if a 3x address is less than another address. - This will also work with 2x address. -*/ -FINLINE FLMBOOL FSAddrIsBelow( - FLMUINT uiAddress1, - FLMUINT uiAddress2) -{ - if( FSGetFileNumber( uiAddress1) == FSGetFileNumber( uiAddress2)) - { - if( FSGetFileOffset( uiAddress1) >= FSGetFileOffset( uiAddress2)) - { - return( FALSE); - } - } - else if( FSGetFileNumber( uiAddress1) > FSGetFileNumber( uiAddress2)) - { - return( FALSE); - } - - return( TRUE); -} - -/* -Desc: Returns TRUE if a 3x address is less than or equal another address. - This will also work with 2x address. -*/ -FINLINE FLMBOOL FSAddrIsAtOrBelow( - FLMUINT uiAddress1, - FLMUINT uiAddress2) -{ - if( FSGetFileNumber( uiAddress1) == FSGetFileNumber( uiAddress2)) - { - if( FSGetFileOffset( uiAddress1) > FSGetFileOffset( uiAddress2)) - { - return( FALSE); - } - } - else if( FSGetFileNumber( uiAddress1) > FSGetFileNumber( uiAddress2)) - { - return( FALSE); - } - - return( TRUE); -} - -/* -Desc: Put the next DIN value - high level without one run worries -Out: value put into dinPtr[state[0]] -Return: length of DIN -*/ -FINLINE FLMUINT DINPutNextVal( - FLMBYTE * dinPtr, - DIN_STATE_p state, - FLMUINT value) -{ - FLMUINT uiLength; - - dinPtr += state->uiOffset; - uiLength = SENPutNextVal( &dinPtr, value); - state->uiOffset += uiLength; - - return( uiLength); -} - -/* -Desc: This routine gets the number of bytes to encrypt for a block. - For encrypted blocks (new to FLM_VER_4_6), it must return the - block end rounded up to the next 16 byte boundary. For - non-encrypted blocks, in order to maintain compatibility on - a database that has been converted, we must return the block - end rounded up to the next 4 byte boundary. This is because - when a database is converted to 4.60, we don't go through - and recalculate the checksums on every block to go to 16 byte - boundaries. Already-existing blocks will have been calcuated - to a four byte boundary. We can check BH_ENCRYPTED for new - blocks that are on the 16 byte boundary, because that flag was - never set prior to version 4.60, and in 4.60+ that is the only - type of block where it will be set to a 16 byte boundary. -Ret: encryption size - FLMUINT -*/ -FINLINE FLMUINT getEncryptSize( - FLMBYTE * pBlk) -{ - FLMUINT uiLen = (FLMUINT)FB2UW( &pBlk [BH_ELM_END]); - - if (!pBlk [BH_ENCRYPTED]) - { - if (uiLen % sizeof( FLMUINT32) != 0) - { - uiLen += (FLMUINT)(sizeof( FLMUINT32) - (uiLen % sizeof( FLMUINT32))); - } - } - else if (uiLen < BH_OVHD) - { - uiLen = BH_OVHD; - } - else - { - if (uiLen % 16) - { - uiLen += (FLMUINT)(16 - (uiLen % 16)); - } - } - - return( uiLen); -} - -/* -Desc: return the first DRN in an elements reference list -In: BTSK_p stack, state - should be DIN_STATE_SIZ - * puiDomain - returns the elements domain -Out: state information updated to refer to the last reference & puiDomain -Return: DIN the din of the first reference -*/ -FINLINE FLMUINT FSRefFirst( - BTSK_p pStack, - DIN_STATE_p pState, - FLMUINT * puiDomain) -{ - FLMBYTE * pCurElm = CURRENT_ELM( pStack); - - // Point past the domain, ignore return value - - *puiDomain = FSGetDomain( &pCurElm, pStack->uiElmOvhd); - - RESET_DINSTATE_p( pState); - - // Don't use DIN because state must be set to zero after getting value - - return( SENNextVal( &pCurElm)); -} - -/* -Desc: This routine locks the write lock on a database. -*/ -FINLINE RCODE dbWriteLock( - FFILE_p pFile, - DB_STATS * pDbStats = NULL, - FLMUINT uiTimeout = FLM_NO_TIMEOUT) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = pFile->pWriteLockObj->Lock( FALSE, NULL, - (FLMBOOL)(uiTimeout ? TRUE : FALSE), - TRUE, uiTimeout, 0, pDbStats))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/* -Desc: This routine unlocks the write lock on a database. -*/ -FINLINE void dbWriteUnlock( - FFILE_p pFile, - DB_STATS * pDbStats = NULL) -{ - (void)pFile->pWriteLockObj->Unlock( FALSE, NULL, FALSE, pDbStats); -} - -typedef struct Update_Cursor -{ - BTSK_p pStack; // Points to current stack level - FLMUINT uiDrn; // Domain Record Number - FLMUINT uiBufLen; // Length of the buffer - FLMUINT uiUsedLen; // Used length in the buffer - FLMUINT uiFlags; // Bit flags for values below -#define UCUR_REPLACE 1 // Replace current element -#define UCUR_INSERT 2 // Insert current element -#define UCUR_LAST_TIME 4 // Set on last insert/replace - FLMBYTE pKeyBuf[ DIN_KEY_SIZ ]; // Holds the DIN key - FLMBYTE pElmBuf[ ELM_DIN_OVHD + 256]; // Holds each element -} UCUR; - -RCODE FSFlushElement( - FDB * pDb, - LFILE * pLFile, - UCUR * updCur); - -#include "fpackoff.h" - -#endif +//------------------------------------------------------------------------- +// Desc: Definitions for internal database structure. +// Tabs: 3 +// +// Copyright (c) 1990-1993,1995-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: filesys.h 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ +//------------------------------------------------------------------------- + +#ifndef FILESYS_H +#define FILESYS_H + +#include "flaimsys.h" + +#include "fpackon.h" + +struct UCUR; + +// IMPORTANT NOTE: No other include files should follow this one except +// for fpackoff.h + + // B-tree ELEMENT Definitions + // + // Portable element definitions are the basic unit of storage within + // any b-tree block. The new format has changed to support longer + // keys up to 1023 bytes long. + // + // KEY: + // BBE - B-tree Block Element + // BNE - B-tree Non-leaf element + // BUE - B-tree Unknown Element - don't know if leaf or non-leaf + // + // CONT - the element 'does' continue to the next element + // DOMAIN- for the new reference set organization in non-leaf blks + // PKC - number of bytes used in the previous key (PKC) + // KL - key Length - # of bytes to represent the right most key info + // RL - number of bytes in the record portion of the element + // KEY - starts the key bounded by KEY_LEN + // CHILD_BLK - Three byte address of the childs block (non-leaf elms) + // + + // BYTE 0 - BITS 0,1 - First and last element markers + + #define BBE_FIRST_FLAG 0x80 + #define BBE_LAST_FLAG 0x40 + + #define BBE_IS_FIRST(elm) ((*(elm)) & BBE_FIRST_FLAG ) + #define BBE_NOT_FIRST(elm) (!((*(elm)) & BBE_FIRST_FLAG )) + #define BBE_SET_FIRST(elm) ((*(elm)) |= BBE_FIRST_FLAG) + #define BBE_CLR_FIRST(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_FIRST_FLAG))) + + #define BBE_IS_LAST(elm) ((*(elm)) & BBE_LAST_FLAG ) + #define BBE_NOT_LAST(elm) (!((*(elm)) & BBE_LAST_FLAG )) + #define BBE_SET_LAST(elm) ((*(elm)) |= (FLMBYTE)(BBE_LAST_FLAG)) + #define BBE_CLR_LAST(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_LAST_FLAG))) + + #define BBE_IS_FIRST_LAST(e) ((*(e)) & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) + + #define BBE_MIDDLE_FLAG (BBE_FIRST_FLAG|BBE_LAST_FLAG) + #define BBE_IS_MIDDLE(elm) (!((*(elm)) & (BBE_MIDDLE_FLAG))) + #define BBE_SET_MIDDLE(elm) ((*(elm)) = (FLMBYTE)(*(elm) & ~(BBE_MIDDLE_FLAG))) + + // BYTE 0 - BITS 2,3 - Key Length High Bits + + #define BBE_KL_HBITS 0x30 + + // BYTE 0 - BITS 4,5,6,7 - Previous Key Count - [0..15] + + #define BBE_PKC 0 + #define BBE_PKC_MAX 0x0F + + // BBE_SET_PKC should clear out all other values + + #define BBE_SET_PKC(elm,val) ((*(elm)) = (FLMBYTE)(BBE_PKC_MAX & (val))) + #define BBE_CHK_PKC(val) (((val) <= BBE_PKC_MAX) ? val : BBE_PKC_MAX) + #define BBE_GET_PKC(elm) ((*(elm)) & BBE_PKC_MAX) + #define BBE_GETR_PKC(elm) (*(elm) & 0x3F) + + // BYTE 1 - Key Length + + #define BBE_KL 1 + #define BBE_SETR_KL(elm,val) ((elm)[BBE_KL] = (val)) + #define BBE_KL_SHIFT_BITS 4 + + #define BBE_SET_KL(elm,val) \ + { \ + if( (val) > 0xFF) \ + *(elm) |= (FLMBYTE)(((val) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS); \ + (elm)[BBE_KL] = (FLMBYTE) (val); \ + } + + #define BBE_GETR_KL(elm) ((elm)[BBE_KL]) + #define BBE_GET_KL(elm) (((*(elm) & BBE_KL_HBITS) << BBE_KL_SHIFT_BITS) + \ + (elm)[BBE_KL]) + + // BYTE 2 - Record Length + + #define BBE_RL 2 + #define BBE_SET_RL(elm,val) (((elm)[BBE_RL]) = (FLMBYTE)(val)) + #define BBE_GET_RL(elm) ((elm)[BBE_RL]) + + // BYTE 3 - KEY + + #define BBE_KEY 3 + + // + // Non-leaf element format + // + + // BYTE 0 - BIT 0 - DOMAIN FLAG + + #define BNE_DOMAIN 0x80 + #define BNE_IS_DOMAIN(elm) ((*(elm)) & BNE_DOMAIN) + #define BNE_SET_DOMAIN(elm) ((*(elm)) |= BNE_DOMAIN) + #define BNE_CLR_DOMAIN(elm) ((*(elm)) = *(elm) & (~(BNE_DOMAIN))) + #define BNE_DOMAIN_LEN 3 + + // BYTE 0 - BITS 1,2 + // Use BBE_KL_HBITS codes + + // BYTE 0 - Bits 3,4,5,6,7 + // Use BBE_xxx_PKC macros + + // BYTE 1 + // Use BBE_xxx_KL macros + + // BYTES 2-5 - CHILD BLOCK ADDRESS - 4 byte number + + #define BNE_CHILD_BLOCK 2 + #define BNE_CHILD_COUNT 6 + + // BYTE 6 or 10 - Start of Key + + #define BNE_KEY_START 6 + #define BNE_KEY_COUNTS_START 10 + + #define BNE_DATA_CHILD_BLOCK 4 + #define BNE_DATA_OVHD 8 + + // The domain value in 3-byte high-low format will follow the key + + // GENERAL MANIPULATION MACROS + // + // LEN - Length of element + // REC_OFS - Offset into the record portion (skip the key) + // REC_PTR - Address of where record portion starts + // KEY_OFS - Offset into where the key starts + + // + // Compute the complete length of a leaf and non-leaf element + // + + #define BBE_LEN(elm) \ + (BBE_GET_RL(elm) + BBE_GET_KL(elm) + BBE_KEY) + + #define BNE_LEN(stack,elm) \ + (BBE_GET_KL(elm) + stack->uiElmOvhd + \ + (BNE_IS_DOMAIN(elm) ? BNE_DOMAIN_LEN : 0)) + + #define BBE_REC_OFS(elm) \ + (BBE_GET_KL(elm) + BBE_KEY) + + #define BBE_REC_PTR(elm) \ + (&(elm)[ BBE_REC_OFS(elm) ] ) + +// Record OPCODEs used in the storage of data record field values. +// All opcodes are prefixed by FOP which is Field OPcode. +// l = bits used to represent the storage length of the field value +// a = bit flag for number of bytes for TAG_NUM +// b = bit flag for number of bytes for value length +// ffff = 4 bits are used for the field type (0..15) +// vvv = value of levels to shift out to (0..7) +// c = The context flag - 0 is sibling - 1 is child +// z = bits used for a compressed tNum (field number) +// VALUE = value portion of the field +// x = future flag +// i = ID is 2 bytes (0) or 4 bytes long +// e = Value is encrypted + + #define FOP_STANDARD 0 // Use 1 left bit 0cll llll + // zzzz zzzz + // VALUE + + #define FOP_IS_STANDARD(p) (!(*(p) & 0x80)) + #define FSTA_MAX_FLD_NUM 0xFF + #define FSTA_MAX_FLD_LEN 0x3F + #define FSTA_LEVEL(p) ((*p) & 0x40) + #define FSTA_FLD_LEN(p) ((*p) & 0x3F) + #define FSTA_FLD_NUM(p) (*(p+1)) + #define FSTA_OVHD 2 + + #define FOP_GET_FLD_FLAGS(p) ((*p) & 0x07) + #define FOP_2BYTE_FLDNUM(bv) ((bv) & 0x02) + #define FOP_2BYTE_FLDLEN(bv) ((bv) & 0x01) + #define FOP_LOCAL_FLDNUM(bv) ((bv) & 0x04) + + + #define FOP_TAGGED 0x80 // Use 4 left bits 1000 cxab + // 0000 ffff tNum | LENGTH | VALUE + + #define FOP_IS_TAGGED(p) ((*(p) & 0xF0) == FOP_TAGGED) + #define FTAG_LEVEL(p) ((*p) & 0x08) + #define FTAG_GET_FLD_TYPE(c) ((c) & 0x0F) + + #define FOP_OPEN 0x90 // Use 4 left bits 1001 cxab + // tNum | LENGTH | VALUE + + #define FOP_IS_OPEN(p) ((*(p) & 0xF0) == FOP_OPEN) + #define FOPE_LEVEL(p) ((*p) & 0x08) + + + #define FOP_SET_LEVEL 0xA0 // Use 5 left bits 1010 0vvv + #define FOP_IS_SET_LEVEL(p) ((*(p) & 0xF8) == FOP_SET_LEVEL) + #define FOP_LEVEL_MAX 0x07 + #define FSLEV_GET(p) (*(p) & FOP_LEVEL_MAX) + + #define FOP_NO_VALUE 0xA8 // Use 5 left bits 1010 1ca0 + // a = 0 FLD_NUM=1 byte + // a = 1 FLD_NUM=2 byte + + #define FOP_IS_NO_VALUE(p) ((*(p) & 0xF8) == FOP_NO_VALUE) + #define FNOV_LEVEL(p) ((*p) & 0x04) + #define FNOV_OVHD 2 + + #define FOP_RECORD_INFO 0xB0 // Use 7 bits 1011 000b + // LENGTH (1 or 2 bytes) | VALUE + #define FOP_IS_RECORD_INFO(p) \ + ((*(p) & 0xFE) == FOP_RECORD_INFO) + + #define DIN_KEY_SIZ 4 + #define ELM_DIN_OVHD (BBE_KEY + DIN_KEY_SIZ) + + #define MAX_REC_ELM 250 // Max length of record portion + #define MAX_FLD_OVHD 14 // Max field overhead + + // Extended field flags (for open and free fields) + + #define FOP_ENCRYPTED 0xE0 // Use 7 left bits 1110 000c ffff abab + // tNum | LENGTH | eNum | eLENGTH | eVALUE + + #define FOP_IS_ENCRYPTED(p) ((*(p) & 0xFE) == FOP_ENCRYPTED) + #define FENC_LEVEL(p) ((*p) & 0x01) + #define FENC_FLD_TYPE(p) (((*(p+1)) & 0xF0) >> 4) + #define FENC_TAG_SZ(p) (((*(p+1)) & 0x08) >> 3) + #define FENC_LEN_SZ(p) (((*(p+1)) & 0x04) >> 2) + #define FENC_ETAG_SZ(p) (((*(p+1)) & 0x02) >> 1) + #define FENC_ELEN_SZ(p) ((*(p+1)) & 0x01) + + #define FOP_LARGE 0xD0 + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMBOOL FOP_IS_LARGE( + FLMBYTE * pucFOP) + { + // 1101 xxec + // fieldType (1 byte, 0000 ffff) + // tagNum (2 bytes) + // dataLen (4 bytes) + // + // If encrypted, the following are also present: + // + // encryptionId (2 bytes) + // encryptionLength (4 bytes) + + if( (*pucFOP & 0xF0) == FOP_LARGE) + { + return( TRUE); + } + + return( FALSE); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMBOOL FLARGE_LEVEL( + FLMBYTE * pucFOP) + { + flmAssert( FOP_IS_LARGE( pucFOP)); + + if( (*pucFOP & 0x01)) + { + return( TRUE); + } + + return( FALSE); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMBOOL FLARGE_ENCRYPTED( + FLMBYTE * pucFOP) + { + flmAssert( FOP_IS_LARGE( pucFOP)); + + if( (*pucFOP & 0x02)) + { + return( TRUE); + } + + return( FALSE); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMBYTE FLARGE_FLD_TYPE( + FLMBYTE * pucFOP) + { + flmAssert( FOP_IS_LARGE( pucFOP)); + return( *(pucFOP + 1) & 0x0F); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMUINT FLARGE_TAG_NUM( + FLMBYTE * pucFOP) + { + flmAssert( FOP_IS_LARGE( pucFOP)); + return( FB2UW( &pucFOP[ 2])); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMUINT FLARGE_DATA_LEN( + FLMBYTE * pucFOP) + { + flmAssert( FOP_IS_LARGE( pucFOP)); + return( FB2UD( &pucFOP[ 4])); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMUINT FLARGE_ETAG_NUM( + FLMBYTE * pucFOP) + { + flmAssert( FLARGE_ENCRYPTED( pucFOP)); + return( FB2UW( &pucFOP[ 8])); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + inline FLMUINT FLARGE_EDATA_LEN( + FLMBYTE * pucFOP) + { + flmAssert( FLARGE_ENCRYPTED( pucFOP)); + return( FB2UD( &pucFOP[ 10])); + } + + // SEN - Simple Encoded Number + // + // This is the variable length numbering system that can store + // up to a 36 bit number in 1 to 5 bytes. + // The SEN is the backbone to the index reference list compression + // and the standard format for other functions that need to represent + // a number in a variable number of bytes. + + #define SEN_1B_CODE 0x00 // SEN 1 byte code + #define SEN_1B_VAL 127 // Max 1 byte value - 7 bits + + #define SEN_2B_CODE 0x80 // SEN 2 byte code + #define SEN_2B_CMSK 0xC0 // Mask to check for code + #define SEN_2B_VAL 16383 // Max 2 byte value - 14 bits + #define SEN_2B_MASK 0x3F + + #define SEN_3B_CODE 0xC0 // SEN 3 byte code + #define SEN_3B_CMSK 0xF0 // Mask to check for code + #define SEN_3B_VAL 1048575 // Max 3 byte value - 20 bits + #define SEN_3B_MASK 0x0F + + #define SEN_4B_CODE 0xD0 // SEN 4 byte code + #define SEN_4B_CMSK 0xF0 // Mask to check for code + #define SEN_4B_VAL 268435455 // Max 4 byte value - 28 bits + #define SEN_4B_MASK 0x0F + + #define SEN_5B_CODE 0xE0 // SEN 5 byte code + #define SEN_5B_CMSK 0xF0 // Mask to check for code + #define SEN_5B_MASK 0x0F + + #define SEN_FLAG 0xF0 // Flag that contains some meaning + + #define SEN_MAX_SIZ 7 // -2,000,000,000 is biggest SEN + + #define SEN_DOMAIN 0xFC // A domain in SEN format follows + #define SEN_UPDATE_VER 0xFD // Future + + + // DIN - Dual Integer Numbers + + #define DIN_ONE_RUN_LV 0xF0 // Lowest value for one runs + #define DIN_MAX_1B_ONE_RUN 9 // Maximum one byte one run value + #define DIN_ONE_RUN_HV 0xF8 // High value for one runs + + #define DIN_IS_ONE_RUN(b) (((b)==1) || \ + (((b) >= DIN_ONE_RUN_LV) && ((b) <= DIN_ONE_RUN_HV))) + + #define DIN_IS_REAL_ONE_RUN(b) \ + (((b) >= DIN_ONE_RUN_LV) && ((b) <= DIN_ONE_RUN_HV)) + + + // The reference set maximums are computed from the most bytes that + // contain the maximum number of items that can exist within a + // single domain. + // The REF_SET_MAX_SIZ must contain more than one domain or the + // set compression is not working as designed. + // The minimum value of REF_SET_MAX_SIZ should >= 180. The worst pattern + // is 02 01 02 01 02 01 = total must be > 256. 170 references + overhead + // + // REF_SET_FIRST_MAX is not used at this point. + + #define REF_SET_MAX_SIZ 180 // 170 references + extra stuff + #define REF_SPLIT_50_50 50 // Be really conservative + #define REF_SPLIT_90_10 0 // Split at first break + + #define SPLIT_90_10 0 + #define SPLIT_50_50 1 + + // B-tree chain end indicator + + #define BT_END ((FLMUINT)0xFFFFFFFFL) + + // At the end of an element list + + #define ELEMENT_END ((FLMUINT16) 0xFFFF) + + // Domains are used for direct access to the index reference sets + + #define DIN_DOMAIN(din) ((din) >> 8) + #define DRN_DOMAIN(drn) ((drn) >> 8) + #define ZERO_DOMAIN ((FLMUINT) 0) + #define MAX_DOMAIN ((FLMUINT) 0x1000000) + + // B-tree Block Scan Return Codes + + #define BT_EQ_KEY 0 + #define BT_GT_KEY 1 + #define BT_LT_KEY 2 + #define BT_END_OF_DATA 0xFFFF + + #define DRN_LAST_MARKER ((FLMUINT) 0xFFFFFFFF) + #define DRN_LAST_MARKER_LEN 11 + + // Block Header Layout + + #define BH_CHECKSUM_LOW 0 // Low order bits of checksum. + // Ver 3.0 low byte of blk address used + // in the checksum value. + #define BH_ADDR 0 // Block address + #define BH_PREV_BLK 4 // Previous block in the chain + #define BH_NEXT_BLK 8 // Next block in the chain + #define BACKCHAIN_CNT 36 // Number of chains in a back chain + + #define BH_TYPE 12 // Block type - defined below + #define BHT_FREE 0 // Free block - avail list + #define BHT_LEAF 1 // Leaf block + #define BHT_LFH_BLK 4 // LFH Header block + #define BHT_PCODE_BLK 5 // PCODE block + #define BHT_NON_LEAF 6 // Non-leaf block - variable key size + #define BHT_NON_LEAF_DATA 7 // Non-leaf block data block - fixed key size + #define BHT_NON_LEAF_COUNTS 8 // Non-leaf index with counts + + #define BHT_BI_BLK 0x30 + + #define BH_GET_TYPE(blk) \ + (((blk)[BH_TYPE]) & 0x0F ) + + #define BH_SET_BI(blk) \ + (((blk)[BH_TYPE]) |= BHT_BI_BLK) + + #define BH_UNSET_BI(blk) \ + (((blk)[BH_TYPE]) &= (~(BHT_BI_BLK))) + + #define BH_IS_BI(blk) \ + ((((blk)[BH_TYPE]) & BHT_BI_BLK) == BHT_BI_BLK) + + #define BHT_ROOT_BLK 0x80 + + #define BH_IS_ROOT_BLK(blk) \ + (((blk)[BH_TYPE]) & BHT_ROOT_BLK) + + #define BH_SET_ROOT_BLK(blk) \ + ((blk)[BH_TYPE] |= BHT_ROOT_BLK) + + // The maximum levels in any b-tree be 8 levels with version 3.x. + // We will not worry about 2x compatibility problems until we understand + // what needs to be done on the 2x to 30 conversion. + // Very long keys in index records (500-1000 bytes) could easily run + // out of 8 levels, but this is very unlikely at this time. + + #define BH_LEVEL 13 // Block level (B-tree only) + + #define BH_MAX_LEVELS 8 // Max allowable b-tree levels + #define MAX_LEVELS BH_MAX_LEVELS + + #define BH_ELM_END 14 // End of the elements in a block + #define BH_BLK_END 14 // End of the elements in a block + + #define BH_TRANS_ID 16 // Last transaction to update this block + #define BH_PREV_TRANS_ID 20 // Previous transaction to update block + #define BH_PREV_BLK_ADDR 24 // Pointer to previous image of blk + #define BH_LOG_FILE_NUM 28 // Logical file number of block + #define BH_ENCRYPTED 30 // Flag indicating if block is encrypted + #define BH_CHECKSUM_HIGH 31 // High order bits of checksum + + #define BH_OVHD 32 // Overhead in the block header + + #define BH_NEXT_BACKCHAIN 4 // Backchains of avail list - 4 bytes + #define BH_PREV_BACKCHAIN0 30 // Avail blocks as of version 3 not encrypted + #define BH_PREV_BACKCHAIN1 13 // Prev backchain contains 3 bytes + #define BH_PREV_BACKCHAIN2 28 // at different locations in the header + #define BH_PREV_BACKCHAIN3 29 // Level and logical file num are used + + #define BBE_LEM_LEN 3 // Length of leaf last element marker + + #define GET_BH_ADDR( pBlk) \ + (FB2UD(&(pBlk)[BH_ADDR])) + + #define SET_BH_ADDR( pBlk, dwAddr) \ + UD2FBA( dwAddr, &(pBlk)[BH_ADDR] ) + + // Block access from the cache pointer + + #define GET_CABLKPTR(stack) \ + ((stack)->pSCache->pucBlk) + + #define CABLK_ELM(stack,elm) \ + ((stack)->pSCache->pucBlk[ (elm) ]) + + // Block access from the pBlk + + #define SET_BLKPTR(stack) \ + ((stack)->pBlk = stack->pSCache->pucBlk) + + #define BLK_PTR(stack) \ + ((stack)->pBlk) + + #define BLK_ELM(stack,elm) \ + ((stack)->pBlk[ (elm) ]) + + #define BLK_ELM_ADDR(stack,elm) \ + (&((stack)->pBlk[ (elm) ])) + + #define CURRENT_ELM(stack) \ + (&((stack)->pBlk[ stack->uiCurElm ])) + + inline void flmCopyDrnKey( + FLMBYTE * pucDest, + FLMBYTE * pucSrc) + { +#ifdef FLM_UNIX + f_memcpy( pucDest, pucSrc, sizeof( FLMUINT32)); +#else + *((FLMUINT32 *)pucDest) = *((FLMUINT32 *)pucSrc); +#endif + } + + // Resolving the block address into components. + + #define MAX_DATA_FILE_NUM_VER40 0x1FF + #define MAX_LOG_FILE_NUM_VER40 0x3FF + #define MAX_DATA_FILE_NUM_VER43 0x7FF + #define MAX_LOG_FILE_NUM_VER43 0xFFF + + #define MAX_DATA_BLOCK_FILE_NUMBER(uiDbVersion) \ + (FLMUINT)(((uiDbVersion) >= FLM_FILE_FORMAT_VER_4_3) \ + ? MAX_DATA_FILE_NUM_VER43 \ + : MAX_DATA_FILE_NUM_VER40) + + #define FIRST_LOG_BLOCK_FILE_NUMBER(uiDbVersion) \ + (FLMUINT)(MAX_DATA_BLOCK_FILE_NUMBER(uiDbVersion) + 1) + + #define MAX_LOG_BLOCK_FILE_NUMBER(uiDbVersion) \ + (FLMUINT)(((uiDbVersion) >= FLM_FILE_FORMAT_VER_4_3) \ + ? MAX_LOG_FILE_NUM_VER43 \ + : MAX_LOG_FILE_NUM_VER40) + + #define FSGetFileNumber( uiBlkAddr) \ + ((uiBlkAddr) & MAX_LOG_FILE_NUM_VER43) + + #define FSGetFileOffset( udBlkAddr) \ + ((udBlkAddr) & 0xFFFFF000) + + #define FSBlkAddress( iFileNum, udFileOfs) \ + ((udFileOfs) + (iFileNum)) + + // Max file size and log threshold. + + #define MAX_FILE_SIZE_VER40 ((FLMUINT)0x7FF00000) + #define LOG_THRESHOLD_SIZE ((FLMUINT) 0x40000) + + FINLINE FLMUINT flmGetMaxFileSize( + FLMUINT uiDbVersion, + FLMBYTE * pucLogHdr) + { + FLMUINT uiMaxSize = MAX_FILE_SIZE_VER40; + + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) + { + uiMaxSize = ((FLMUINT)FB2UW( &pucLogHdr[ LOG_MAX_FILE_SIZE])) << 16; + if( !uiMaxSize) + { + uiMaxSize = MAX_FILE_SIZE_VER40; + } + } + + return( uiMaxSize); + } + + // Very large threshhold is the size we will allow the physical + // log to grow to before we force a truncation. At the low end, + // it is about 10 megabytes. At the high end it is about + // 1 gigabyte. + + #define LOW_VERY_LARGE_LOG_THRESHOLD_SIZE ((FLMUINT)0xA00000) + #define HIGH_VERY_LARGE_LOG_THRESHOLD_SIZE ((FLMUINT) 0x40000000) + + // RFL_TRUNCATE_SIZE is the size we will let an RFL file grow to + // before we truncate it back. RFL files are only truncated if + // we are configured to delete old RFL files. + + #define RFL_TRUNCATE_SIZE ((FLMUINT)1024 * (FLMUINT)1024 * (FLMUINT)10) + + void ScaCleanupCache( + FLMUINT uiMaxLockTime); + + void ScaFreeModifiedBlocks( + FDB * pDb); + + FLMBOOL flmNeededByReadTrans( + FFILE * pFile, + FLMUINT uiLowTransId, + FLMUINT uiHighTransId); + + void ScaReleaseLogBlocks( + FFILE * pFile); + + RCODE ScaGetBlock( + FDB * pDb, + LFILE * pLFile, + FLMUINT uiBlkType, + FLMUINT uiBlkAddress, + FLMUINT * puiNumLooksRV, + SCACHE ** ppSCacheRV); + + RCODE ScaCreateBlock( + FDB * pDb, + LFILE * pLFile, + SCACHE ** ppSCacheRV); + + void ScaHoldCache( + SCACHE * pSCache); + + void ScaReleaseCache( + SCACHE * pSCache, + FLMBOOL bMutexAlreadyLocked); + + RCODE ScaLogPhysBlk( + FDB * pDb, + SCACHE ** ppSCacheRV); + + RCODE ScaInit( + FLMUINT uiMaxSharedCache); + + RCODE ScaConfig( + FLMUINT uiType, + void * pvValue1, + void * pvValue2); + + void ScaExit( void); + + void ScaFreeFileCache( + FFILE * pFile); + + RCODE ScaDoCheckpoint( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMBOOL bDoTruncate, + FLMBOOL bForceCheckpoint, + FLMINT iForceReason, + FLMUINT uiCPFileNum, + FLMUINT uiCPOffset); + + RCODE ScaEncryptBlock( + FFILE * pFile, + FLMBYTE * pucBuffer, + FLMUINT uiBufLen, + FLMUINT uiBlockSize); + + RCODE ScaDecryptBlock( + FFILE * pFile, + FLMBYTE * pucBuffer); + + FLMUINT64 FSGetSizeInBytes( + FLMUINT uiMaxFileSize, + FLMUINT uiBlkAddress); + + RCODE FSGetBlock( + FDB * pDb, + LFILE * pLFile, + FLMUINT uiBlkAddress, + BTSK * pStack); + + void FSReleaseStackCache( + BTSK * pStack, + FLMUINT uiNumLevels, + FLMBOOL bMutexAlreadyLocked); + + RCODE FSBlockFree( + FDB * pDb, + SCACHE * pSCache); + + RCODE FSBlockFixLinks( + FDB * pDb, + LFILE * pLFile, + SCACHE * pSCache); + + RCODE FSBlockUseNextAvail( + FDB * pDb, + LFILE * pLFile, + SCACHE ** ppSCacheRV); + + FLMUINT ALGetNBC( + FLMBYTE * pBlkBuf); + + #define ALGetNBC( pBlkBuf) \ + (FB2UD( &pBlkBuf [BH_NEXT_BACKCHAIN])) + + void ALPutNBC( + FLMBYTE * pBlkBuf, + FLMUINT uiAddr); + + #define ALPutNBC(pBlkBuf,uiAddr) \ + (UD2FBA( uiAddr, &(pBlkBuf)[ BH_NEXT_BACKCHAIN])) + + RCODE FSCombineBlks( + FDB * pDb, + LFILE * lfd, + BTSK ** stackRV); + + FLMUINT FSBlkBuildPKC( + BTSK * stack, + FLMBYTE * pkcBuf, + FLMUINT uiFlags); + + #define FSBBPKC_BEFORE_CURELM 0 + #define FSBBPKC_AT_CURELM 1 + + RCODE FSBlkMoveElms( + BTSK * newBlkStk, + FLMBYTE * inElm, + FLMUINT uiInsElmLen, + FLMBYTE * elmPKCBuf); + + inline FLMUINT FSRefFirst( + BTSK * stack, + DIN_STATE * state, + FLMUINT * puiDomainRV); + + RCODE FSNextRecord( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack); + + RCODE FSRefNext( + FDB * pDb, + LFILE * lfd, + BTSK * stk, + DIN_STATE * state, + FLMUINT * puiDrnRV); + + RCODE FSRefSearch( + BTSK * stack, + DIN_STATE * state, + FLMUINT * dinRV); + + FLMUINT DINNextVal( + FLMBYTE * dinPtr, + DIN_STATE * state); + + FLMUINT SENNextVal( + FLMBYTE ** senPtrRV); + + FLMUINT DINOneRunVal( + FLMBYTE * dinPtr, + DIN_STATE * state); + + FLMUINT FSGetDomain( + FLMBYTE ** curElmRV, + FLMUINT uiElmOvhd); + + RCODE FSBtPrevElm( + FDB * pDb, + LFILE * lfd, + BTSK * stack); + + FLMUINT FSRefLast( + BTSK * stack, + DIN_STATE * state, + FLMUINT * domainRV); + + FLMUINT FSGetPrevRef( + FLMBYTE * pCurRef, + DIN_STATE * pState, + FLMUINT uiTarget); + + RCODE FSRefPrev( + FDB * pDb, + LFILE * lfd, + BTSK * stk, + DIN_STATE * state, + FLMUINT * drnRV); + + RCODE FSBtDelete( + FDB * pDb, + LFILE * lfd, + BTSK ** stack); + + RCODE FSDelParentElm( + FDB * pDb, + LFILE * lfd, + BTSK ** stackRV); + + RCODE FSNewLastBlkElm( + FDB * pDb, + LFILE * logDef, + BTSK ** stackRV, + FLMUINT uiFlags); + + #define FSNLBE_GREATER 0x01 + #define FSNLBE_LESS 0x02 + #define FSNLBE_POSITION 0x04 + + RCODE FSBlkDelElm( + BTSK * stack); + + void FSSetChildBlkAddr( + FLMBYTE * childElmPtr, + FLMUINT uiBlkAddr, + FLMUINT uiElmOvhd); + + RCODE FSBtReplace( + FDB * pDb, + LFILE * lfd, + BTSK ** stackRV, + FLMBYTE * elm, + FLMUINT uiElmLen); + + RCODE FSBtInsert( + FDB * pDb, + LFILE * lfd, + BTSK ** stackRV, + FLMBYTE * elm, + FLMUINT uiElmLen); + + FLMUINT FSSetElmOvhd( + FLMBYTE * elm, + FLMUINT uiElmOvhd, + FLMUINT pkc, + FLMUINT uiKeyLen, + FLMBYTE * byteOneAddr); + + RCODE FSReadRecord( + FDB * pDb, + LFILE * pLFile, + FLMUINT drn, + FlmRecord ** ppRecord, + FLMUINT * puiRecTransId, + FLMBOOL * pbMostCurrent); + + RCODE FSReadElement( + FDB * pDb, + POOL * pPool, + LFILE * pLFile, + FLMUINT drn, + BTSK * pStack, + FLMBOOL bOkToPreallocSpace, + FlmRecord ** ppRecord, + FLMUINT * puiRecTransId, + FLMBOOL * pbMostCurrent); + + RCODE FSRecUpdate( + FDB * pDb, + LFILE * lfd, + FlmRecord * pRecord, + FLMUINT drn, + FLMUINT uiAddAppendFlags); + + #define REC_UPD_NEW_RECORD 2 + #define REC_UPD_ADD 1 + #define REC_UPD_MODIFY 0 + #define REC_UPD_DELETE 0 + + RCODE FSGetNextDrn( + FDB * pDb, + LFILE * lfd, + FLMBOOL bUpdateNextDrn, + FLMUINT * drnRV); + + RCODE FSSetNextDrn( + FDB * pDb, + BTSK * stack, + FLMUINT drn, + FLMBOOL bManditory); + + RCODE FSRefUpdate( + FDB * pDb, + LFILE * pLFile, + KREF_ENTRY * pKref); + + void FSFreeIxCounts( + FDB * pDb); + + RCODE FSCommitIxCounts( + FDB * pDb); + + RCODE FSUpdateBlkCounts( + FDB * pDb, + BTSK * pStack, + FLMUINT uiNewCount); + + RCODE FSUpdateAdjacentBlkCounts( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack, + BTSK * pNextBlkStk); + + RCODE FSChangeCount( + FDB * pDb, + BTSK * pStack, + FLMBOOL bAddReference); + + RCODE FSChangeBlkCounts( + FDB * pDb, + BTSK * pStack, + FLMINT iDelta); + + RCODE FSGetBtreeRefPosition( + FDB * pDb, + BTSK * pStack, + DIN_STATE * pDinState, + FLMUINT * puiRefPosition); + + RCODE FSPositionSearch( + FDB * pDb, + LFILE * pLFile, + FLMUINT uiRefPosition, + BTSK * * ppStack, + FLMUINT * puiRecordId, + FLMUINT * puiDomain, + DIN_STATE * pDinState); + + RCODE FSPositionScan( + BTSK * pStack, + FLMUINT uiRelativePosition, + FLMUINT * puiRelativePosInElement, + FLMUINT * puiRecordId, + FLMUINT * puiDomain, + DIN_STATE * pDinState); + + RCODE FSPositionToRef( + BTSK * pStack, + FLMUINT uiRelativePosition, + FLMUINT * puiRecordId, + FLMUINT * puiDomain, + DIN_STATE * pDinState); + + RCODE FSSetInsertRef( + FLMBYTE * dest, + FLMBYTE * src, + FLMUINT drn, + FLMUINT * puiSetLenRV ); + + RCODE FSSetDeleteRef( + FLMBYTE * dest, + FLMBYTE * src, + FLMUINT drn, + FLMUINT * puiSetLenRV); + + FLMUINT SENValLen( + FLMBYTE * senPtr); + + #define SENValLen(ptr) \ + (SENLenArray[ *(ptr) >> 4 ]) + + FLMUINT SENPutNextVal( + FLMBYTE ** senPtrRV, + FLMUINT senValue ); + + FLMUINT DINPutOneRunVal( + FLMBYTE * dinPtr, + DIN_STATE * state, + FLMUINT value); + + RCODE FSRefSplit( + FDB * pDb, + LFILE * lfd, + BTSK ** stkRV, + FLMBYTE * elmBuf, + FLMUINT drn, + FLMUINT uiDeleteFlag, + FLMUINT uiSplitFactor); + + RCODE FSBtSearch( + FDB * pDb, + LFILE * pLFile, + BTSK ** ppStackRV, + FLMBYTE * pKey, + FLMUINT uiKeyLen, + FLMUINT uiDrnDomain); + + RCODE FSBtSearchEnd( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMUINT uiDrn); + + RCODE FSGetRootBlock( + FDB * pDb, + LFILE ** ppLFile, + LFILE * pTmpLFile, + BTSK * pStack); + + RCODE FSBtScan( + BTSK * stk, + FLMBYTE * key, + FLMUINT uiKeyLen, + FLMUINT uiDrnDomain); + + RCODE FSBtScanNonLeafData( + BTSK * pStack, + FLMUINT uiDrn); + + void FSBlkToStack( + BTSK * stack); + + RCODE FSBtScanTo( + BTSK * stk, + FLMBYTE * key, + FLMUINT uiKeyLen, + FLMUINT drnDomain); + + RCODE FSBlkNextElm( + BTSK * stack); + + RCODE FSBtNextElm( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack); + + RCODE FSAdjustStack( + FDB * pDb, + LFILE * pLFile, + BTSK * stack, + FLMBOOL bMovedNext); + + RCODE FSBlkSplit( + FDB * pDb, + LFILE * pLFile, + BTSK ** stkRV, + FLMBYTE * elm, + FLMUINT uiElmLen); + + RCODE dbLock( + FDB * pDb, + FLMUINT uiMaxLockWait); + + RCODE dbUnlock( + FDB * pDb); + + RCODE flmLFileInit( + FDB * pDb, + LFILE * pLFile); + + RCODE flmLFileRead( + FDB * pDb, + LFILE * pLFile); + + RCODE flmBufferToLFile( + FLMBYTE * pBuf, + LFILE * pLFile, + FLMUINT uiBlkAddress, + FLMUINT uiOffsetInBlk); + + RCODE flmLFileWrite( + FDB * pDb, + LFILE * pLFile); + + RCODE flmLFileCreate( + FDB * pDb, + LFILE * pLFile, + FLMUINT uiLfNum, + FLMUINT uiLfType); + + RCODE flmLFileDictUpdate( + FDB * pDb, + LFILE * pDictLFile, + FLMUINT * puiDrnRV, + FlmRecord * pNewDictRecord, + FlmRecord * pOldDictRecord, + FLMBOOL bDoInBackground, + FLMBOOL bCreateSuspended, + FLMBOOL * pbLogCompleteIndexSet, + FLMBOOL bRebuildOp = FALSE); + + RCODE FSComputeRecordBlocks( + BTSK * pFromStack, + BTSK * pUntilStack, + FLMUINT * puiLeafBlocksBetween, + FLMUINT * puiTotalRecords, + FLMBOOL * pbTotalsEstimated); + + RCODE FSComputeIndexCounts( + BTSK * pFromStack, + BTSK * pUntilStack, + FLMUINT * puiLeafBlocksBetween, + FLMUINT * puiTotalKeys, + FLMUINT * puiTotalRefs, + FLMBOOL * pbTotalsEstimated); + + FLMUINT FSElementRefCount( + BTSK * pStack); + + RCODE FSBlockCounts( + BTSK * pStack, + FLMUINT uiFirstElement, + FLMUINT uiLastElement, + FLMUINT * puiFirstKeyCount, + FLMUINT * puiElementCount, + FLMUINT * puiRefCount); + + RCODE flmWriteLogHdr( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMBYTE * pucLogHdr, + FLMBYTE * pucCPLogHdr, + FLMBOOL bIsCheckpoint); + + RCODE flmPhysRollback( + FDB * pDb, + FLMUINT uiLogEOF, + FLMUINT uiFirstLogBlkAddr, + FLMBOOL bDoingRecovery, + FLMUINT uiMaxTransID); + + RCODE lgFlushLogBuffer( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMBOOL bDoAsync); + + RCODE lgOutputBlock( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + SCACHE * pLogBlock, + FLMBYTE * pucBlk, + FLMBOOL bDoAsync, + FLMUINT * puiLogEofRV); + + void lgSetSyncCheckpoint( + FFILE * pFile, + FLMUINT uiCheckpoint, + FLMUINT uiBlkAddress); + + FLMUINT lgHdrCheckSum( + FLMBYTE * pucLogHdr, + FLMBOOL bCompare); + + RCODE FSVersionConversion40( + FDB * pDb, + FLMUINT uiNewVersion, + STATUS_HOOK fnStatusCallback, + void * pvUserData); + + RCODE FSFlushElement( + FDB * pDb, + LFILE * pLFile, + UCUR * updCur); + + /**************************************************************************** + Desc: Get the previous backchain (PBC) address given an block + ****************************************************************************/ + inline FLMUINT ALGetPBC( + FLMBYTE * pucBlkBuf) + { + FLMUINT uiPbcAddr; + + uiPbcAddr = ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN1]) << 24; + uiPbcAddr |= ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN2]) << 16; + uiPbcAddr |= ((FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN3]) << 8; + uiPbcAddr |= (FLMUINT) pucBlkBuf [BH_PREV_BACKCHAIN0]; + + return( uiPbcAddr); + } + + /**************************************************************************** + Desc: Get the previous backchain (PBC) address given an block + ****************************************************************************/ + inline void ALPutPBC( + FLMBYTE * pucBlkBuf, + FLMUINT uiAddr) + { + pucBlkBuf [BH_PREV_BACKCHAIN1] = (FLMBYTE) (uiAddr >> 24); + pucBlkBuf [BH_PREV_BACKCHAIN2] = (FLMBYTE) (uiAddr >> 16); + pucBlkBuf [BH_PREV_BACKCHAIN3] = (FLMBYTE) (uiAddr >> 8); + + // Code doesn't support old pre 3.0 format + pucBlkBuf [BH_PREV_BACKCHAIN0] = (FLMBYTE) uiAddr; + } + + /**************************************************************************** + Desc: Free Chain - reset the avail block with zeros + ****************************************************************************/ + inline void ALResetAvailBlk( + FLMBYTE * pucBlkBuf) + { + UD2FBA( 0, &pucBlkBuf [BH_NEXT_BACKCHAIN]); + + // This is ok to set the [0] backchain - doubles as encryption value. + pucBlkBuf [BH_PREV_BACKCHAIN0] = + pucBlkBuf [BH_PREV_BACKCHAIN1] = + pucBlkBuf [BH_PREV_BACKCHAIN2] = + pucBlkBuf [BH_PREV_BACKCHAIN3] = 0; + } + + /**************************************************************************** + Desc: Compare 2 PKC buffers + Return: Number of bytes that were equal (from left to right) + ****************************************************************************/ + inline FLMUINT FSElmComparePKC( + FLMBYTE * pPkcBuf1, + FLMUINT uiPkcBufLen1, + FLMBYTE * pPkcBuf2, + FLMUINT uiPkcBufLen2) + { + FLMUINT uiMinBytes = f_min( uiPkcBufLen1, uiPkcBufLen2); + FLMUINT uiEqualBytes = 0; + + while( uiMinBytes--) + { + if( *pPkcBuf1++ != *pPkcBuf2++ ) + break; + uiEqualBytes++; + } + return( uiEqualBytes); + } + + /**************************************************************************** + Desc: Returns the parent element's child block value + Return: Address of child block + ****************************************************************************/ + inline FLMUINT FSChildBlkAddr( + BTSK * pStack) + { + FLMBYTE * childBlkPtr; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + + if( uiElmOvhd == BNE_KEY_START || uiElmOvhd == BNE_KEY_COUNTS_START) + { + childBlkPtr = BLK_ELM_ADDR( pStack, pStack->uiCurElm + BNE_CHILD_BLOCK ); + return FB2UD( childBlkPtr); + } + else if( uiElmOvhd == BNE_DATA_OVHD) + { + childBlkPtr = BLK_ELM_ADDR( pStack, pStack->uiCurElm + BNE_DATA_CHILD_BLOCK ); + return FB2UD( childBlkPtr); + } + else + { + // Pre 3.x format is no longer supported. + // Corruption + flmAssert( 0); + return BNE_KEY_START; + } + } + + /**************************************************************************** + Desc: Release the current block in the 'stack' + Out: pStack->pBlk, pSCache are set to NULL values. + Notes: Supports a NULL block (defined as pSCache == NULL) + ****************************************************************************/ + inline void FSReleaseBlock( + BTSK * pStack, // Stack of variables for each level + FLMBOOL bMutexAlreadyLocked) + { + // Release the current block, if any + + if( pStack->pSCache) + { + ScaReleaseCache( pStack->pSCache, bMutexAlreadyLocked); + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + // NOTE: Do NOT unset pStack->uiBlkAddr. There are cases where we + // will release the block, but come back later and re-get it using + // the block address that is in the stack. + } + } + + /**************************************************************************** + Desc: Log the current block. The pointer to the block buffer may + change on the log call. + Out: pStack->pBlk may be changed + ****************************************************************************/ + inline RCODE FSLogPhysBlk( + FDB * pDb, + BTSK * pStack) + { + RCODE rc; + + if( RC_OK( rc = ScaLogPhysBlk( pDb, &pStack->pSCache))) + { + pStack->pBlk = pStack->pSCache->pucBlk; + } + else + { + ScaReleaseCache( pStack->pSCache, FALSE); + pStack->pBlk = NULL; + pStack->pSCache = NULL; + } + + return( rc); + } + + /**************************************************************************** + Desc: Initialize a stack array for cache access. Set all of the pSCache + pointers in the array to NULL. This will prevent them from being + released if they were never filled with anything. + ****************************************************************************/ + inline void FSInitStackCache( + BTSK * pStack, + FLMUINT uiNumLevels) + { + while( uiNumLevels--) + { + pStack->pSCache = NULL; + pStack->pBlk = NULL; + pStack->uiBlkAddr = BT_END; + pStack++; + } + } + + /**************************************************************************** + Desc: Returns TRUE if a 3x address is less than another address. + This will also work with 2x address. + ****************************************************************************/ + inline FLMBOOL FSAddrIsBelow( + FLMUINT uiAddress1, + FLMUINT uiAddress2) + { + if( FSGetFileNumber( uiAddress1) == FSGetFileNumber( uiAddress2)) + { + if( FSGetFileOffset( uiAddress1) >= FSGetFileOffset( uiAddress2)) + { + return FALSE; + } + } + else if( FSGetFileNumber( uiAddress1) > FSGetFileNumber( uiAddress2)) + { + return FALSE; + } + return TRUE; + } + + /**************************************************************************** + Desc: Returns TRUE if a 3x address is less than or equal another address. + This will also work with 2x address. + ****************************************************************************/ + inline FLMBOOL FSAddrIsAtOrBelow( + FLMUINT uiAddress1, + FLMUINT uiAddress2) + { + if( FSGetFileNumber( uiAddress1) == FSGetFileNumber( uiAddress2)) + { + if( FSGetFileOffset( uiAddress1) > FSGetFileOffset( uiAddress2)) + { + return FALSE; + } + } + else if( FSGetFileNumber( uiAddress1) > FSGetFileNumber( uiAddress2)) + { + return FALSE; + } + return TRUE; + } + + /**************************************************************************** + Desc: Put the next DIN value - high level without one run worries + Out: value put into dinPtr[state[0]] + Return: length of DIN + ****************************************************************************/ + inline FLMUINT DINPutNextVal( + FLMBYTE * dinPtr, + DIN_STATE * state, + FLMUINT value) + { + FLMUINT uiLength; + + dinPtr += state->uiOffset; + uiLength = SENPutNextVal( &dinPtr, value); + state->uiOffset += uiLength; + + return( uiLength ); + } + + /**************************************************************************** + Desc: This routine gets the number of bytes to encrypt for a block. + For encrypted blocks (new to FLM_FILE_FORMAT_VER_4_6), it must return + the block end rounded up to the next 16 byte boundary. For + non-encrypted blocks, in order to maintain compatibility on + a database that has been converted, we must return the block + end rounded up to the next 4 byte boundary. This is because + when a database is converted to 4.60, we don't go through + and recalculate the checksums on every block to go to 16 byte + boundaries. Already-existing blocks will have been calcuated + to a four byte boundary. We can check BH_ENCRYPTED for new + blocks that are on the 16 byte boundary, because that flag was + never set prior to version 4.60, and in 4.60+ that is the only + type of block where it will be set to a 16 byte boundary. + Ret: encryption size - FLMUINT + ****************************************************************************/ + inline FLMUINT getEncryptSize( + FLMBYTE * pBlk) + { + FLMUINT uiLen = (FLMUINT)FB2UW( &pBlk [BH_ELM_END]); + if (!pBlk [BH_ENCRYPTED]) + { + if (uiLen % sizeof( FLMUINT32) != 0) + { + uiLen += (FLMUINT)(sizeof( FLMUINT32) - (uiLen % sizeof( FLMUINT32))); + } + } + else if (uiLen < BH_OVHD) + { + uiLen = BH_OVHD; + } + else + { + if (uiLen % 16) + { + uiLen += (FLMUINT)(16 - (uiLen % 16)); + } + } + return( uiLen); + } + + /**************************************************************************** + Desc: return the first DRN in an elements reference list + In: BTSK * stack, state - should be DIN_STATE_SIZ + * puiDomain - returns the elements domain + Out: state information updated to refer to the last reference & puiDomain + Return: DIN the din of the first reference + ****************************************************************************/ + inline FLMUINT FSRefFirst( + BTSK * pStack, // Small stack to hold b-tree variables + DIN_STATE * pState, // Holds offset, one run number, etc. + FLMUINT * puiDomain) // Returns the elements domain + { + FLMBYTE * pCurElm = CURRENT_ELM( pStack); + + // Point past the domain, ignore return value + + *puiDomain = FSGetDomain( &pCurElm, pStack->uiElmOvhd); + + RESET_DINSTATE_p( pState); + + // Don't use DIN because state must be set to zero after getting value + + return( SENNextVal( &pCurElm)); + } + + /**************************************************************************** + Desc: This routine locks the write lock on a database. + ****************************************************************************/ + inline RCODE dbWriteLock( + FFILE * pFile, + DB_STATS * pDbStats = NULL, + FLMUINT uiTimeout = FLM_NO_TIMEOUT) + { + RCODE rc = FERR_OK; + + if (RC_BAD( rc = pFile->pWriteLockObj->Lock( FALSE, NULL, + (FLMBOOL)(uiTimeout ? TRUE : FALSE), + TRUE, uiTimeout, 0, pDbStats))) + { + goto Exit; + } + + Exit: + + return( rc); + } + + /**************************************************************************** + Desc: This routine unlocks the write lock on a database. + ****************************************************************************/ + inline void dbWriteUnlock( + FFILE * pFile, + DB_STATS * pDbStats = NULL) + { + (void)pFile->pWriteLockObj->Unlock( FALSE, NULL, FALSE, pDbStats); + } + + /**************************************************************************** + Desc: + ****************************************************************************/ + typedef struct UCUR + { + BTSK * pStack; // Points to current stack level + FLMUINT uiDrn; // Domain Record Number + FLMUINT uiBufLen; // Length of the buffer + FLMUINT uiUsedLen; // Used length in the buffer + FLMUINT uiFlags; // Bit flags for values below + #define UCUR_REPLACE 1 // Replace current element + #define UCUR_INSERT 2 // Insert current element + #define UCUR_LAST_TIME 4 // Set on last insert/replace + FLMBYTE pKeyBuf[ DIN_KEY_SIZ ]; // Holds the DIN key + FLMBYTE pElmBuf[ ELM_DIN_OVHD + 256]; // Holds each element + } UCUR; + +#include "fpackoff.h" + +#endif diff --git a/flaim/src/fitem.cpp b/flaim/src/fitem.cpp deleted file mode 100644 index 11a267e..0000000 --- a/flaim/src/fitem.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Functions for doing id-to-name and name-to-id mapping. -// Tabs: 3 -// -// Copyright (c) 1995-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fitem.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/******************************************************************************* -Desc: Retrieves a dictionary item name. -Notes: Given an item ID, this routine will search a specified shared or - local dictionary for the item. If it is found, the name - of the item will be returned. This routine supports version 2.0 and - higher databases only. -*******************************************************************************/ -FLMEXP RCODE FLMAPI FlmGetItemName( - HFDB hDb, - FLMUINT uiItemId, - FLMUINT uiNameBufSize, - char * pszNameBuf) -{ - RCODE rc = FERR_OK; - FlmRecord * pRecord = NULL; - - *pszNameBuf = 0; - if( RC_BAD( rc = FlmRecordRetrieve( hDb, - FLM_DICT_CONTAINER, uiItemId, FO_EXACT, &pRecord, NULL))) - { - goto Exit; - } - - if( RC_BAD( rc = pRecord->getNative( pRecord->root(), - pszNameBuf, &uiNameBufSize))) - { - goto Exit; - } - -Exit: - - if( pRecord) - { - pRecord->Release(); - } - - return (rc == FERR_EOF_HIT) ? RC_SET( FERR_NOT_FOUND) : rc; -} diff --git a/flaim/src/flaim.h b/flaim/src/flaim.h index eb469c2..5689d4a 100644 --- a/flaim/src/flaim.h +++ b/flaim/src/flaim.h @@ -321,7 +321,7 @@ /// \defgroup dbcreateopen Database Create, Open, Close /// \ingroup database - /// \defgroup Trans Transaction Functions + /// \defgroup trans Transaction Functions /// \ingroup database /// \defgroup update Database Update Functions @@ -403,10 +403,10 @@ #define FALSE 0 #endif - typedef void * F_MUTEX; - typedef void * F_SEM; - #define F_MUTEX_NULL NULL - #define F_MAXIMUM_FILE_SIZE 0xFFFC0000 + typedef void * F_MUTEX; + typedef void * F_SEM; + #define F_MUTEX_NULL NULL + #define F_MAXIMUM_FILE_SIZE 0xFFFC0000 /// Return codes typedef enum @@ -659,9 +659,9 @@ FERR_PASSWD_INVALID, ///< 0xC329 - Invalid password passed, database could not be opened. - /**************************************************************************** + /************************************************************************* Server TCP/IP Errors - ****************************************************************************/ + *************************************************************************/ FERR_SVR_NOIP_ADDR = 0xC900, ///< 0xC900 - IP address not found. FERR_SVR_SOCK_FAIL, ///< 0xC901 - IP socket failure. @@ -694,7 +694,7 @@ #endif /*************************************************************************** - * Forward Declarations + Forward Declarations ***************************************************************************/ class FlmRecord; @@ -706,42 +706,40 @@ class F_Restore; /*************************************************************************** - * FLAIM Types + FLAIM Types ***************************************************************************/ - typedef void * HFDB; ///< Database handle. + typedef void * HFDB; ///< Database handle. #define HFDB_NULL NULL - typedef void * HFCURSOR; ///< Query object handle. + typedef void * HFCURSOR; ///< Query object handle. #define HFCURSOR_NULL NULL - typedef void * HFBLOB; ///< BLOB handle. + typedef void * HFBLOB; ///< BLOB handle. #define HFBLOB_NULL NULL - typedef void * HFBACKUP; ///< Backup object handle. + typedef void * HFBACKUP; ///< Backup object handle. #define HFBACKUP_NULL NULL /// Header for blocks in a memory pool. This structure is at the head of each block that belongs to a pool of /// memory. typedef struct MBLK { - MBLK * pPrevBlk; ///< Points to the previous memory block in the memory pool. - FLMUINT uiBlkSize; ///< Total size of the memory block. - FLMUINT uiFreeOfs; ///< Offset in block where next allocation should be made. - FLMUINT uiFreeSize; ///< Amount of free memory left in block - from uiFreeOfs. + MBLK * pPrevBlk; ///< Points to the previous memory block in the memory pool. + FLMUINT uiBlkSize; ///< Total size of the memory block. + FLMUINT uiFreeOfs; ///< Offset in block where next allocation should be made. + FLMUINT uiFreeSize; ///< Amount of free memory left in block - from uiFreeOfs. } MBLK; - /* - Desc: Structure that is used my "Smart" pools to determine optimal - block sizes. - */ + /// Pool statistics. This structure is used to track statistics on + /// smart pools. typedef struct { - FLMUINT uiAllocBytes; // Total number of bytes requested from - // GedPoolAlloc & GedPoolCalloc calls - FLMUINT uiCount; // Number of Free/Resets performed on - // the pool + FLMUINT uiAllocBytes; ///< Total number of bytes requested from + ///< GedPoolAlloc and GedPoolCalloc calls + FLMUINT uiCount; ///< Number of frees and resets performed on + ///< the pool } POOL_STATS; - /// Pool memory manager. Thus structure is used to keep track of a pool + /// Pool memory manager. This structure is used to keep track of a pool /// of memory blocks that are used for pool memory allocation. typedef struct { @@ -801,18 +799,19 @@ #define DEFAULT_BLKSIZ 4096 FLMUINT uiVersionNum; ///< Database version number. - #define FLM_VER_3_0 301 - #define FLM_VER_3_02 302 - #define FLM_VER_3_10 310 - #define FLM_VER_4_0 400 - #define FLM_VER_4_3 430 - #define FLM_VER_4_31 431 // Added last committed trans ID to the log header - #define FLM_VER_4_50 450 // Added ability to create cross-container indexes. - #define FLM_VER_4_51 451 // Added ability to permanently suspend indexes - #define FLM_VER_4_52 452 // Added ability to delete indexes in the background - #define FLM_VER_4_60 460 // Added support for encrypted attributes - #define FLM_CURRENT_VERSION_NUM FLM_VER_4_60 - #define FLM_CURRENT_VER_STR "4.60" + #define FLM_FILE_FORMAT_VER_3_0 301 + #define FLM_FILE_FORMAT_VER_3_02 302 + #define FLM_FILE_FORMAT_VER_3_10 310 + #define FLM_FILE_FORMAT_VER_4_0 400 + #define FLM_FILE_FORMAT_VER_4_3 430 + #define FLM_FILE_FORMAT_VER_4_31 431 // Added last committed trans ID to the log header + #define FLM_FILE_FORMAT_VER_4_50 450 // Added ability to create cross-container indexes. + #define FLM_FILE_FORMAT_VER_4_51 451 // Added ability to permanently suspend indexes + #define FLM_FILE_FORMAT_VER_4_52 452 // Added ability to delete indexes in the background + #define FLM_FILE_FORMAT_VER_4_60 460 // Added support for encrypted attributes + #define FLM_FILE_FORMAT_VER_4_61 461 // Added support for RFL disk usage limits, large field values, and async I/O on Linux and Solaris + #define FLM_CUR_FILE_FORMAT_VER_NUM FLM_FILE_FORMAT_VER_4_61 + #define FLM_CUR_FILE_FORMAT_VER_STR "4.61" FLMUINT uiMinRflFileSize; ///< Minimum bytes per RFL file. #define DEFAULT_MIN_RFL_FILE_SIZE ((FLMUINT)100 * (FLMUINT)1024 * (FLMUINT)1024) @@ -945,7 +944,7 @@ }; /**************************************************************************** - Name Table Function Structures + Name Table Function Structures ****************************************************************************/ typedef struct @@ -1261,6 +1260,14 @@ FlmRecord * pNewRecord; ///< New record (adds, modifies). FlmRecord * pOldRecord; ///< Old record (modifies, deletes). } FLM_UPDATE_EVENT; + + /// Structure returned to an event handler function whenever RFL size events occur.\ Specifically, this structure is + /// returned whenever the RFL exceeds the on-disk size threshold specified for a database. + typedef struct + { + const char * pszRflDir; ///< RFL directory path + FLMUINT64 ui64RflDiskUsage; ///< Size of the RFL + } FLM_RFL_SIZE_EVENT; /// Structure that gives the current state of the checkpoint thread.\ Returned from FlmDbGetConfig() when /// eDbGetConfigType::FDB_GET_CHECKPOINT_INFO is passed in as the option. @@ -1535,12 +1542,6 @@ const FLMUNICODE * puzStr2 ///< Unicode string 2 - string must be terminated with a zero Unicode character. ); - /*-------------------------------------------------------- - FLAIM Record stuff - **-------------------------------------------------------*/ - - #define FLM_MAX_FIELD_VAL_SIZE ((FLMUINT)65535) - /// This class allows an application to keep a set of ::FlmRecord objects. class FLMEXP FlmRecordSet : public F_Base { @@ -2176,18 +2177,18 @@ /// Add a value to the query criteria. A value is generally added where an operand would appear - such as in a comparison expression. /// \ingroup querydef FLMEXP RCODE FLMAPI FlmCursorAddValue( - HFCURSOR hCursor, ///< Handle to query object. - QTYPES eValType, ///< Type of value being added to the query criteria. - void * pVal, ///< Pointer to the value being added.\ This should point to a value that corresponds to the type - ///< specified in eValType. - FLMUINT uiValLen ///< For binary values, this will contain the value length.\ It is not used for any other type of - ///< value.\ String values are expected to be null-terminated. + HFCURSOR hCursor, ///< Handle to query object. + QTYPES eValType, ///< Type of value being added to the query criteria. + void * pVal, ///< Pointer to the value being added.\ This should point to a value that corresponds to the type + ///< specified in eValType. + FLMUINT uiValLen ///< For binary values, this will contain the value length.\ It is not used for any other type of + ///< value.\ String values are expected to be null-terminated. ); /// Finalize and validate query syntax. After this function has been called, no more query criteria may be added. /// \ingroup querydef FLMEXP RCODE FLMAPI FlmCursorValidate( - HFCURSOR hCursor ///< Handle to query object. + HFCURSOR hCursor ///< Handle to query object. ); /// Startup FLAIM database system. @@ -2476,7 +2477,7 @@ ); /**************************************************************************** - Statistics + Statistics ****************************************************************************/ /// Structure used in gathering statistics to hold an operation count and an elapsed time. @@ -2640,7 +2641,7 @@ { F_EVENT_LOCKS, ///< Catch all database lock events. F_EVENT_UPDATES, ///< Catch all transaction and update event events. - F_MAX_EVENT_CATEGORIES + F_EVENT_SIZE ///< Catch all size threshold events } FEventCategory; /// Types of events returned to registered event handling functions. See FlmRegisterForEvent() @@ -2663,7 +2664,7 @@ F_EVENT_INDEXING_COMPLETE, ///< Background indexing status, pvEventData1 (FLMUINT) == index number, ///< pvEventData2 (FLMUINT) == last drn indexed, ///< if zero indexing is complete and the index is now online. - F_MAX_EVENT_TYPES // Should always be last. + F_EVENT_RFL_SIZE ///< RFL size threshold has been exceeded, pvEventData1 == FLM_RFL_SIZE_EVENT *. } FEventType; typedef void * HFEVENT; ///< Handle returned from FlmRegisterForEvent() - needed when calling FlmDeregisterForEvent(). @@ -2855,9 +2856,16 @@ ///< update transaction.\ pvValue1 is a pointer to the callback ///< function - a ::COMMIT_FUNC.\ pvValue2 is a pointer to application data that will be passed into the ///< function whenever it is called. - FDB_ENABLE_FIELD_ID_TABLE ///< Enable the creating of a field ID table for level-one fields in cached records for a specific + FDB_ENABLE_FIELD_ID_TABLE, ///< Enable the creating of a field ID table for level-one fields in cached records for a specific ///< container.\ pvValue1 is a FLMUINT that holds the container number.\ pvValue2 is a FLMBOOL indicating ///< whether the field id table is to be enabled or disabled. + FDB_SET_RFL_SIZE_THRESHOLD, ///< Sets the RFL size threshold (in K bytes). If registered to receive RFL size events, an event will + ///< be reported when the on-disk size of the RFL exceeds this value.\ pvValue1 is a FLMUINT which + ///< specifies the threshold value in K bytes. + FDB_SET_RFL_SIZE_EVENT_INTERVALS ///< Sets the criteria for determining how often to report RFL size events once the RFL exceeds the + ///< size threshold.\ pvValue1 is a FLMUINT which specifies the minimum number of seconds between + ///< events.\ pvValue2 is a FLMUINT which specifies the minimum increase in K bytes of the RFL + ///< between events. } eDbConfigType; #define F_SERIAL_NUM_SIZE 16 @@ -2976,7 +2984,7 @@ #define FO_DONT_REDO_LOG 0x0040 // Used only in FlmDbOpen #define FO_DONT_RESUME_BACKGROUND_THREADS 0x0080 // Used only in FlmDbOpen - #define FO_ALLOW_LIMITED 0X0400 // Used only in FlmDbOpen + #define FO_ALLOW_LIMITED 0x0400 // Used only in FlmDbOpen /// Close a database. /// \ingroup dbcreateopen @@ -3126,11 +3134,11 @@ HFDB hDb, ///< Database handle - see FlmDbOpen() or FlmDbCreate(). FLMUINT uiIndexNum ///< Number of index to resume. ); - + /// Determine if a return code (RCODE) indicates a corruption. /// \ingroup errhandling FLMEXP FLMBOOL FLMAPI FlmErrorIsFileCorrupt( - RCODE rc ///< Error code to be tested. + RCODE rc ///< Error code to be tested. ); /// Convert a return code (RCODE) into a string. @@ -3190,7 +3198,7 @@ #define FLM_NO_TIMEOUT 0xFF /// Begin a transaction on the database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbTransBegin( HFDB hDb, ///< Database handle. FLMUINT uiTransType, ///< Type of transaction to start.\ May be FLM_UPDATE_TRANS or FLM_READ_TRANS.\ The @@ -3216,7 +3224,7 @@ #define F_TRANS_HEADER_SIZE 2048 // Size of buffer required for pszHeader parameter of FlmDbTransBegin /// Commit current transaction (if any) on a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbTransCommit( HFDB hDb, ///< Database handle. FLMBOOL * pbEmpty = NULL ///< If non-NULL, this returns a flag indicating whether or not the transaction was @@ -3228,13 +3236,13 @@ ); /// Abort current transaction (if any) on a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbTransAbort( HFDB hDb ///< Database handle. ); /// Get type of current transaction (if any) on a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbGetTransType( HFDB hDb, ///< Database handle. FLMUINT * puiTransType ///< Transaction type is returned here.\ It will be @@ -3245,7 +3253,7 @@ ); /// Get current transaction ID. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbGetTransId( HFDB hDb, ///< Database handle. FLMUINT * puiTransID ///< Current transaction ID is returned here.\ If no transaction is currently active, @@ -3253,14 +3261,14 @@ ); /// Get number of committed transactions for a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbGetCommitCnt( HFDB hDb, ///< Database handle. FLMUINT * puiCommitCount ///< Number of transactions that have been committed is returned here. ); /// Lock a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbLock( HFDB hDb, ///< Database handle. FLOCK_TYPE eLockType, ///< Type of lock being requested. @@ -3271,13 +3279,13 @@ ); /// Unlock a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbUnlock( HFDB hDb ///< Database handle. ); /// Get the type of lock currently in effect on a database (if any). - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbGetLockType( HFDB hDb, ///< Database handle. FLOCK_TYPE * peLockType, ///< Type of lock currently held returned here. @@ -3289,7 +3297,7 @@ ); /// Get lock information for a database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbGetLockInfo( HFDB hDb, ///< Database handle. FLMINT iPriority, ///< A count of all locks with a priority >= this value will be returned in @@ -3298,7 +3306,7 @@ ); /// Perform a checkpoint on the database. - /// \ingroup Trans + /// \ingroup trans FLMEXP RCODE FLMAPI FlmDbCheckpoint( HFDB hDb, ///< Database handle. FLMUINT uiTimeout ///< Specifies the maximum number of seconds to wait to obtain the database lock.\ An @@ -3666,8 +3674,9 @@ ///< operation.\ pvValue2 is a FLMUINT that contains the number of blocks to delete.\ pvValue3 is a ///< FLMUINT that contains the block address of the last block that was deleted. RESTORE_WRAP_KEY, ///< Restoring a FlmDbWrapKey() operation.\ pvValue1 is a FLMUINT that contains the length of the database key. - RESTORE_ENABLE_ENCRYPTION ///< Restoring a FlmEnableEncryption() operation.\ pvValue1 is a FLMUINT that contains the length of + RESTORE_ENABLE_ENCRYPTION, ///< Restoring a FlmEnableEncryption() operation.\ pvValue1 is a FLMUINT that contains the length of ///< the database key. + RESTORE_CONFIG_SIZE_EVENT ///< Restoring a FlmSetSizeEventThreshold() operation.\ pvValue1 is a FLMUINT .... // here } eRestoreStatusType; /// Actions that an application may want to tell FlmDbRestore() to take during a restore operation. @@ -3779,9 +3788,9 @@ ) = 0; }; - /*-------------------------------------------------------- - BLOB Class, Functions and Definitions - **-------------------------------------------------------*/ + /**************************************************************************** + BLOB Class, Functions and Definitions + ****************************************************************************/ // FlmBlob::create uiBlobType values @@ -3833,10 +3842,6 @@ FlmBlob ** ppBlob ///< Pointer to newly allocated BLOB object is returned here. ); - /* - *** FLAIM message logging - */ - /// Categories of messages that FLAIM can log and that an application can request to receive. typedef enum { @@ -4155,8 +4160,10 @@ /// Convert a native string to FLAIM's internal storage format. /// \ingroup storageconversion FLMEXP RCODE FLMAPI FlmNative2Storage( - const char * pszStr, ///< Native string that is to be converted.\ FLAIM expects the string - ///< to be null-terminated. + const char * pszStr, ///< Native string that is to be converted. + FLMUINT uiStrLen, ///< Length (in bytes) of the native string.\ If zero, the string is + ///< expected to be NULL-terminated. + ///< *puiStorageLen contains number of bytes returned. FLMUINT * puiStorageLen, ///< On input, *puiStorageLen is length (in bytes) of pucStorageBuf.\ On output, ///< *puiStorageLen contains number of bytes returned. FLMBYTE * pucStorageBuf ///< Converted string, in FLAIM's internal storage format, is returned here. @@ -4613,7 +4620,7 @@ #define RCA_OLD_VERSION 0x00000008 #define RCA_HEAP_BUFFER 0x00000010 #define RCA_ID_TABLE_HEAP_BUFFER 0x00000020 - #define RCA_FIELD_ID_TABLE_ENABLED 0x00000040 + #define RCA_FIELD_ID_TABLE_ENABLED 0x00000040 #define RCA_NEED_TO_SORT_FIELD_ID_TABLE 0x00000080 FlmRecord(); @@ -5954,6 +5961,7 @@ FLM_BAD_PCODE_IXD_TBL, ///< 82 FLM_DICT_REC_ADD_ERR, ///< 83 FLM_BAD_FIELD_FLAG, ///< 84 + FLM_BAD_FOP, ///< 85 FLM_LAST_CORRUPT_ERROR } eCorruptionType; @@ -6388,10 +6396,9 @@ const char * pszFileName, const char * pszTemplate); - /* - *** Directories - */ - + /**************************************************************************** + Desc: Directory handle + ****************************************************************************/ class FLMEXP F_DirHdl : public F_Base { public: @@ -6419,10 +6426,6 @@ FLMEXP RCODE FLMAPI FlmAllocDirHdl( F_DirHdl ** ppDirHdl); - /* - *** List item - */ - typedef struct { F_ListItem * pPrevItem; // Prev ListItem @@ -6432,6 +6435,9 @@ // a ListItem (only used in ListMgr) } F_ListNode; + /**************************************************************************** + Desc: + ****************************************************************************/ class FLMEXP F_ListItem : public F_Base { protected: @@ -6509,10 +6515,9 @@ friend class F_ObjRefTracker; }; - /* - *** File handle - */ - + /**************************************************************************** + Desc: + ****************************************************************************/ class FLMEXP F_FileHdl : public F_ListItem { public: @@ -6570,12 +6575,9 @@ FLMEXP RCODE FLMAPI FlmAllocFileHandle( F_FileHdl ** ppFileHandle); - /* - *** File flags - */ - - #define F_IO_CURRENT_POS 0xFFFFFFFF + // File flags + #define F_IO_CURRENT_POS 0xFFFFFFFF #define F_IO_RDONLY 0x0001 #define F_IO_RDWR 0x0002 #define F_IO_TRUNC 0x0004 @@ -6593,10 +6595,9 @@ #define F_IO_SEEK_CUR 1 // Current File Pointer Position #define F_IO_SEEK_END 2 // End of File - /* - *** File system - */ - + /**************************************************************************** + Desc: + ****************************************************************************/ class FLMEXP F_FileSystem : public F_Base { public: diff --git a/flaim/src/flaimsys.h b/flaim/src/flaimsys.h index 74354af..967729c 100644 --- a/flaim/src/flaimsys.h +++ b/flaim/src/flaimsys.h @@ -28,6 +28,17 @@ #include "flaim.h" +#if defined( FLM_DEBUG) && !defined( FLM_HPUX) + #define f_new new( __FILE__, __LINE__) +#else + #define f_new new +#endif + +FLMUINT flmStrHashBucket( + const char * pszStr, + struct FBUCKET * pHashTbl, + FLMUINT uiNumBuckets); + class FResultSet; class F_Thread; class HRequest; @@ -58,43 +69,13 @@ class F_FixedAlloc; class F_BufferAlloc; class F_CCS; -typedef struct Kref_Entry * KREF_ENTRY_p; -typedef struct Kref_Cntrl * KREF_CNTRL_p; -typedef struct F_Event * FEVENT_p; -typedef struct FBucket * FBUCKET_p; -typedef struct Itt * ITT_p; -typedef struct Ixd * IXD_p; -typedef struct Ifd * IFD_p; -typedef struct Cdl * CDL_p; -typedef struct FDict * FDICT_p; -typedef struct FNotify * FNOTIFY_p; -typedef struct File_Hdr * FILE_HDR_p; -typedef struct Log_Hdr * LOG_HDR_p; -typedef struct FFile * FFILE_p; -typedef struct FDb * FDB_p; -typedef struct FlmBlob_Tag * FBLOB_p; -typedef struct FlmBlobInfo * FBLOBINFO_p; -typedef struct Din_State * DIN_STATE_p; -typedef struct Btsk * BTSK_p; -typedef struct SCache_Mgr * SCACHE_MGR_p; -typedef struct CP_Info * CP_INFO_p; -typedef struct RCache_Mgr_Tag * RCACHE_MGR_p; -typedef struct CS_Context * CS_CONTEXT_p; -typedef struct F_BkgndIx * F_BKGND_IX_p; -typedef struct QueryHdrTag * QUERY_HDR_p; - -FLMUINT flmStrHashBucket( - const char * pszStr, - FBUCKET_p pHashTbl, - FLMUINT uiNumBuckets); - #include "ftk.h" #include "ftkmem.h" #include "ftknsem.h" -#include "ftkwptxt.h" +#include "ftksem.h" #include "ftkthrd.h" #include "fstructs.h" -#include "fddpcode.h" +#include "fdict.h" #include "flist.h" #include "fmutxref.h" #include "ffilehdl.h" @@ -119,10 +100,8 @@ FLMUINT flmStrHashBucket( #include "fsuperfl.h" #include "f64bitfh.h" #include "fdynsset.h" -#include "frestore.h" #include "fobjtrck.h" #include "ftrace.h" -#include "gddiff.h" #include "flfixed.h" #include "f_nici.h" @@ -157,6 +136,239 @@ FLMUINT flmStrHashBucket( #endif +// Language definitions + +#define US_LANG 0 // English, United States +#define AF_LANG 1 // Afrikaans +#define AR_LANG 2 // Arabic +#define CA_LANG 3 // Catalan +#define HR_LANG 4 // Croatian +#define CZ_LANG 5 // Czech +#define DK_LANG 6 // Danish +#define _NL_LANG 7 // Dutch +#define OZ_LANG 8 // English, Australia +#define CE_LANG 9 // English, Canada +#define UK_LANG 10 // English, United Kingdom +#define FA_LANG 11 // Farsi +#define SU_LANG 12 // Finnish +#define CF_LANG 13 // French, Canada +#define FR_LANG 14 // French, France +#define GA_LANG 15 // Galician +#define DE_LANG 16 // German, Germany +#define SD_LANG 17 // German, Switzerland +#define GR_LANG 18 // Greek +#define HE_LANG 19 // Hebrew +#define HU_LANG 20 // Hungarian +#define IS_LANG 21 // Icelandic +#define IT_LANG 22 // Italian +#define NO_LANG 23 // Norwegian +#define PL_LANG 24 // Polish +#define BR_LANG 25 // Portuguese, Brazil +#define PO_LANG 26 // Portuguese, Portugal +#define RU_LANG 27 // Russian +#define SL_LANG 28 // Slovak +#define ES_LANG 29 // Spanish +#define SV_LANG 30 // Swedish +#define YK_LANG 31 // Ukrainian +#define UR_LANG 32 // Urdu +#define TK_LANG 33 // Turkey +#define JP_LANG 34 // Japanese +#define KO_LANG 35 // Korean +#define CT_LANG 36 // Chinese-Traditional +#define CS_LANG 37 // Chinese-Simplified +#define LA_LANG 38 // another asian language + +#define LAST_LANG (LA_LANG + 1) +#define FIRST_DBCS_LANG (JP_LANG) +#define LAST_DBCS_LANG (LA_LANG) + +// Character code high byte values for character sets + +#define CHSASCI 0 // ASCII +#define CHSMUL1 1 // Multinational 1 +#define CHSMUL2 2 // Multinational 2 +#define CHSBOXD 3 // Box drawing +#define CHSSYM1 4 // Typographic Symbols +#define CHSSYM2 5 // Iconic Symbols +#define CHSMATH 6 // Math +#define CHMATHX 7 // Math Extension +#define CHSGREK 8 // Greek +#define CHSHEB 9 // Hebrew +#define CHSCYR 10 // Cyrillic +#define CHSKANA 11 // Japanese Kana +#define CHSUSER 12 // User-defined +#define CHSARB1 13 // Arabic +#define CHSARB2 14 // Arabic script + +#define NCHSETS 15 // # of character sets (excluding asian) +#define ACHSETS 0x0E0 // maximum character set value - asian +#define ACHSMIN 0x024 // minimum character set value - asian +#define ACHCMAX 0x0FE // maxmimum character value in asian sets + +// Bit patterns for codes in internal text type + +#define ASCII_CHAR_CODE 0x00 // 0nnnnnnn +#define ASCII_CHAR_MASK 0x80 // 10000000 +#define CHAR_SET_CODE 0x80 // 10nnnnnn +#define CHAR_SET_MASK 0xC0 // 11000000 +#define WHITE_SPACE_CODE 0xC0 // 110nnnnn +#define WHITE_SPACE_MASK 0xE0 // 11100000 + +// UNK_GT_255 is an outdated code not part of 3x or newer + +#define UNK_GT_255_CODE 0xE0 // 11100nnn +#define UNK_GT_255_MASK 0xF8 // 11111000 +#define UNK_EQ_1_CODE 0xF0 // 11110nnn +#define UNK_EQ_1_MASK 0xF8 // 11111000 + +// UNK_LE_255 is an outdated code not part of 3x or newer + +#define UNK_LE_255_CODE 0xF8 // 11111nnn +#define UNK_LE_255_MASK 0xF8 // 11111000 +#define EXT_CHAR_CODE 0xE8 // 11101000 +#define OEM_CODE 0xE9 // 11101001 +#define UNICODE_CODE 0xEA // 11101010 + +// Text type defines + +#define WP60_TYPE 1 +#define NATIVE_TYPE 2 + +// Misc. character constants + +#define HARD_HYPHEN 3 +#define HARD_HYPHEN_EOL 4 +#define HARD_HYPHEN_EOP 5 +#define HARD_RETURN 7 +#define NATIVE_TAB 12 +#define NATIVE_LINEFEED 13 +#define UNICODE_UNCONVERTABLE_CHAR 0x03 + +// Collation bits + +#define HAD_SUB_COLLATION 0x01 // Set if had sub-collating values-diacritics +#define HAD_LOWER_CASE 0x02 // Set if you hit a lowercase character +#define COMPOUND_MARKER 0x02 // Compound key marker between each piece +#define END_COMPOUND_MARKER 0x01 // Last of all compound markers - for post +#define NULL_KEY_MARKER 0x03 +#define COLL_FIRST_SUBSTRING 0x03 // First substring marker +#define COLL_MARKER 0x04 // Marks place of sub-collation +#define SC_LOWER 0x00 // Only lowercase characters exist +#define SC_MIXED 0x01 // Lower/uppercase flags follow in next byte +#define SC_UPPER 0x02 // Only upper characters exist +#define SC_SUB_COL 0x03 // Sub-collation follows (diacritics|extCh) +#define UNK_UNICODE_CODE 0xFFFE // Used for collation +#define COLL_TRUNCATED 0x0C // This key piece has been truncated from original +#define MAX_COL_OPCODE COLL_TRUNCATED + +// Numeric collation + +#define SIG_POS 0x80 +#define COLLATED_DIGIT_OFFSET 0x05 +#define COLLATED_NUM_EXP_BIAS 64 +#define MIN_7BIT_EXP 0x08 +#define MAX_7BIT_EXP 0x78 + +// Definitions for diacritics + +#define grave 0 +#define centerd 1 +#define tilde 2 +#define circum 3 +#define crossb 4 +#define slash 5 +#define acute 6 +#define umlaut 7 +#define macron 8 +#define aposab 9 +#define aposbes 10 +#define aposba 11 +#define ring 14 +#define dota 15 +#define dacute 16 +#define cedilla 17 +#define ogonek 18 +#define caron 19 +#define stroke 20 +#define breve 22 +#define dotlesi 239 +#define dotlesj 25 +#define gacute 83 // greek acute +#define gdia 84 // greek diaeresis +#define gactdia 85 // acute diaeresis +#define ggrvdia 86 // grave diaeresis +#define ggrave 87 // greek grave +#define gcircm 88 // greek circumflex +#define gsmooth 89 // smooth breathing +#define grough 90 // rough breathing +#define giota 91 // iota subscript +#define gsmact 92 // smooth breathing acute +#define grgact 93 // rough breathing acute +#define gsmgrv 94 // smooth breathing grave +#define grggrv 95 // rough breathing grave +#define gsmcir 96 // smooth breathing circumflex +#define grgcir 97 // rough breathing circumflex +#define gactio 98 // acute iota +#define ggrvio 99 // grave iota +#define gcirio 100 // circumflex iota +#define gsmio 101 // smooth iota +#define grgio 102 // rough iota +#define gsmaio 103 // smooth acute iota +#define grgaio 104 // rough acute iota +#define gsmgvio 105 // smooth grave iota +#define grggvio 106 // rough grave iota +#define gsmcio 107 // smooth circumflex iota +#define grgcio 108 // rough circumflex iota +#define ghprime 81 // high prime +#define glprime 82 // low prime +#define racute 200 // russian acute +#define rgrave 201 // russian grave +#define rrtdesc 204 // russian right descender +#define rogonek 205 // russian ogonek +#define rmacron 206 // russian macron + +/**************************************************************************** +Desc: +****************************************************************************/ +#define flmTextObjType(c) ( \ + (((c & ASCII_CHAR_MASK) == ASCII_CHAR_CODE) \ + ? ASCII_CHAR_CODE \ + : (((c & WHITE_SPACE_MASK) == WHITE_SPACE_CODE) \ + ? WHITE_SPACE_CODE \ + : (((c & UNK_EQ_1_MASK) == UNK_EQ_1_CODE) \ + ? UNK_EQ_1_CODE \ + : (((c & CHAR_SET_MASK) == CHAR_SET_CODE) \ + ? CHAR_SET_CODE \ + : c \ + ) \ + ) \ + ) \ + ) \ +) + +FLMBOOL flmIsUpper( + FLMUINT16 ui16Char); + +FLMUINT16 flmCh6Upper( + FLMUINT16 ui16WpChar); + +FLMUINT16 flmCh6Lower( + FLMUINT16 ui16WpChar); + +FLMBOOL flmCh6Brkcar( + FLMUINT16 ui16WpChar, + FLMUINT16 * pui16BaseChar, + FLMUINT16 * pui16DiacriticChar); + +FLMBOOL flmCh6Cmbcar( + FLMUINT16 * pui16WpChar, + FLMUINT16 ui16BaseChar, + FLMINT16 i16DiacriticChar); + +FLMUINT flmUnicodeToWP( + const FLMUNICODE * pUniStr, + FLMUINT16 * pWPChr); + /**************************************************************************** General FLAIM @@ -548,17 +760,17 @@ FLMINT gedCopyValue( #define KY_CONTEXT_LEN 3 // Length of each context index FINLINE RCODE KYFlushKeys( - FDB_p pDb); + FDB * pDb); RCODE KrefCntrlCheck( FDB * pDb); void KrefCntrlFree( - FDB_p pDb); + FDB * pDb); RCODE flmProcessRecFlds( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, FLMUINT uiContainerNum, FLMUINT uiDrn, FlmRecord * pRecord, @@ -590,9 +802,9 @@ FLMBOOL flmCheckIfdPath( RCODE KYAddToKrefTbl( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, FLMUINT uiContainer, - IFD_p pIfd, + IFD * pIfd, FLMUINT uiAction, FLMUINT uiDrn, FLMBOOL * pbHadUniqueKeys, @@ -615,15 +827,15 @@ RCODE KYKeysCommit( void KYGetIxAndCdlEntries( FDB * pDb, - IXD_p pIxd, - IFD_p pIfd, + IXD * pIxd, + IFD * pIfd, FLMUINT * puiIxEntryRV, FLMUINT * puiCdlEntryRV); RCODE KYCmpKeyAdd2Lst( FDB * pDb, - IXD_p pIxd, - IFD_p pIfd, + IXD * pIxd, + IFD * pIfd, void * pFld, void * pRootContext); @@ -658,7 +870,7 @@ RCODE KYVerifyMatchingPaths( RCODE KYTreeToKey( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, FlmRecord * pRecord, FLMUINT uiContainerNum, FLMBYTE * pKeyBuf, @@ -714,7 +926,7 @@ FLMBOOL KYEachWordParse( #define CJK_CHR 0x0010 // CJK word chr RCODE flmBuildFromAndUntilKeys( - IXD_p pIxd, + IXD * pIxd, QPREDICATE ** ppQPredicate, FLMBYTE * pFromKey, FLMUINT * puiFromKeyLen, @@ -767,7 +979,7 @@ void flmUnlockDbMutex( f_mutexUnlock( (pDb)->hShareMutex); FLMUINT flmGetDbTransType( - FDB_p pDb); + FDB * pDb); #define flmGetDbTransType( pDb) \ ((pDb)->uiTransType) @@ -794,7 +1006,7 @@ void fdbInitCS( FDB * pDb); RCODE fdbInit( - FDB_p pDb, + FDB * pDb, FLMUINT uiTransType, FLMUINT uiFlags, FLMUINT uiAutoTrans, @@ -878,13 +1090,13 @@ RCODE fdictGetIndex( FLMBOOL bInLimitedMode, FLMUINT uiIxdId, LFILE ** ppLFileRV, - IXD_p * ppIxdRV, + IXD ** ppIxdRV, FLMBOOL bOfflineOk = FALSE); RCODE fdictGetNextIXD( FDICT * pDict, FLMUINT uiIxdId, - IXD_p * ppIxdRV); + IXD ** ppIxdRV); RCODE fdictReadLFiles( FDB * pDb, @@ -911,7 +1123,7 @@ RCODE flmSendCSOp( CS_CONTEXT * pCSContext, FLMUINT uiClass, FLMUINT uiOp, - FDB_p pDb); + FDB * pDb); RCODE flmUnicodeToAscii( FLMUNICODE * puzString); @@ -921,14 +1133,14 @@ LFILE_STATS * fdbGetLFileStatPtr( LFILE * pLFile); RCODE flmIxKeyOutput( - IXD_p pIxd, + IXD * pIxd, FLMBYTE * pucFromKey, FLMUINT uiKeyLen, FlmRecord ** ppKeyRV, FLMBOOL bFullFldPaths); RCODE flmBuildKeyPaths( - IFD_p pIfd, + IFD * pIfd, FLMUINT uiFldNum, FLMUINT uiDataType, FLMBOOL bFullFldPaths, @@ -989,20 +1201,20 @@ RCODE BlkCheckSum( #define CHECKSUM_CHECK 1 #define IsInCSMode(pDb) \ - (FLMBOOL)((((FDB_p)pDb)->pCSContext != NULL) \ + (FLMBOOL)((((FDB *)pDb)->pCSContext != NULL) \ ? (FLMBOOL)TRUE \ : (FLMBOOL)FALSE) RCODE flmGetCSConnection( const char * pszUrlName, - CS_CONTEXT_p * ppCSContextRV); + CS_CONTEXT ** ppCSContextRV); void flmCloseCSConnection( - CS_CONTEXT_p * ppCSContext); + CS_CONTEXT ** ppCSContext); RCODE flmAllocHashTbl( FLMUINT uiHashTblSize, - FBUCKET_p * ppHashTblRV); + FBUCKET ** ppHashTblRV); RCODE flmGetTmpDir( char * pszOutputTmpDir); @@ -1016,40 +1228,40 @@ F_BKGND_IX * flmBackgroundIndexGet( FLMUINT flmBinHashBucket( void * pBuf, FLMUINT uiBufLen, - FBUCKET_p pHashTbl, + FBUCKET * pHashTbl, FLMUINT uiNumBuckets); RCODE flmWaitNotifyReq( F_MUTEX hMutex, - FNOTIFY_p * ppNotifyListRV, + FNOTIFY ** ppNotifyListRV, void * UserData); RCODE flmLinkFileToBucket( - FFILE_p pFile); + FFILE * pFile); void flmLinkFileToNUList( - FFILE_p pFile, + FFILE * pFile, FLMBOOL bQuickTimeout = FALSE); void flmUnlinkFileFromNUList( - FFILE_p pFile); + FFILE * pFile); void flmCheckNUStructs( FLMUINT uiCurrTime); void flmUnlinkDict( - FDICT_p pDict); + FDICT * pDict); void flmReleaseDict( FDB * pDb, FDICT * pDict); RCODE flmLinkFdbToFile( - FDB_p pDb, - FFILE_p pFile); + FDB * pDb, + FFILE * pFile); void flmUnlinkFdbFromFile( - FDB_p pDb); + FDB * pDb); void flmDoEventCallback( FEventCategory eCategory, @@ -1078,7 +1290,7 @@ void flmRcaExit( void); void flmRcaFindRec( FLMUINT uiContainer, FLMUINT uiDrn, - FFILE_p pFile, + FFILE * pFile, FLMUINT uiVersionNeeded, FLMBOOL bDontPoisonCache, FLMUINT * puiNumLooks, @@ -1092,7 +1304,7 @@ RCODE flmRcaRetrieveRec( FLMUINT uiContainer, FLMUINT uiDrn, FLMBOOL bOkToGetFromDisk, - BTSK_p pStack, + BTSK * pStack, LFILE * pLFile, FlmRecord ** ppRecord); @@ -1115,7 +1327,7 @@ RCODE flmRcaRemoveRec( FLMUINT uiDrn); void flmRcaFreeFileRecs( - FFILE_p pFile); + FFILE * pFile); void flmRcaAbortTrans( FDB * pDb); @@ -1177,10 +1389,10 @@ RCODE flmOpenFile( F_Restore * pRestoreObj, F_FileHdlImp * pLockFileHdl, const char * pszPassword, - FDB_p * ppDb); + FDB ** ppDb); RCODE flmCompleteOpenOrCreate( - FDB_p * ppDb, + FDB ** ppDb, RCODE rc, FLMBOOL bNewFile, FLMBOOL bAllocatedFdb); @@ -1195,21 +1407,21 @@ RCODE flmOpenOrCreateDbClientServer( CREATE_OPTS * pCreateOpts, FLMBOOL bOpening, CS_CONTEXT * pCSContext, - FDB_p * ppDb); + FDB ** ppDb); RCODE flmAllocFdb( - FDB_p * ppDb); + FDB ** ppDb); RCODE flmNewFileFinish( FFILE * pFile, RCODE OpenRc); RCODE flmUnregisterFile( - FFILE_p pFile ); + FFILE * pFile ); RCODE flmVerifyFileUse( F_MUTEX hMutex, - FFILE_p * ppFileRV); + FFILE ** ppFileRV); RCODE flmCreateLckFile( const char * pszFilePath, @@ -1222,17 +1434,20 @@ RCODE flmGetExclAccess( RCODE flmFindFile( const char * pDbPath, const char * pszDataDir, - FFILE_p * ppFileRV); + FFILE ** ppFileRV); RCODE flmAllocFile( const char * pDbPath, const char * pszDataDir, const char * pszDbPassword, - FFILE_p * ppFile); + FFILE ** ppFile); RCODE flmStartCPThread( FFILE * pFile); +RCODE flmStartDbMonitorThread( + FFILE * pFile); + RCODE flmStartMaintThread( FFILE * pFile); @@ -1248,9 +1463,9 @@ RCODE flmMaintFreeBlockChain( FLMUINT64 * pui64BlocksFreed); RCODE flmGetHdrInfo( - F_SuperFileHdl_p pSFileHdl, - FILE_HDR_p pFileHdrRV, - LOG_HDR_p pLogHdrRV, + F_SuperFileHdl * pSFileHdl, + FILE_HDR * pFileHdrRV, + LOG_HDR * pLogHdrRV, FLMBYTE * pLogHdr); void flmGetCreateOpts( @@ -1268,24 +1483,24 @@ FLMUINT flmAdjustBlkSize( void flmInitFileHdrInfo( CREATE_OPTS * pCreateOpts, - FILE_HDR_p pFileHdr, + FILE_HDR * pFileHdr, FLMBYTE * pFileHdrBuf); RCODE flmWriteVersionNum( - F_SuperFileHdl_p pSFileHdl, + F_SuperFileHdl * pSFileHdl, FLMUINT uiVersionNum); RCODE flmGetFileHdrInfo( FLMBYTE * pPrefixBuf, FLMBYTE * pFileHdrBuf, - FILE_HDR_p pFileHdrRV); + FILE_HDR * pFileHdrRV); RCODE flmReadAndVerifyHdrInfo( DB_STATS * pDbStats, F_FileHdl * pFileHdl, FLMBYTE * pReadBuf, - FILE_HDR_p pFileHdrRV, - LOG_HDR_p pLogHdrRV, + FILE_HDR * pFileHdrRV, + LOG_HDR * pLogHdrRV, FLMBYTE * pLogHdr); RCODE flmStartIndexBuild( @@ -1309,7 +1524,7 @@ void flmIndexingAfterAbort( RCODE flmLFileIndexBuild( FDB * pDb, LFILE * pIxLFile, - IXD_p pIxd, + IXD * pIxd, FLMBOOL bDoInBackground, FLMBOOL bCreateSuspended, FLMBOOL * pbLogCompleteIndexSet); @@ -1407,29 +1622,29 @@ RCODE tokenGetUnicode( RCODE expImpInit( F_FileHdl * pFileHdl, FLMUINT uiFlag, - EXP_IMP_INFO_p pExpImpInfoRV); + EXP_IMP_INFO * pExpImpInfoRV); #define EXPIMP_IMPORT_DICTIONARY 1 #define EXPIMP_EXPORT_DICTIONARY 2 #define EXPIMP_IMPORT_EXPORT_GEDCOM 3 void expImpFree( - EXP_IMP_INFO_p pExpImpInfo); + EXP_IMP_INFO * pExpImpInfo); RCODE expFlush( - EXP_IMP_INFO_p pExpImpInfo); + EXP_IMP_INFO * pExpImpInfo); RCODE expImpSeek( - EXP_IMP_INFO_p pExpImpInfo, + EXP_IMP_INFO * pExpImpInfo, FLMUINT uiSeekPos); RCODE expWriteRec( - EXP_IMP_INFO_p pExpImpInfo, + EXP_IMP_INFO * pExpImpInfo, FlmRecord * pRecord, FLMUINT uiDrn); RCODE impReadRec( - EXP_IMP_INFO_p pExpImpInfo, + EXP_IMP_INFO * pExpImpInfo, FlmRecord ** ppRecordRV); RCODE impFileIsExpImp( @@ -1480,7 +1695,7 @@ Desc: Extracts the information from a log header. ****************************************************************************/ FINLINE void flmGetLogHdrInfo( FLMBYTE * pucLogHdr, - LOG_HDR_p pLogHdr) + LOG_HDR * pLogHdr) { pLogHdr->uiCurrTransID = (FLMUINT)FB2UD( &pucLogHdr [LOG_CURR_TRANS_ID]); @@ -1707,7 +1922,7 @@ Desc: Flush all keys in KREF table, if any. This is called by routines flushed to the index. ****************************************************************************/ FINLINE RCODE KYFlushKeys( - FDB_p pDb) + FDB * pDb) { RCODE rc = FERR_OK; @@ -1820,19 +2035,20 @@ FINLINE RCODE flmCheckVersionNum( switch( uiVersionNum) { - case FLM_VER_3_0: - case FLM_VER_3_02: - case FLM_VER_3_10: - case FLM_VER_4_0: - case FLM_VER_4_3: - case FLM_VER_4_31: - case FLM_VER_4_50: - case FLM_VER_4_51: - case FLM_VER_4_52: - case FLM_VER_4_60: + case FLM_FILE_FORMAT_VER_3_0: + case FLM_FILE_FORMAT_VER_3_02: + case FLM_FILE_FORMAT_VER_3_10: + case FLM_FILE_FORMAT_VER_4_0: + case FLM_FILE_FORMAT_VER_4_3: + case FLM_FILE_FORMAT_VER_4_31: + case FLM_FILE_FORMAT_VER_4_50: + case FLM_FILE_FORMAT_VER_4_51: + case FLM_FILE_FORMAT_VER_4_52: + case FLM_FILE_FORMAT_VER_4_60: + case FLM_FILE_FORMAT_VER_4_61: break; default: - if( uiVersionNum > FLM_CURRENT_VERSION_NUM) + if( uiVersionNum > FLM_CUR_FILE_FORMAT_VER_NUM) { rc = RC_SET( FERR_NEWER_FLAIM); } @@ -1946,7 +2162,7 @@ Exit: /**************************************************************************** Desc: ****************************************************************************/ -typedef struct RSIxKeyTag +typedef struct RS_IX_KEY { FLMUINT uiRSIxNum; #define RS_KEY_OVERHEAD 6 @@ -1961,7 +2177,7 @@ typedef struct RSIxKeyTag /**************************************************************************** Desc: ****************************************************************************/ -typedef struct +typedef struct LF_HDR { LFILE * pLFile; IXD * pIxd; @@ -1972,7 +2188,7 @@ typedef struct /**************************************************************************** Desc: ****************************************************************************/ -typedef struct Db_Info +typedef struct DB_INFO { FILE_HDR FileHdr; LF_HDR * pLogicalFiles; @@ -1991,7 +2207,7 @@ typedef struct Db_Info /**************************************************************************** Desc: ****************************************************************************/ -typedef struct +typedef struct IX_CHK_INFO { POOL pool; FLMUINT uiIxCount; @@ -2007,10 +2223,12 @@ typedef struct FLMUINT uiRSIxRefCount; FLMUINT uiFlags; DB_INFO * pDbInfo; - } IX_CHK_INFO; -typedef struct State_Info +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct STATE_INFO { FLMUINT uiVersionNum; FDB * pDb; @@ -2051,6 +2269,7 @@ typedef struct State_Info #define FLM_FOP_NEXT_DRN 7 #define FLM_FOP_REC_INFO 8 #define FLM_FOP_ENCRYPTED 9 +#define FLM_FOP_LARGE 10 #define FLM_FOP_BAD 0xFF FLMUINT uiFieldLen; FLMUINT uiFieldProcessedLen; @@ -2071,13 +2290,19 @@ typedef struct State_Info FLMUINT uiEncFieldLen; } STATE_INFO; -typedef struct +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct HDR_INFO { FILE_HDR FileHdr; LOG_HDR LogHdr; } HDR_INFO; -typedef struct Rebuild_State +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct REBUILD_STATE { STATUS_HOOK fnStatusFunc; void * AppArg; @@ -2102,7 +2327,7 @@ RCODE flmCreateNewFile( const char * pszDictBuf, CREATE_OPTS * pCreateOpts, FLMUINT uiStartCheckpoint, - FDB_p * ppDb, + FDB ** ppDb, REBUILD_STATE * pvRebuildState = NULL); RCODE flmDbRebuildFile( @@ -2155,12 +2380,6 @@ eCorruptionType flmVerifyElement( eCorruptionType flmVerifyElmFOP( STATE_INFO * pStateInfo); -RCODE flmVerifyIXRefs( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiResetDrn, - eCorruptionType * piElmCorruptionCode); - void flmInitReadState( STATE_INFO * pStateInfo, FLMBOOL * pbStateInitialized, @@ -2171,6 +2390,25 @@ void flmInitReadState( FLMUINT uiBlkType, FLMBYTE * pKeyBuffer); +RCODE flmVerifyIXRefs( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiResetDrn, + eCorruptionType * piElmCorruptionCode); + +RCODE chkVerifyIXRSet( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIxRefDrn); + +RCODE chkResolveNonUniqueKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn); + RCODE flmGetRecKeys( FDB * pDb, IXD * pIxd, @@ -2180,72 +2418,6 @@ RCODE flmGetRecKeys( POOL * pPool, REC_KEY ** ppKeysRV); -RCODE chkVerifyIXRSet( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIxRefDrn); - -RCODE chkGetNextRSKey( - IX_CHK_INFO * pIxChkInfo); - -RCODE chkResolveIXMissingKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo); - -RCODE chkResolveNonUniqueKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn); - -RCODE chkRSInit( - const char * pszIoPath, - void ** pRSetRV); - -RCODE chkRSFinalize( - IX_CHK_INFO * pIxChkInfo, - FLMUINT64 * pui64TotalEntries); - -FLMINT chkCompareKeySet( - FLMUINT uiIxNum1, - FLMBYTE * pData1, - FLMUINT uiLength1, - FLMUINT uiDrn1, - FLMUINT uiIxNum2, - FLMBYTE * pData2, - FLMUINT uiLength2, - FLMUINT uiDrn2); - -RCODE chkBlkRead( - DB_INFO * pDbInfo, - FLMUINT uiBlkAddress, - LFILE * pLFile, - FLMBYTE ** ppBlk, - SCACHE ** ppSCache, - eCorruptionType * peCorruption); - -RCODE chkVerifyBTrees( - DB_INFO * pDbInfo, - POOL * pPool, - FLMBOOL * pbStartOverRV); - -RCODE chkReportError( - DB_INFO * pDbInfo, - eCorruptionType eCorruption, - eCorruptionLocale eErrLocale, - FLMUINT uiErrLfNumber, - FLMUINT uiErrLfType, - FLMUINT uiErrBTreeLevel, - FLMUINT uiErrBlkAddress, - FLMUINT uiErrParentBlkAddress, - FLMUINT uiErrElmOffset, - FLMUINT uiErrDrn, - FLMUINT uiErrElmRecOffset, - FLMUINT uiErrFieldNum, - FLMBYTE * pBlk); - #ifdef FLM_UNIX RCODE MapErrnoToFlaimErr( int err, @@ -2256,22 +2428,12 @@ void flmGetCPInfo( void * pFile, CHECKPOINT_INFO * pCheckpointInfo); -/**************************************************************************** -Desc: -****************************************************************************/ -FINLINE RCODE chkCallProgFunc( - DB_INFO * pDbInfo) -{ - if( (pDbInfo->fnStatusFunc) && (RC_OK( pDbInfo->LastStatusRc))) - { - pDbInfo->LastStatusRc = (*pDbInfo->fnStatusFunc)( FLM_CHECK_STATUS, - (void *)pDbInfo->pProgress, - (void *)0, - pDbInfo->pProgress->AppArg); - } - return( pDbInfo->LastStatusRc); -} - +RCODE flmSetRflSizeThreshold( + HFDB hDb, + FLMUINT uiSizeThreshold, + FLMUINT uiTimeInterval, + FLMUINT uiSizeInterval); + /**************************************************************************** Desc: The FlmBlobImp class provides support for database Binary Large ` Objects (BLOB). This class replaces the old 'C' FlmBlobXxx functions. @@ -2418,6 +2580,150 @@ FINLINE FLMUINT flmGetSigBits( return( uiSigBits); } +enum GRD_DifferenceType +{ + GRD_Inserted, + GRD_Deleted, + GRD_Modified, + GRD_DeletedSubtree +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct +{ + GRD_DifferenceType type; + // The 'type' indicates the nature + // of the difference, and can have one of the following values: + // GRD_Inserted: a field was inserted. In this case, the field only exists + // in the 'after record.' 'pAfterField' points to the + // inserted field. 'pBeforeField' == NULL. + // GRD_Deleted: a field was deleted. In this case, the field only exists in + // the 'before record'. 'pBeforeField' points to the + // deleted field. 'pAfterField' == NULL. + // GRD_Modified: a field was modified. In this case, 'pBeforeField' points + // to the field before it was modified, and 'pAfterField' + // points to the field after it was modified. + // GRD_DeletedSubtree: a sub-tree was deleted. In this case, the sub-tree only exists in + // the 'before record'. 'pBeforeField' points to the + // deleted sub-tree. 'pAfterField' == NULL + + FLMUINT uiAbsolutePosition; + // 'uiAbsolutePosition' is the 1-based position where the difference occured. + // When using the list of differences generated by flmRecordDifference to + // undo changes, uiAbsolutePosition can be thought of as the 1-based position + // relative to the 'after record.' In order for 'undo' to work correctly, + // the differences must be undone in reverse order. + // + // When using the list of differences to redo changes, uiAbsolutePosition + // can be thought of as the 1-based position relative to the 'before + // record.' In order for 'redo' to work correctly, the differences must be + // redone in order. Note that when a node is inserted or deleted, all + // subsequent nodes are, in essence, renumbered. + + FlmRecord * pBeforeRecord; + + FlmRecord * pAfterRecord; + + void * pvBeforeField; + // 'pvBeforeField' is a pointer to the field before the change. + // There are situations where 'pBeforeField' will be NULL. + // See a description of the 'type' for more details. + + void * pvAfterField; + // 'pvAfterField' is a pointer to the field after the change. There are + // situations where 'pBeforeField' will be NULL. See a description + // of the 'type' for more details. +} GRD_DifferenceData; + + +typedef void (* GRD_CallBackFunction)( // Called for each difference found + GRD_DifferenceData & difference, // Description of difference + void * pCallBackData); // User-defined data + +void flmRecordDifference( + FlmRecord * pBeforeRecord, + FlmRecord * pAfterRecord, + GRD_CallBackFunction pCallBackFunction, + void * pvCallBackData); + +/**************************************************************************** +Desc: The F_FSRestore class is used to read backup and RFL files from + a disk file system. +****************************************************************************/ +class F_FSRestore : public F_Restore +{ +public: + + F_FSRestore(); + + virtual ~F_FSRestore(); + + RCODE setup( + const char * pucDbPath, + const char * pucBackupSetPath, + const char * pucRflDir); + + RCODE openBackupSet( void); + + RCODE openIncFile( + FLMUINT uiFileNum); + + RCODE openRflFile( + FLMUINT uiFileNum); + + RCODE read( + FLMUINT uiLength, + void * pvBuffer, + FLMUINT * puiBytesRead); + + RCODE close( void); + + FINLINE RCODE abortFile( void) + { + return( close()); + } + + FINLINE RCODE processUnknown( + F_UnknownStream * pUnkStrm) + { + // Skip any unknown data in the RFL + + return( pUnkStrm->close()); + } + + FINLINE RCODE status( + eRestoreStatusType eStatusType, + FLMUINT uiTransId, + void * pvValue1, + void * pvValue2, + void * pvValue3, + eRestoreActionType * peRestoreAction) + { + F_UNREFERENCED_PARM( eStatusType); + F_UNREFERENCED_PARM( uiTransId); + F_UNREFERENCED_PARM( pvValue1); + F_UNREFERENCED_PARM( pvValue2); + F_UNREFERENCED_PARM( pvValue3); + + *peRestoreAction = RESTORE_ACTION_CONTINUE; + return( FERR_OK); + } + +private: + + F_FileHdlImp * m_pFileHdl; + F_64BitFileHandle * m_pFileHdl64; + FLMUINT64 m_ui64Offset; + FLMUINT m_uiDbVersion; + char m_szDbPath[ F_PATH_MAX_SIZE]; + char m_szBackupSetPath[ F_PATH_MAX_SIZE]; + char m_szRflDir[ F_PATH_MAX_SIZE]; + FLMBOOL m_bSetupCalled; + FLMBOOL m_bOpen; +}; + #include "fpackoff.h" #endif diff --git a/flaim/src/flbackup.cpp b/flaim/src/flbackup.cpp index b001828..a188837 100644 --- a/flaim/src/flbackup.cpp +++ b/flaim/src/flbackup.cpp @@ -212,7 +212,7 @@ FLMEXP RCODE FLMAPI FlmDbBackupBegin( goto Exit; } - if( uiDbVersion < FLM_VER_4_3 && + if( uiDbVersion < FLM_FILE_FORMAT_VER_4_3 && eBackupType != FLM_FULL_BACKUP) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -292,7 +292,7 @@ FLMEXP RCODE FLMAPI FlmDbBackupBegin( // set of incremental backup files from being applied // to a database. - if( uiDbVersion >= FLM_VER_4_3) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { if( !pFBak->bCSMode) { @@ -322,7 +322,7 @@ FLMEXP RCODE FLMAPI FlmDbBackupBegin( // Get version 4.3+ values from the header - if( uiDbVersion >= FLM_VER_4_3) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { // Determine the transaction ID of the last backup @@ -410,9 +410,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Returns information about a backup -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmBackupGetConfig( HFBACKUP hBackup, eBackupGetConfigType eConfigType, @@ -449,14 +449,14 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Streams the contents of a database to the write hook supplied by the application. Notes: This routine attempts to create a backup of a database without excluding any readers or updaters. However, if the backup runs too long in an environment where extensive updates are happening, an old view error could be returned. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbBackup( HFBACKUP hBackup, const char * pszBackupPath, @@ -464,8 +464,7 @@ FLMEXP RCODE FLMAPI FlmDbBackup( BACKER_WRITE_HOOK fnWrite, STATUS_HOOK fnStatus, void * pvAppData, - FLMUINT * puiIncSeqNum - ) + FLMUINT * puiIncSeqNum) { FDB * pDb = NULL; FLMBOOL bDbInitialized = FALSE; @@ -647,7 +646,7 @@ FLMEXP RCODE FLMAPI FlmDbBackup( // Fix up the log header - if( !pLogHdr[ LOG_KEEP_RFL_FILES] || pFBak->uiDbVersion < FLM_VER_4_3) + if( !pLogHdr[ LOG_KEEP_RFL_FILES] || pFBak->uiDbVersion < FLM_FILE_FORMAT_VER_4_3) { pLogHdr[ LOG_KEEP_RFL_FILES] = 0; @@ -662,7 +661,7 @@ FLMEXP RCODE FLMAPI FlmDbBackup( // Create new serial numbers for the RFL. We don't want anyone // to be able to branch into a "no-keep" RFL sequence. - if( pFBak->uiDbVersion >= FLM_VER_4_3) + if( pFBak->uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { if (RC_BAD( rc = f_createSerialNumber( &pLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM]))) @@ -689,7 +688,7 @@ FLMEXP RCODE FLMAPI FlmDbBackup( // Shroud the database key (stored in the log header) in the password // so we can restore this backup to a different server - if ( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_60 && + if ( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60 && pszPassword && *pszPassword && FB2UW( &pLogHdr[ LOG_DATABASE_KEY_LEN]) > 0) { @@ -704,14 +703,25 @@ FLMEXP RCODE FLMAPI FlmDbBackup( goto Exit; } - // IMPORTANT NOTE: pucTmpBuf must be freed before going to Exit!!! - - // Assert that the field in the log header is long enough to - // hold the key. Note: This test is only valid if the key - // field is the last one in the log header!! - - flmAssert( ui32KeyLen <= (LOG_HEADER_SIZE - LOG_DATABASE_KEY)); + // Verify that the field in the log header is long enough to + // hold the key. + + if( ui32KeyLen > FLM_MAX_DB_ENC_KEY_LEN) + { + rc = RC_SET_AND_ASSERT( FERR_BAD_ENC_KEY); + goto Exit; + } + // Verify that the field in the log header is long enough to + // hold the key. + + if( ui32KeyLen > FLM_MAX_DB_ENC_KEY_LEN) + { + f_free( &pucTmpBuf); + rc = RC_SET_AND_ASSERT( FERR_BAD_ENC_KEY); + goto Exit; + } + UW2FBA( ui32KeyLen, &pLogHdr[ LOG_DATABASE_KEY_LEN]); f_memcpy( &pLogHdr[ LOG_DATABASE_KEY], pucTmpBuf, ui32KeyLen); f_free( &pucTmpBuf); @@ -972,9 +982,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Ends the backup, updating the log header if needed. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbBackupEnd( HFBACKUP * phBackup) { @@ -998,7 +1008,7 @@ FLMEXP RCODE FLMAPI FlmDbBackupEnd( // Update log header fields if( pFBak->bCompletedBackup && - pFBak->uiDbVersion >= FLM_VER_4_3) + pFBak->uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { // Start an update transaction. @@ -1156,9 +1166,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Restores a database and supporting files. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbRestore( const char * pszDbPath, const char * pszDataDir, @@ -1342,7 +1352,7 @@ FLMEXP RCODE FLMAPI FlmDbRestore( // Apply any available incremental backups. uiNextIncNum will be 0 if // the database version does not support incremental backups. - if( uiNextIncNum && uiDbVersion >= FLM_VER_4_3) + if( uiNextIncNum && uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { FLMUINT uiCurrentIncNum; @@ -1461,7 +1471,7 @@ FLMEXP RCODE FLMAPI FlmDbRestore( rc = flmOpenFile( pFile, pszDbPath, pszDataDir, pszRflDir, FO_DONT_RESUME_BACKGROUND_THREADS, - TRUE, pRestoreObj, pLockFileHdl, NULL, (FDB_p *)&hDb); + TRUE, pRestoreObj, pLockFileHdl, NULL, (FDB **)&hDb); pLockFileHdl = NULL; pFile = NULL; @@ -1553,7 +1563,7 @@ Exit: /*************************************************************************** Desc : Restores a full or incremental backup -*END************************************************************************/ +****************************************************************************/ FSTATIC RCODE flmRestoreFile( F_Restore * pRestoreObj, const char * pszPassword, @@ -1682,22 +1692,21 @@ FSTATIC RCODE flmRestoreFile( if( FB2UD( &pucBlkBuf[ FLM_BACKER_VERSION_OFFSET]) != FLM_BACKER_VERSION) { - rc = RC_SET( FERR_UNSUPPORTED_VERSION); + rc = RC_SET_AND_ASSERT( FERR_UNSUPPORTED_VERSION); goto Exit; } if( f_strncmp( (const char *)&pucBlkBuf[ FLM_BACKER_SIGNATURE_OFFSET], FLM_BACKER_SIGNATURE, FLM_BACKER_SIGNATURE_SIZE) != 0) { - rc = RC_SET( FERR_UNSUPPORTED_VERSION); + rc = RC_SET_AND_ASSERT( FERR_UNSUPPORTED_VERSION); goto Exit; } uiBlockSize = (FLMUINT)FB2UW( &pucBlkBuf[ FLM_BACKER_DB_BLOCK_SIZE_OFFSET]); if( uiBlockSize > FLM_BACKER_MAX_DB_BLOCK_SIZE) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -1709,8 +1718,7 @@ FSTATIC RCODE flmRestoreFile( if( FB2UD( &pucBlkBuf[ FLM_BACKER_MTU_OFFSET]) != FLM_BACKER_MTU_SIZE) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -1770,8 +1778,7 @@ FSTATIC RCODE flmRestoreFile( if( uiBlockSize != FB2UD( &pucBlkBuf[ FLAIM_HEADER_START + DB_BLOCK_SIZE])) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -1789,8 +1796,7 @@ FSTATIC RCODE flmRestoreFile( if( (FLMUINT)FB2UW( &pLogHdr[ LOG_FLAIM_VERSION]) != uiDbVersion) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } uiMaxFileSize = flmGetMaxFileSize( uiDbVersion, pLogHdr); @@ -1812,8 +1818,7 @@ FSTATIC RCODE flmRestoreFile( if( uiBackupMaxFileSize != uiMaxFileSize) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -1823,7 +1828,7 @@ FSTATIC RCODE flmRestoreFile( // create the F_CCS object when it initializes the FFILE.) if( pszPassword && *pszPassword && - FB2UD( &pLogHdr[ LOG_FLAIM_VERSION]) >= FLM_VER_4_60 && + FB2UD( &pLogHdr[ LOG_FLAIM_VERSION]) >= FLM_FILE_FORMAT_VER_4_60 && FB2UW( &pLogHdr[ LOG_DATABASE_KEY_LEN]) > 0 ) { FLMBYTE * pucTmpBuf = NULL; @@ -1855,13 +1860,15 @@ FSTATIC RCODE flmRestoreFile( goto Exit; } - // IMPORTANT NOTE: pucTmpBuf must be freed before going to Exit!!! - - // Assert that the field in the log header is long enough to - // hold the key. Note: This test is only valid if the key - // field is the last one in the log header!! - - flmAssert( ui32KeyLen <= (LOG_HEADER_SIZE - LOG_DATABASE_KEY)); + // Verify that the field in the log header is long enough to + // hold the key. + + if( ui32KeyLen > FLM_MAX_DB_ENC_KEY_LEN) + { + f_free( &pucTmpBuf); + rc = RC_SET_AND_ASSERT( FERR_BAD_ENC_KEY); + goto Exit; + } UW2FBA( ui32KeyLen, &pLogHdr[ LOG_DATABASE_KEY_LEN]); f_memcpy( &pLogHdr[LOG_DATABASE_KEY], pucTmpBuf, ui32KeyLen); @@ -1883,14 +1890,14 @@ FSTATIC RCODE flmRestoreFile( goto Exit; } - f_memcpy( *ppucKeyToSave, &pLogHdr[LOG_DATABASE_KEY], ui32KeyLen); + f_memcpy( *ppucKeyToSave, &pLogHdr[ LOG_DATABASE_KEY], ui32KeyLen); *puiKeyLen = ui32KeyLen; } } else if( pucKeyToUse) { - UW2FBA( *puiKeyLen, &pLogHdr[LOG_DATABASE_KEY_LEN]); - f_memcpy( &pLogHdr[LOG_DATABASE_KEY], pucKeyToUse, *puiKeyLen); + UW2FBA( *puiKeyLen, &pLogHdr[ LOG_DATABASE_KEY_LEN]); + f_memcpy( &pLogHdr[ LOG_DATABASE_KEY], pucKeyToUse, *puiKeyLen); } // Get the logical EOF from the log header @@ -1979,7 +1986,7 @@ FSTATIC RCODE flmRestoreFile( // so, the log header will contain the correct serial number for a // subsequent incremental backup that may have been made. - if( uiDbVersion >= FLM_VER_4_3) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { f_memcpy( &pLogHdr[ LOG_INC_BACKUP_SERIAL_NUM], ucNextIncSerialNum, F_SERIAL_NUM_SIZE); @@ -2040,8 +2047,7 @@ FSTATIC RCODE flmRestoreFile( !FSAddrIsBelow( uiBlkAddr, uiLogicalEOF) || (uiPriorBlkAddr && !FSAddrIsBelow( uiPriorBlkAddr, uiBlkAddr))) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -2049,8 +2055,7 @@ FSTATIC RCODE flmRestoreFile( if( uiActualBlkSize > uiBlockSize || uiActualBlkSize < BH_OVHD) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -2061,8 +2066,7 @@ FSTATIC RCODE flmRestoreFile( if( (GET_BH_ADDR( pucBlkBuf) & 0xFFFFFF00) != (uiBlkAddr & 0xFFFFFF00)) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -2081,8 +2085,7 @@ FSTATIC RCODE flmRestoreFile( { if( rc == FERR_BLOCK_CHECKSUM) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); } goto Exit; @@ -2118,8 +2121,7 @@ FSTATIC RCODE flmRestoreFile( if( FSGetFileNumber( uiBlkAddr) != (uiPriorBlkFile + 1)) { - flmAssert( 0); - rc = RC_SET( FERR_INCONSISTENT_BACKUP); + rc = RC_SET_AND_ASSERT( FERR_INCONSISTENT_BACKUP); goto Exit; } @@ -2899,3 +2901,294 @@ Exit: f_semSignal( pBackerStream->m_hIdleSem); return( rc); } + +/**************************************************************************** +Desc: +****************************************************************************/ +F_FSRestore::F_FSRestore() +{ + m_pFileHdl = NULL; + m_pFileHdl64 = NULL; + m_ui64Offset = 0; + m_bSetupCalled = FALSE; + m_szDbPath[ 0] = 0; + m_uiDbVersion = 0; + m_szBackupSetPath[ 0] = 0; + m_szRflDir[ 0] = 0; + m_bOpen = FALSE; +} + +/**************************************************************************** +Desc: +****************************************************************************/ +F_FSRestore::~F_FSRestore() +{ + if( m_bOpen) + { + (void)close(); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::setup( + const char * pucDbPath, + const char * pucBackupSetPath, + const char * pucRflDir) +{ + flmAssert( !m_bSetupCalled); + flmAssert( pucDbPath); + flmAssert( pucBackupSetPath); + + f_strcpy( m_szDbPath, pucDbPath); + f_strcpy( m_szBackupSetPath, pucBackupSetPath); + + if( pucRflDir) + { + f_strcpy( m_szRflDir, pucRflDir); + } + + + m_bSetupCalled = TRUE; + return( FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::openBackupSet( void) +{ + RCODE rc = FERR_OK; + + flmAssert( m_bSetupCalled); + flmAssert( !m_pFileHdl64); + + if( (m_pFileHdl64 = f_new F_64BitFileHandle) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if( RC_BAD( rc = m_pFileHdl64->Open( m_szBackupSetPath))) + { + m_pFileHdl64->Release(); + m_pFileHdl64 = NULL; + goto Exit; + } + + m_ui64Offset = 0; + m_bOpen = TRUE; + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::openRflFile( + FLMUINT uiFileNum) +{ + RCODE rc = FERR_OK; + char szRflPath[ F_PATH_MAX_SIZE]; + char szDbPrefix[ F_FILENAME_SIZE]; + char szBaseName[ F_FILENAME_SIZE]; + FLMBYTE * pBuf = NULL; + FILE_HDR fileHdr; + LOG_HDR logHdr; + F_FileHdl * pFileHdl = NULL; + + flmAssert( m_bSetupCalled); + flmAssert( uiFileNum); + flmAssert( !m_pFileHdl); + + // Read the database header to determine the version number + + if( !m_uiDbVersion) + { + if (RC_BAD( rc = f_alloc( 2048, &pBuf))) + { + goto Exit; + } + + if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( + m_szDbPath, F_IO_RDWR | F_IO_SH_DENYNONE, &pFileHdl))) + { + goto Exit; + } + + if( RC_BAD( rc = flmReadAndVerifyHdrInfo( NULL, pFileHdl, + pBuf, &fileHdr, &logHdr, NULL))) + { + goto Exit; + } + + pFileHdl->Close(); + pFileHdl->Release(); + pFileHdl = NULL; + + m_uiDbVersion = fileHdr.uiVersionNum; + } + + /* + Generate the log file name. + */ + + if( RC_BAD( rc = rflGetDirAndPrefix( + m_uiDbVersion, m_szDbPath, m_szRflDir, szRflPath, szDbPrefix))) + { + goto Exit; + } + + rflGetBaseFileName( m_uiDbVersion, szDbPrefix, uiFileNum, szBaseName); + f_pathAppend( szRflPath, szBaseName); + + /* + Open the file. + */ + + if( RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( + szRflPath, F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, + 512, &m_pFileHdl))) + { + goto Exit; + } + + m_bOpen = TRUE; + m_ui64Offset = 0; + +Exit: + + if( pBuf) + { + f_free( &pBuf); + } + + if( pFileHdl) + { + pFileHdl->Release(); + } + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::openIncFile( + FLMUINT uiFileNum) +{ + RCODE rc = FERR_OK; + char szIncPath[ F_PATH_MAX_SIZE]; + char szIncFile[ F_FILENAME_SIZE]; + + flmAssert( m_bSetupCalled); + flmAssert( !m_pFileHdl64); + + /* + Since this is a non-interactive restore, we will "guess" + that incremental backups are located in the same parent + directory as the main backup set. We will further assume + that the incremental backup sets have been named XXXXXXXX.INC, + where X is a hex digit. + */ + + if( RC_BAD( rc = f_pathReduce( m_szBackupSetPath, + szIncPath, NULL))) + { + goto Exit; + } + + f_sprintf( szIncFile, "%08X.INC", (unsigned)uiFileNum); + f_pathAppend( szIncPath, szIncFile); + + if( (m_pFileHdl64 = f_new F_64BitFileHandle) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if( RC_BAD( rc = m_pFileHdl64->Open( szIncPath))) + { + m_pFileHdl64->Release(); + m_pFileHdl64 = NULL; + goto Exit; + } + + m_ui64Offset = 0; + m_bOpen = TRUE; + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::read( + FLMUINT uiLength, + void * pvBuffer, + FLMUINT * puiBytesRead) +{ + FLMUINT uiBytesRead = 0; + RCODE rc = FERR_OK; + + flmAssert( m_bSetupCalled); + flmAssert( m_pFileHdl || m_pFileHdl64); + + if( m_pFileHdl64) + { + if( RC_BAD( rc = m_pFileHdl64->Read( m_ui64Offset, + uiLength, pvBuffer, &uiBytesRead))) + { + goto Exit; + } + } + else + { + if( RC_BAD( rc = m_pFileHdl->Read( (FLMUINT)m_ui64Offset, + uiLength, pvBuffer, &uiBytesRead))) + { + goto Exit; + } + } + +Exit: + + m_ui64Offset += uiBytesRead; + + if( puiBytesRead) + { + *puiBytesRead = uiBytesRead; + } + + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_FSRestore::close( void) +{ + flmAssert( m_bSetupCalled); + + if( m_pFileHdl64) + { + m_pFileHdl64->Release(); + m_pFileHdl64 = NULL; + } + + if( m_pFileHdl) + { + m_pFileHdl->Release(); + m_pFileHdl = NULL; + } + + m_bOpen = FALSE; + m_ui64Offset = 0; + + return( FERR_OK); +} diff --git a/flaim/src/flblddb.cpp b/flaim/src/flblddb.cpp deleted file mode 100644 index 397e22c..0000000 --- a/flaim/src/flblddb.cpp +++ /dev/null @@ -1,2063 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Rebuild corrupted database. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flblddb.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -typedef struct Container_Info -{ - FLMUINT uiHighetstDrnFound; - FLMUINT uiHighestNextDrnFound; - FLMUINT uiNumNextDrnsFound; - FLMBOOL bCountEstimated; -} CONTAINER_INFO, * CONTAINER_INFO_p; - -typedef struct RECOV_DICT_REC -{ - FlmRecord * pRec; - FLMUINT uiBlkAddress; - FLMUINT uiElmOffset; - FLMBOOL bAdded; - FLMBOOL bGotFromDataRec; - RECOV_DICT_REC * pNext; -} RECOV_DICT_REC; - -typedef struct -{ - RECOV_DICT_REC * pRecovRecs; - POOL pool; -} RECOV_DICT_INFO; - -FSTATIC RCODE bldAdjustNextDrn( - FDB * pDb, - LFILE * pLFile, - CONTAINER_INFO * pContInfo); - -FSTATIC RCODE bldRecovData( - FDB * pDb, - REBUILD_STATE * pRebuildState, - CONTAINER_INFO * pContainerInfo, - FLMBOOL bRecovDictRecs, - FLMBOOL * pbStartedTransRV); - -FSTATIC RCODE bldCheckBlock( - STATE_INFO * pStateInfo, - HDR_INFO * pHdrInfo, - FLMUINT uiBlkAddress, - FLMUINT uiPrevBlkAddress, - eCorruptionType * peCorruptionCode); - -FSTATIC RCODE bldExtractRecs( - FDB * pDb, - REBUILD_STATE * pRebuildState, - LFILE * pLFile, - CONTAINER_INFO * pContInfo, - FLMUINT uiBlkAddress, - LF_HDR * pLogicalFile, - FLMBOOL bRecovDictRecs, - RECOV_DICT_INFO ** ppRecovDictInfoRV); - -FSTATIC RCODE bldGetNextElm( - REBUILD_STATE * pRebuildState, - STATE_INFO * pStateInfo, - FLMBOOL * pbGotNextElmRV, - FLMBOOL * pbGotNewBlockRV); - -FSTATIC RCODE bldGetOneRec( - FDB * pDb, - REBUILD_STATE * pRebuildState, - STATE_INFO * pStateInfo, - FLMBOOL bRecovDictRecs, - FLMBOOL * pbGotNewBlockRV, - FLMBOOL * pbGotRecord); - -FSTATIC RCODE bldSaveRecovDictRec( - FDB * pDb, - RECOV_DICT_INFO ** ppRecovDictInfoRV, - FlmRecord * pRecord, - FLMUINT uiDrn, - FLMBOOL bGotFromDataRec, - FLMUINT uiBlkAddress, - FLMUINT uiElmOffset); - -FSTATIC void bldFreeRecovDictInfo( - RECOV_DICT_INFO * pRecovDictInfo); - -FSTATIC RCODE bldDoDict( - FDB * pDb, - REBUILD_STATE * pRebuildState, - RECOV_DICT_INFO * pDictToDo, - FLMBOOL * pbStartedTransRV); - -/*************************************************************************** -Desc: This routine adds all of the recovered dictionary records to their - appropriate dictionaries. -****************************************************************************/ -FINLINE RCODE bldAddRecovDictRecs( - FDB * pDb, - REBUILD_STATE * pRebuildState, - RECOV_DICT_INFO ** ppDictListRV, - FLMBOOL * pbStartedTransRV) -{ - RECOV_DICT_INFO * pDict; - - if( (pDict = *ppDictListRV) != NULL) - { - *ppDictListRV = NULL; - return bldDoDict( pDb, pRebuildState, pDict, pbStartedTransRV); - } - - return FERR_OK; -} - -/*************************************************************************** -Desc: Setup corrupt info structure prior to calling status callback -****************************************************************************/ -FINLINE RCODE bldReportReason( - REBUILD_STATE * pRebuildState, - eCorruptionType eCorruption, - FLMUINT uiErrBlkAddress, - FLMUINT uiErrElmOffset, - FLMUINT uiErrDrn, - FLMUINT uiErrElmRecOffset, - FLMUINT uiErrFieldNum) -{ - RCODE rc = FERR_OK; - - if( pRebuildState->fnStatusFunc) - { - pRebuildState->CorruptInfo.eCorruption = eCorruption; - pRebuildState->CorruptInfo.uiErrBlkAddress = uiErrBlkAddress; - pRebuildState->CorruptInfo.uiErrElmOffset = uiErrElmOffset; - pRebuildState->CorruptInfo.uiErrDrn = uiErrDrn; - pRebuildState->CorruptInfo.uiErrElmRecOffset = uiErrElmRecOffset; - pRebuildState->CorruptInfo.uiErrFieldNum = uiErrFieldNum; - rc = (*pRebuildState->fnStatusFunc)( FLM_PROBLEM_STATUS, - (void *)&pRebuildState->CorruptInfo, - (void *)0, pRebuildState->AppArg); - pRebuildState->CorruptInfo.eCorruption = FLM_NO_CORRUPTION; - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine determines whether or not a container should be done. -****************************************************************************/ -FINLINE FLMBOOL bldDoContainer( - FLMUINT uiContainerNum, - FLMBOOL bDoDictContainers) -{ - if (!bDoDictContainers) - { - switch (uiContainerNum) - { - case FLM_DICT_CONTAINER: - return( FALSE); - case FLM_DATA_CONTAINER: - return( TRUE); - default: - if (uiContainerNum < FLM_RESERVED_TAG_NUMS) - { - return( TRUE); - } - else - { - return( FALSE); - } - } - } - - return( TRUE); -} - -/*************************************************************************** -Desc: Reads through a database, extracts data records from all containers - and puts them into the database specified by hDb. It is - assumed that the new database has the same containers as the old - database. -****************************************************************************/ -RCODE flmDbRebuildFile( - REBUILD_STATE * pRebuildState, // Rebuild state information. - FLMBOOL bBadHeader // Was file's header or log header - // information bad? - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiCurrLf; - FLMBOOL bFdbInitialized = FALSE; - FLMBOOL bStartedTrans = FALSE; - LFILE * pLFile; - FLMUINT uiTemp; - FLMUINT uiContainerNum; - CONTAINER_INFO * pContainerInfo = NULL; - CONTAINER_INFO * pContInfo; - FDB * pDb = (FDB_p)pRebuildState->hDb; - - pRebuildState->CorruptInfo.eErrLocale = LOCALE_B_TREE; - pRebuildState->CorruptInfo.uiErrLfType = LF_CONTAINER; - - bFdbInitialized = TRUE; - if (RC_BAD( fdbInit( pDb, FLM_UPDATE_TRANS, - FDB_DONT_RESET_DIAG, - FLM_AUTO_TRANS | 5, &bStartedTrans))) - { - goto Exit; - } - - if( RC_BAD( rc = f_alloc( pRebuildState->pHdrInfo->FileHdr.uiBlockSize, - &pRebuildState->pBlk))) - { - goto Exit; - } - - // Do a first pass to recover any dictionary items that may not have - // been added from the dictionary file that was passed into the rebuild - // function. - - if( RC_BAD( rc = bldRecovData( pDb, pRebuildState, pContainerInfo, TRUE, - &bStartedTrans))) - { - goto Exit; - } - - // Reset records recovered to zero after dictionary pass. - - pRebuildState->CallbackData.uiRecsRecov = 0; - - // Allocate an array of structures to keep information on each - // container. - - if( RC_BAD( rc = f_calloc( - (FLMUINT)( sizeof( CONTAINER_INFO) * pDb->pDict->uiLFileCnt), - &pContainerInfo))) - { - goto Exit; - } - - if( RC_BAD( rc = bldRecovData( pDb, pRebuildState, pContainerInfo, FALSE, - &bStartedTrans))) - { - goto Exit; - } - - // Adjust the next DRN for all containers so that they are at least as high - // as the next DRN in the containers we were rebuilding from. - - for( uiCurrLf = 0, - pContInfo = pContainerInfo, - pLFile = (LFILE *)pDb->pDict->pLFileTbl; - uiCurrLf < pDb->pDict->uiLFileCnt; - uiCurrLf++, pLFile++, pContInfo++) - { - if (pLFile->uiLfType == LF_CONTAINER) - { - uiContainerNum = pLFile->uiLfNum; - if (bldDoContainer( uiContainerNum, FALSE)) - { - if (RC_BAD( rc = bldAdjustNextDrn( pDb, pLFile, pContInfo))) - { - goto Exit; - } - } - } - } - - // Preserve other things in the log header that we ought - // to try and preserve. - - if( !bBadHeader) - { - FLMBYTE * pucLogHdr = &pDb->pFile->ucUncommittedLogHdr [0]; - - // Set the commit count one less than the old database's - // This is because it will be incremented if the transaction - // successfully commits - which will make it exactly right. - - uiTemp = (FLMUINT)FB2UD( &pRebuildState->pLogHdr [LOG_COMMIT_COUNT]) - 1; - if ((FLMUINT)FB2UD( &pucLogHdr [LOG_COMMIT_COUNT]) < uiTemp) - { - UD2FBA( (FLMUINT32)uiTemp, &pucLogHdr [LOG_COMMIT_COUNT]); - } - } - - // Signal the we are finished the rebuild - - if (pRebuildState->fnStatusFunc) - { - pRebuildState->CallbackData.iDoingFlag = REBUILD_FINISHED; - - pRebuildState->CallbackData.bStartFlag = TRUE; - - if (RC_BAD( rc = (*pRebuildState->fnStatusFunc)( FLM_REBUILD_STATUS, - (void *)&pRebuildState->CallbackData, - (void *)0, - pRebuildState->AppArg))) - { - goto Exit; - } - pRebuildState->CallbackData.bStartFlag = FALSE; - } - -Exit: - - if (pContainerInfo) - { - f_free( &pContainerInfo); - } - - if (pRebuildState->pBlk) - { - f_free( &pRebuildState->pBlk); - } - - if (bStartedTrans) - { - if (rc == FERR_OK) - { - rc = flmCommitDbTrans( pDb, 0, TRUE); - } - else - { - (void)flmAbortDbTrans( pDb); - } - } - - if (bFdbInitialized) - { - fdbExit( pDb); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine adjusts the next DRN for a container so that it - is at least as high as the DRN in the file we are rebuilding - from. -****************************************************************************/ -FSTATIC RCODE bldAdjustNextDrn( - FDB * pDb, - LFILE * pLFile, - CONTAINER_INFO * pContInfo) -{ - RCODE rc; - FLMUINT uiNextDrn; - BTSK StackBuf [BH_MAX_LEVELS]; - FLMBOOL bUsedStack = FALSE; - - // First see what the next DRN is currently set to - - uiNextDrn = 0; - if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, FALSE, &uiNextDrn))) - { - goto Exit; - } - - // Adjust the next DRN to be at least as high as the highest DRN - // in the old databaseor the highest next DRN found int the - // old database. - - if( uiNextDrn < pContInfo->uiHighetstDrnFound) - { - uiNextDrn = pContInfo->uiHighetstDrnFound + 1; - } - - if( uiNextDrn < pContInfo->uiHighestNextDrnFound) - { - uiNextDrn = pContInfo->uiHighestNextDrnFound; - } - - // Add either 100 or 1000 to next record number - just in case - // things weren't as accurate as they should have been in the - // old database. We want to make sure the next record - // number is high enough to avoid accidentally reusing any - // records which may have been used in the old database. - - uiNextDrn += ((pContInfo->uiNumNextDrnsFound != 1) ? 1000 : 100); - - // If there is no root block, the next DRN is stored inside the - // logical file header. Otherwise, it is stored in the rightmost - // element of the B-Tree - the one with a DRN of DRN_LAST_MARKER. - - if( pLFile->uiRootBlk == BT_END) - { - // LFILE is up to date from previously calling FSGetNxtDrn - - pLFile->uiNextDrn = uiNextDrn; - if (RC_BAD( rc = flmLFileWrite( pDb, pLFile))) - { - goto Exit; - } - } - else - { - BTSK_p pStack = StackBuf; - FLMBYTE KeyBuf [DIN_KEY_SIZ + 4]; - FLMBYTE DrnMarker [DIN_KEY_SIZ]; - FLMBYTE * pNextDrnBuf; - - // Set up the stack - - FSInitStackCache( &StackBuf [0], BH_MAX_LEVELS); - bUsedStack = TRUE; - pStack->pKeyBuf = KeyBuf; - - // Find the element whose DRN is DRN_LAST_MARKER - - flmUINT32ToBigEndian( (FLMUINT32)DRN_LAST_MARKER, DrnMarker); - if( RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, DrnMarker, - DIN_KEY_SIZ, 0))) - { - goto Exit; - } - - // Log the block before modifying it - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - { - goto Exit; - } - - pNextDrnBuf = CURRENT_ELM( pStack); - pNextDrnBuf += BBE_GETR_KL( pNextDrnBuf ) + BBE_KEY; - - // Update with the next DRN value and dirty the block - - UD2FBA( (FLMUINT32)uiNextDrn, pNextDrnBuf ); - } - -Exit: - - if( bUsedStack) - { - FSReleaseStackCache( StackBuf, BH_MAX_LEVELS, FALSE); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine recovers all records in the database for all - containers. -*****************************************************************************/ -FSTATIC RCODE bldRecovData( - FDB * pDb, - REBUILD_STATE * pRebuildState, // Pointer to rebuild state information. - // This structure has the container - // number being recovered. - CONTAINER_INFO * pContainerInfo, // Information being remembered for - // ALL containers. - FLMBOOL bRecovDictRecs, // Flag indicating whether we are to - // doing a pass to recover dictionary - // data or regular data. - - FLMBOOL * pbStartedTransRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiBlkAddress; - FLMUINT uiBytesRead; - F_SuperFileHdl * pSFileHdl = pRebuildState->pSFileHdl; - HDR_INFO * pHdrInfo = pRebuildState->pHdrInfo; - LF_HDR LogicalFile; - LF_STATS LfStats; - FLMBYTE * pucBlk = pRebuildState->pBlk; - STATUS_HOOK fnStatusFunc = pRebuildState->fnStatusFunc; - REBUILD_INFO * pCallbackData = &pRebuildState->CallbackData; - void * AppArg = pRebuildState->AppArg; - FLMUINT uiBlockSize = pHdrInfo->FileHdr.uiBlockSize; - FLMUINT uiCurrContainerNum = 0; - LFILE * pCurrLFile = NULL; - CONTAINER_INFO * pCurrContInfo = NULL; - FLMUINT uiBlkContainerNum; - LFILE * pBlkLFile; - RECOV_DICT_INFO * pRecovDictInfo = NULL; - FLMUINT uiFileNumber = 0; - FLMUINT uiOffset = 0; - F_FileHdlImp * pFileHdl = NULL; - FLMUINT uiMaxFileSize = pRebuildState->uiMaxFileSize; - FLMUINT uiDbVersion = - pRebuildState->pHdrInfo->FileHdr.uiVersionNum; - - // Read through all blocks in the file -- looking for leaf blocks - // of containers. Read until we get an error or run out of file. - - LogicalFile.pLfStats = &LfStats; - fnStatusFunc = pRebuildState->fnStatusFunc; - pCallbackData->iDoingFlag = (FLMINT)((bRecovDictRecs) - ? (FLMINT)REBUILD_RECOVER_DICT - : (FLMINT)REBUILD_RECOVER_DATA); - pCallbackData->bStartFlag = TRUE; - pCallbackData->ui64BytesExamined = 0; - for (;;) - { - if (uiOffset >= uiMaxFileSize || !uiFileNumber) - { - uiOffset = 0; - uiFileNumber++; - if (uiFileNumber > MAX_DATA_BLOCK_FILE_NUMBER( uiDbVersion)) - { - break; - } - - if (RC_BAD( rc = pSFileHdl->GetFileHdl( - uiFileNumber, FALSE, &pFileHdl))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - break; - } - goto Exit; - } - } - - // Read the block into memory. - - if (RC_BAD( rc = pFileHdl->SectorRead( uiOffset, uiBlockSize, - pucBlk, &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - if (!uiBytesRead) - { - - // Set uiOffset so we will go to the next file. - - uiOffset = uiMaxFileSize; - continue; - } - else - { - rc = FERR_OK; - } - } - else - { - goto Exit; - } - } - - if (fnStatusFunc) - { - pCallbackData->ui64BytesExamined += (FLMUINT64)uiBlockSize; - if (RC_BAD( rc = (*fnStatusFunc)( FLM_REBUILD_STATUS, - (void *)pCallbackData, - (void *)0, - AppArg))) - { - goto Exit; - } - pCallbackData->bStartFlag = FALSE; - } - - f_yieldCPU(); - - uiBlkAddress = (FLMUINT)GET_BH_ADDR( pucBlk); - if ((FSGetFileOffset( uiBlkAddress) == uiOffset) && - (BH_GET_TYPE( pucBlk) == BHT_LEAF) && - (pucBlk [BH_LEVEL] == 0) && - ((uiBlkContainerNum = (FLMUINT)FB2UW( &pucBlk [BH_LOG_FILE_NUM])) != 0) && - (bldDoContainer( uiBlkContainerNum, bRecovDictRecs))) - { - if (uiBlkContainerNum != uiCurrContainerNum) - { - if (RC_BAD( rc = fdictGetContainer( pDb->pDict, uiBlkContainerNum, - &pBlkLFile))) - { - if (rc != FERR_BAD_CONTAINER) - goto Exit; - rc = FERR_OK; - goto Do_Next_Block; - } - else - { - uiCurrContainerNum = uiBlkContainerNum; - f_memset( &LogicalFile, 0, sizeof( LF_HDR)); - f_memset( &LfStats, 0, sizeof( LF_STATS)); - LogicalFile.pLfStats = &LfStats; - LogicalFile.pLFile = pCurrLFile = pBlkLFile; - if (bRecovDictRecs) - { - pCurrContInfo = NULL; - } - else - { - pCurrContInfo = - &pContainerInfo [pCurrLFile - - ((LFILE *)pDb->pDict->pLFileTbl)]; - } - pRebuildState->CorruptInfo.uiErrLfNumber = uiBlkContainerNum; - } - } - - // Estimate the number of records in the block if we did't have - // a count of records in the container. The loop ignores the - // possibility that the block may be corrupted -- we are trying - // to estimate what might have been in the block. It loops through - // the elements in the block, looking for those which are marked - // as FIRST elements. When it encounters one of these, it will - // increment the counter. - - if (pCurrContInfo && !pCurrContInfo->bCountEstimated) - { - FLMUINT uiBlkOffset; - FLMUINT uiEndOfBlock; - FLMBYTE * pucElm; - FLMUINT uiElmLen; - FLMUINT uiElmKeyLen; - FLMUINT uiElmPKCLen; - FLMUINT uiNxtBlkAddr; - FLMBOOL bIncremented; - - uiEndOfBlock = (FLMUINT)FB2UW( &pucBlk [BH_ELM_END]); - uiNxtBlkAddr = (FLMUINT)FB2UD( &pucBlk [BH_NEXT_BLK]); - - // If uiEndOfBlock is too big, adjust it down so we can - // estimate. - - if (uiEndOfBlock > uiBlockSize) - { - uiEndOfBlock = uiBlockSize; - } - uiBlkOffset = BH_OVHD; - bIncremented = FALSE; - while (uiBlkOffset < uiEndOfBlock) - { - pucElm = &pucBlk [uiBlkOffset]; - uiElmLen = (FLMUINT)(BBE_LEN( pucElm)); - uiElmKeyLen = (FLMUINT)(BBE_GET_KL( pucElm)); - uiElmPKCLen = (FLMUINT)(BBE_GET_PKC( pucElm)); - - // If it is a FIRST element, and it is NOT the LEM - // element, increment the count. - - if ((BBE_IS_FIRST( pucElm)) && - ((uiElmLen != BBE_LEM_LEN) || - (uiElmKeyLen > 0) || - (uiElmPKCLen > 0) || - (uiBlkOffset + uiElmLen != uiEndOfBlock) || - (uiNxtBlkAddr != BT_END))) - { - pCallbackData->uiTotRecs++; - bIncremented = TRUE; - } - uiBlkOffset += uiElmLen; - } - - // Decrement the estimated count by one if it is a last - // block - one of the elements in a last block should - // always be a DRN_LAST_MARKER element. - - if ((bIncremented) && (uiNxtBlkAddr == BT_END)) - { - pCallbackData->uiTotRecs--; - } - } - - // See if we can now extract any records from the block - - uiBlkAddress = FSBlkAddress( uiFileNumber, uiOffset); - if( RC_BAD( rc = bldExtractRecs( pDb, pRebuildState, pCurrLFile, - pCurrContInfo, uiBlkAddress, - &LogicalFile, - bRecovDictRecs, - &pRecovDictInfo))) - { - goto Exit; - } - } - -Do_Next_Block: - - uiOffset += uiBlockSize; - } - - // If we are recovering dictionary records, we need to now add them - // into the appropriate dictionaries. - - if( bRecovDictRecs) - { - if( RC_BAD( rc = bldAddRecovDictRecs( pDb, pRebuildState, - &pRecovDictInfo, pbStartedTransRV))) - { - goto Exit; - } - } - -Exit: - - bldFreeRecovDictInfo( pRecovDictInfo); - return( rc); -} - -/*************************************************************************** -Desc: This routine checks a few things in the block header and then - attempts to decrypt the block so we can read through its elements. -Ret: 0 if block is OK, error code otherwise -*****************************************************************************/ -FSTATIC RCODE bldCheckBlock( - STATE_INFO * pStateInfo, - HDR_INFO * pHdrInfo, - FLMUINT uiBlkAddress, - FLMUINT uiPrevBlkAddress, - eCorruptionType * peCorruptionCode) -{ - RCODE rc = FERR_OK; - - // Determine where the end of block is -- make sure it is a legal value - - pStateInfo->uiBlkAddress = uiBlkAddress; - - // Must force the block address to be correct so this check will not - // fail. We already have previously verified that the offset matches, and - // we know that we got it from the right block file. However, the low - // byte of the block header will not be correct because until we do a - // block checksum calculation, it will hold the low checksum byte. - // We don't do a block checksum calculation during rebuild, so at this - // point, it still holds the low checksum byte. - - SET_BH_ADDR( pStateInfo->pBlk, uiBlkAddress); - if ((*peCorruptionCode = flmVerifyBlockHeader( pStateInfo, NULL, - pHdrInfo->FileHdr.uiBlockSize, - 0, uiPrevBlkAddress, FALSE, TRUE)) != FLM_NO_CORRUPTION) - { - goto Exit; - } - - pStateInfo->uiElmOffset = BH_OVHD; - - // Decrypt the block if necessary to check the elements. - // If encryption is not enabled for the database, or the block - // is already decrypted, do nothing. - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: This routine traverses all elements within a block, extracting - whatever records it can from the block. -*****************************************************************************/ -FSTATIC RCODE bldExtractRecs( - FDB * pDb, - REBUILD_STATE * pRebuildState, - LFILE * pLFile, - CONTAINER_INFO * pContInfo, - FLMUINT uiBlkAddress, - LF_HDR * pLogicalFile, - FLMBOOL bRecovDictRecs, - RECOV_DICT_INFO ** ppRecovDictInfoRV) -{ - RCODE rc = FERR_OK; - eCorruptionType eCorruptionCode; - FLMBOOL bGotNewBlock; - FLMUINT uiSaveElmOffset; - STATE_INFO * pStateInfo = pRebuildState->pStateInfo; - FLMBOOL bStateInitialized = TRUE; - STATUS_HOOK fnStatusFunc = pRebuildState->fnStatusFunc; - void * AppArg = pRebuildState->AppArg; - FLMBOOL bGotRecord; - - // Setup the STATE variable for processing through the block - - flmInitReadState( pStateInfo, &bStateInitialized, - pRebuildState->pHdrInfo->FileHdr.uiVersionNum, - pDb, pLogicalFile, 0xFF, BHT_LEAF, - pRebuildState->pKeyBuffer); - pStateInfo->pBlk = pRebuildState->pBlk; - - if( (RC_BAD( rc = bldCheckBlock( pStateInfo, pRebuildState->pHdrInfo, - uiBlkAddress, 0, &eCorruptionCode))) || (eCorruptionCode != FLM_NO_CORRUPTION)) - { - if( eCorruptionCode != FLM_NO_CORRUPTION) - { - (void)bldReportReason( pRebuildState, eCorruptionCode, uiBlkAddress, - 0, 0, 0xFFFF, 0); - } - goto Exit; - } - - // Go through each element in the block, extracting whatever data - // we can. The loop quits if it finds an inconsistency in the block. - - bGotNewBlock = FALSE; - while ((pStateInfo->uiElmOffset < pStateInfo->uiEndOfBlock) && - (!bGotNewBlock)) - { - bGotRecord = FALSE; - if (pRebuildState->pRecord) - { - pRebuildState->pRecord->clear(); - } - uiSaveElmOffset = pStateInfo->uiElmOffset; - - // Get the element and check it - - if( (eCorruptionCode = flmVerifyElement( pStateInfo, FLM_CHK_FIELDS)) != FLM_NO_CORRUPTION) - { - if( RC_BAD( rc = bldReportReason( pRebuildState, eCorruptionCode, uiBlkAddress, - pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, 0xFFFF, 0))) - { - goto Exit; - } - } - - // Skip continuation elements -- at this point, it should only - // be continuation elements which are at the first of the block. - // This is because the bldGetOneRec routine will traverse through - // continuation elements for a record. - - else if ((BBE_IS_FIRST( pStateInfo->pElm)) && (pStateInfo->uiCurKeyLen)) - { - if (pStateInfo->uiElmDrn == DRN_LAST_MARKER) - { - - if (pStateInfo->uiElmRecLen == 4) - { - FLMUINT uiNxtDrn = (FLMUINT)FB2UD( pStateInfo->pElmRec); - - if (pContInfo) - { - pContInfo->uiNumNextDrnsFound++; - if (uiNxtDrn > pContInfo->uiHighestNextDrnFound) - { - pContInfo->uiHighestNextDrnFound = uiNxtDrn; - } - } - } - } - - // If the element is the FIRST element in a record, - // see if we can extract a record from it. - - else if( RC_BAD( rc = bldGetOneRec( pDb, pRebuildState, pStateInfo, - bRecovDictRecs, &bGotNewBlock, &bGotRecord))) - { - // If we didn't have enough memory to retrieve the record, just - // skip it. - - if( rc == FERR_MEM) - { - bGotRecord = FALSE; - if (pRebuildState->pRecord) - { - pRebuildState->pRecord->clear(); - } - rc = FERR_OK; - } - else - { - goto Exit; - } - } - } - - // If we didn't get a data record, there was some inconsistency - // we encountered, so we continue to the next element in the block. - - if( bGotRecord) - { - f_yieldCPU(); - - if( pContInfo) - { - if( pStateInfo->uiElmDrn > pContInfo->uiHighetstDrnFound) - { - pContInfo->uiHighetstDrnFound = pStateInfo->uiElmDrn; - } - } - - // Add the record to the database - - if( bRecovDictRecs) - { - FlmRecord * pDictRec; - FLMUINT uiDictDrn = 0; - FLMBOOL bGotFromDataRec; - CHK_RECORD ChkRec; - - f_memset( &ChkRec, 0, sizeof( ChkRec)); - - // If this is not a dictionary container record, need to do the - // callback to see if there is dictionary information in this - // record. - - if( pLFile->uiLfNum == FLM_DICT_CONTAINER) - { - pDictRec = pRebuildState->pRecord; - uiDictDrn = pStateInfo->uiElmDrn; - bGotFromDataRec = FALSE; - } - else - { - if( !fnStatusFunc) - { - pDictRec = NULL; - } - else - { - ChkRec.pRecord = pRebuildState->pRecord; - ChkRec.uiContainer = pLFile->uiLfNum; - ChkRec.uiDrn = pStateInfo->uiElmDrn; - if( RC_BAD( rc = (*fnStatusFunc)( FLM_CHECK_RECORD_STATUS, - (void *)&ChkRec, - (void *)0, - AppArg))) - { - if( ChkRec.pDictRecSet) - { - ChkRec.pDictRecSet->Release(); - ChkRec.pDictRecSet = NULL; - } - goto Exit; - } - - if( ChkRec.pDictRecSet) - { - if( (pDictRec = ChkRec.pDictRecSet->first()) != NULL) - { - uiDictDrn = pDictRec->getID(); - } - } - else - { - pDictRec = NULL; - } - bGotFromDataRec = TRUE; - } - } - - if( !pDictRec) - { - rc = FERR_OK; - } - else - { - for (;;) - { - rc = bldSaveRecovDictRec( pDb, - ppRecovDictInfoRV, pDictRec, - uiDictDrn, bGotFromDataRec, uiBlkAddress, - uiSaveElmOffset); - - if( RC_BAD( rc) || !bGotFromDataRec) - { - break; - } - - // If bGotFromDataRec is TRUE, there may be more than - // one that was returned. - - if( (pDictRec = ChkRec.pDictRecSet->next()) == NULL) - { - break; - } - - uiDictDrn = pDictRec->getID(); - } - } - - if( ChkRec.pDictRecSet) - { - ChkRec.pDictRecSet->Release(); - ChkRec.pDictRecSet = NULL; - } - } - else if( pLFile->uiLfNum == FLM_TRACKER_CONTAINER) - { - rc = FSRecUpdate( pDb, pLFile, - pRebuildState->pRecord, pStateInfo->uiElmDrn, - REC_UPD_ADD); - } - else - { - rc = flmAddRecord( pDb, pLFile, &pStateInfo->uiElmDrn, - pRebuildState->pRecord, TRUE, - FALSE, FALSE, FALSE, NULL); - - if( RC_OK(rc) && fnStatusFunc ) - { - CHK_RECORD ChkRec; - - f_memset( &ChkRec, 0, sizeof( ChkRec)); - ChkRec.pRecord = pRebuildState->pRecord; - ChkRec.uiContainer = pLFile->uiLfNum; - ChkRec.uiDrn = pStateInfo->uiElmDrn; - rc = (*fnStatusFunc)( FLM_EXAMINE_RECORD_STATUS, - (void *)&ChkRec, - (void *)0, - AppArg); - if (ChkRec.pDictRecSet) - { - ChkRec.pDictRecSet->Release(); - ChkRec.pDictRecSet = NULL; - } - } - - if( pRebuildState->pRecord->isReadOnly()) - { - pRebuildState->pRecord->Release(); - pRebuildState->pRecord = NULL; - } - } - - if( RC_BAD( rc)) - { - if( (rc == FERR_EXISTS) || (rc == FERR_NOT_UNIQUE)) - { - eCorruptionCode = (rc == FERR_EXISTS) - ? FLM_REBUILD_REC_EXISTS - : FLM_REBUILD_KEY_NOT_UNIQUE; - if (RC_BAD( rc = bldReportReason( pRebuildState, - eCorruptionCode, uiBlkAddress, - uiSaveElmOffset, pStateInfo->uiElmDrn, 0xFFFF, 0))) - { - goto Exit; - } - } - else - { - goto Exit; - } - } - else - { - // Make sure the tempory memory is freed. - // Eats up the memory during a rebuild. - - GedPoolReset( &pDb->TempPool, NULL); - if (!bRecovDictRecs) - { - pRebuildState->CallbackData.uiRecsRecov++; - } - } - } - - pStateInfo->uiElmOffset += pStateInfo->uiElmLen; - } - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: This routine gets the next element for a record. If necessary, it - will try to go to the next block. -Ret: TRUE if we got the next element, FALSE otherwise. -*****************************************************************************/ -FSTATIC RCODE bldGetNextElm( - REBUILD_STATE * pRebuildState, - STATE_INFO * pStateInfo, - FLMBOOL * pbGotNextElmRV, - FLMBOOL * pbGotNewBlockRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiSaveDrn; - FLMUINT uiBytesRead; - FLMUINT uiBlkAddress; - FLMBYTE * pBlk = pStateInfo->pBlk; - HDR_INFO * pHdrInfo = pRebuildState->pHdrInfo; - eCorruptionType eCorruptionCode; - FLMUINT uiSaveBlkAddress = pStateInfo->uiBlkAddress; - - *pbGotNextElmRV = FALSE; - uiSaveDrn = pStateInfo->uiElmDrn; - - // See if we need to go to the next block to get the element - - pStateInfo->uiElmOffset += pStateInfo->uiElmLen; - if (pStateInfo->uiElmOffset >= pStateInfo->uiEndOfBlock) - { - // Get the next block - - *pbGotNewBlockRV = TRUE; - uiBlkAddress = (FLMUINT)FB2UD( &pBlk [BH_NEXT_BLK]); - rc = pRebuildState->pSFileHdl->ReadBlock( uiBlkAddress, - pHdrInfo->FileHdr.uiBlockSize, - pBlk, &uiBytesRead); - if( uiBytesRead < pHdrInfo->FileHdr.uiBlockSize) - { - rc = RC_SET( FERR_IO_END_OF_FILE); - } - - if( RC_BAD( rc)) - { - RCODE TempRc; - - if( rc == FERR_IO_END_OF_FILE || - rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - } - - if( RC_BAD( TempRc = bldReportReason( pRebuildState, - FLM_BAD_BLK_HDR_NEXT, uiSaveBlkAddress, - 0, 0, 0xFFFF, 0))) - { - if( RC_OK( rc)) - { - rc = TempRc; - } - } - - goto Exit; - } - - // Make sure it is the right type of block - - else if( (RC_BAD( rc = bldCheckBlock( pStateInfo, pRebuildState->pHdrInfo, - uiBlkAddress, uiSaveBlkAddress, &eCorruptionCode))) || (eCorruptionCode != FLM_NO_CORRUPTION)) - { - if (eCorruptionCode != FLM_NO_CORRUPTION) - { - (void)bldReportReason( pRebuildState, eCorruptionCode, - uiBlkAddress, 0, 0, - 0xFFFF, 0); - } - - goto Exit; - } - } - - // Verify other things about the element - - if( (eCorruptionCode = flmVerifyElement( pStateInfo, FLM_CHK_FIELDS)) != FLM_NO_CORRUPTION) - { - rc = bldReportReason( pRebuildState, eCorruptionCode, - pStateInfo->uiBlkAddress, pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, 0xFFFF, 0); - goto Exit; - } - - // This had better not be a LEM element - - if( pStateInfo->uiCurKeyLen == 0) - { - rc = bldReportReason( pRebuildState, FLM_BAD_LEM, - pStateInfo->uiBlkAddress, pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, 0xFFFF, 0); - goto Exit; - } - - // This element had better not be the first element - - if( BBE_IS_FIRST( pStateInfo->pElm)) - { - rc = bldReportReason( pRebuildState, FLM_BAD_FIRST_ELM_FLAG, - pStateInfo->uiBlkAddress, pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, 0xFFFF, 0); - goto Exit; - } - - // Must stay on the same DRN while processing the record - - if (pStateInfo->uiElmDrn != uiSaveDrn) - { - rc = bldReportReason( pRebuildState, FLM_BAD_CONT_ELM_KEY, - pStateInfo->uiBlkAddress, pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, 0xFFFF, 0); - goto Exit; - } - - *pbGotNextElmRV = TRUE; - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: This routine retrieves one record from a block -- at the current - element. It will follow continuation elements if necessary. The - record is returned in pRebuildState->pRecord. A NULL is returned if some - inconsistency was encountered. -*****************************************************************************/ -FSTATIC RCODE bldGetOneRec( - FDB * pDb, - REBUILD_STATE * pRebuildState, - STATE_INFO * pStateInfo, - FLMBOOL bRecovDictRecs, - FLMBOOL * pbGotNewBlockRV, - FLMBOOL * pbGotRecord) -{ - RCODE rc = FERR_OK; - FLMBYTE * pValue; - FLMBYTE * pData; - FLMBYTE * pTempValue; - eCorruptionType eCorruptionCode; - FlmRecord * pRecord = NULL; - FLMBOOL bAllocatedRecord = FALSE; - FLMBOOL bFieldDone; - FLMUINT uiSaveElmRecOffset; - FLMBOOL bGotNextElm; - FLMBOOL bSkipField = FALSE; - FLMBOOL bSkippedField = FALSE; - FLMUINT uiSkipToLevel = 0; - - // Setup things to get the record - - if( pRebuildState->pRecord) - { - pRebuildState->pRecord->clear(); - pRecord = pRebuildState->pRecord; - } - - pValue = NULL; - pTempValue = NULL; - *pbGotRecord = FALSE; - - // Follow elements until we have traversed all continuation elements - // or until we discover some inconsistency. - - for (;;) - { - uiSaveElmRecOffset = pStateInfo->uiElmRecOffset; - if ((eCorruptionCode = flmVerifyElmFOP( pStateInfo)) != FLM_NO_CORRUPTION) - { - if ((bRecovDictRecs) && (eCorruptionCode == FLM_BAD_ELM_FLD_NUM)) - { - bSkipField = TRUE; - bSkippedField = TRUE; - uiSkipToLevel = pStateInfo->uiFieldLevel; - bFieldDone = - (pStateInfo->uiFieldProcessedLen == pStateInfo->uiFieldLen) - ? TRUE - : FALSE; - } - else - { - rc = bldReportReason( pRebuildState, eCorruptionCode, pStateInfo->uiBlkAddress, - pStateInfo->uiElmOffset, pStateInfo->uiElmDrn, - uiSaveElmRecOffset, pStateInfo->uiFieldNum); - goto Exit; - } - } - - // See if we are starting a new field - - if( (pStateInfo->uiFOPType == FLM_FOP_STANDARD) || - (pStateInfo->uiFOPType == FLM_FOP_OPEN) || - (pStateInfo->uiFOPType == FLM_FOP_TAGGED) || - (pStateInfo->uiFOPType == FLM_FOP_NO_VALUE) || - (pStateInfo->uiFOPType == FLM_FOP_ENCRYPTED)) - { - // If we skipped a previous field, see if this field is a child - // or grandchild, etc. of the field that was skipped. If so, we skip - // this field as well. We stop skipping when we come to a field - // that is a sibling or aunt/uncle to the field that was skipped. - - if( (bSkipField) && - (pStateInfo->uiFieldLevel <= uiSkipToLevel)) - { - bSkipField = FALSE; - } - - // See if field should be skipped. - - if( !bSkipField) - { - FLMUINT uiState; - FLMUINT uiDictFieldType; - - if( RC_BAD( fdictGetField( pDb->pDict, pStateInfo->uiFieldNum, - &uiDictFieldType, NULL, &uiState))) - { - bSkipField = TRUE; - bSkippedField = TRUE; - uiSkipToLevel = pStateInfo->uiFieldLevel; - } - } - - // If we aren't skipping the field, allocate space for it - - if( !bSkipField) - { - void * pvField; - - if( !pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - bAllocatedRecord = TRUE; - } - - // Create a new field in the record. - - if( RC_BAD( rc = pRecord->insertLast( pStateInfo->uiFieldLevel, - pStateInfo->uiFieldNum, - pStateInfo->uiFieldType, &pvField))) - { - goto Exit; - } - - pStateInfo->pvField = pvField; - - // Allocate space for the field's value and set the field's type. - - if( !pStateInfo->uiFieldLen) - { - pValue = NULL; - } - else - { - if (!pStateInfo->uiEncId) - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - pStateInfo->uiFieldType, - pStateInfo->uiFieldLen, - 0, - 0, - 0, - &pValue, - NULL))) - { - goto Exit; - } - } - else - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - pStateInfo->uiFieldType, - pStateInfo->uiFieldLen, - pStateInfo->uiEncFieldLen, - pStateInfo->uiEncId, - FLD_HAVE_ENCRYPTED_DATA, - &pData, - &pValue))) - { - goto Exit; - } - } - } - pTempValue = pValue; - } - bFieldDone = - ((!pStateInfo->uiEncId && - pStateInfo->uiFieldProcessedLen == pStateInfo->uiFieldLen) || - (pStateInfo->uiEncId && - pStateInfo->uiFieldProcessedLen == pStateInfo->uiEncFieldLen)) - ? TRUE - : FALSE; - } - else if( (pStateInfo->uiFOPType == FLM_FOP_JUMP_LEVEL) || - (pStateInfo->uiFOPType == FLM_FOP_NEXT_DRN)) - { - bFieldDone = FALSE; - } - else - { - bFieldDone = - ((!pStateInfo->uiEncId && - pStateInfo->uiFieldProcessedLen == pStateInfo->uiFieldLen) || - (pStateInfo->uiEncId && - pStateInfo->uiFieldProcessedLen == pStateInfo->uiEncFieldLen)) - ? TRUE - : FALSE; - } - - // See if we got some data with this FOP - - if( pValue && - pStateInfo->uiFOPDataLen && - !bSkipField && - pStateInfo->uiFOPType != FLM_FOP_REC_INFO) - { - f_memcpy( pTempValue, - pStateInfo->pFOPData, pStateInfo->uiFOPDataLen); - pTempValue += pStateInfo->uiFOPDataLen; - } - - // See if we are done with this field - - if( bFieldDone) - { - // Verify the value - - if( pStateInfo->uiFieldLen) - { - if( bSkipField || pStateInfo->uiFieldType == 0xFF) - { - eCorruptionCode = FLM_NO_CORRUPTION; - } - else - { - if (!pStateInfo->uiEncId) - { - eCorruptionCode = flmVerifyField( pValue, - pStateInfo->uiFieldLen, - pStateInfo->uiFieldType); - } - - // Encrypted fields are never supposed to be found in the dictionary, so - // if we do not have an ITT table, we will not be able to decrypt this field. - // Therefore, we should be in our first pass. This field / record will - // not be used to recover the dictionary. - - else if (pDb->pFile->pDictList->pIttTbl) - { - if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, - pStateInfo->pvField, pStateInfo->uiEncId, - &pDb->TempPool))) - { - goto Exit; - } - eCorruptionCode = flmVerifyField( pData, - pStateInfo->uiFieldLen, - pStateInfo->uiFieldType); - } - } - - if( eCorruptionCode != FLM_NO_CORRUPTION) - { - rc = bldReportReason( pRebuildState, eCorruptionCode, - pStateInfo->uiBlkAddress, - pStateInfo->uiElmOffset, pStateInfo->uiElmDrn, - uiSaveElmRecOffset, - pStateInfo->uiFieldNum); - goto Exit; - } - } - - // Set pValue to NULL for the next field - - pValue = pTempValue = NULL; - } - - // See if we are at the end of this element - - if( pStateInfo->uiElmRecOffset == pStateInfo->uiElmRecLen) - { - // If the last element flag is set, we are done with this - // record and can return - unless we have a half processed field. - - if( BBE_IS_LAST( pStateInfo->pElm)) - { - if (!bFieldDone) - { - rc = bldReportReason( pRebuildState, FLM_BAD_LAST_ELM_FLAG, - pStateInfo->uiBlkAddress, - pStateInfo->uiElmOffset, pStateInfo->uiElmDrn, - uiSaveElmRecOffset, - pStateInfo->uiFieldNum); - } - else - { - pRebuildState->pRecord = pRecord; - *pbGotRecord = TRUE; - pRecord = NULL; - bAllocatedRecord = FALSE; - } - - goto Exit; - } - else - { - // Attempt to get the next element - - if( (RC_BAD( rc = bldGetNextElm( pRebuildState, pStateInfo, - &bGotNextElm, pbGotNewBlockRV))) || !bGotNextElm) - { - // Need to set bSkippedField to TRUE so that cleanup will - // occur at the bottom of this routine. - - bSkippedField = TRUE; - goto Exit; - } - } - } - } - -Exit: - - if( bSkippedField || RC_BAD( rc)) - { - if (pRebuildState->pRecord) - { - pRebuildState->pRecord->Release(); - pRebuildState->pRecord = NULL; - } - - *pbGotRecord = FALSE; - } - - if( pRecord && bAllocatedRecord) - { - pRecord->Release(); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine recovers any dictionary records from the corrupted file - that it can recover, attempting to find any that may not have been - in the dictionary file that was passed into the rebuild routines. -*****************************************************************************/ -FSTATIC RCODE bldSaveRecovDictRec( - FDB * pDb, // FDB for newly created database - RECOV_DICT_INFO ** ppRecovDictInfoRV, // Recover info - FlmRecord * pRecord, // Dictionary Record - FLMUINT uiDrn, // Dict. record DRN - FLMBOOL bGotFromDataRec, // Was this dictionary record - // extracted from a data record? - FLMUINT uiBlkAddress, // Block the record was - // recovered from - FLMUINT uiElmOffset // Offset in block the - // record was recovered - // from - ) -{ - RCODE rc = FERR_OK; - RECOV_DICT_INFO * pRecovDictInfo; - RECOV_DICT_REC * pRecovDictRec; - RECOV_DICT_REC * pNewDictRec = NULL; - RECOV_DICT_REC * pPrevDictRec; - FLMUINT uiRecType = pRecord->getFieldID( pRecord->root()); - FlmRecord * pDummyRec; - LFILE * pDictLFile; - - // Ignore any record that is not a dictionary record or - // an unregistered (comment) record. - - if( uiRecType < FLM_RESERVED_TAG_NUMS) - { - goto Exit; - } - - // Determine if the record already exists in the dictionary. If it - // does, simply ignore this record - the record that was loaded from - // the dictionary file takes precedence. - - if( RC_OK( rc = fdictGetContainer( pDb->pDict, FLM_DICT_CONTAINER, - &pDictLFile))) - { - pDummyRec = NULL; - rc = FSReadRecord( pDb, pDictLFile, uiDrn, - &pDummyRec, NULL, NULL); - if( pDummyRec) - { - pDummyRec->Release(); - } - } - - if( rc != FERR_NOT_FOUND) - { - goto Exit; - } - - rc = FERR_OK; - - // If the dictionary was not found in the list, create an entry in the - // list. - - if( (pRecovDictInfo = *ppRecovDictInfoRV) == NULL) - { - if( RC_BAD( rc = f_calloc( - (FLMUINT)sizeof( RECOV_DICT_INFO), &pRecovDictInfo))) - { - goto Exit; - } - - GedPoolInit( &pRecovDictInfo->pool, 512); - *ppRecovDictInfoRV = pRecovDictInfo; - } - - // Determine if the record is already in our list of records. If so, - // simply ignore it, or remove the old one. The old one is removed if - // it is "less desirable to recover". Desirability of record types is - // as follows: - // - // 1. Field Definitions && Template definitions take top priority - // 2. Container Definitions - // 3. Area Definitions - // 4. Reserve Definitions - // 5. Index Definitions - // 6. Other - - pPrevDictRec = NULL; - pRecovDictRec = pRecovDictInfo->pRecovRecs; - - while( pRecovDictRec) - { - if( pRecovDictRec->pRec->getID() != uiDrn) - { - pPrevDictRec = pRecovDictRec; - pRecovDictRec = pRecovDictRec->pNext; - } - else if( bGotFromDataRec && !pRecovDictRec->bGotFromDataRec) - { - // Throw away this record and keep the one that was previously - // recovered from the dictionary container. Records recovered - // from the dictionary container are preferred to ones that - // were extracted from a data record. - - goto Exit; - } - else if( !bGotFromDataRec && pRecovDictRec->bGotFromDataRec) - { - // Throw away prior dictionary record that was recovered, because - // we got it from a data record. This newer one was actually found - // in the dictionary, so we will keep it in preference to the - // earlier one that we found in a data record. - - goto Remove_Rec; - } - else - { - switch (pRecovDictRec->pRec->getFieldID( pRecovDictRec->pRec->root())) - { - case FLM_FIELD_TAG: - goto Exit; - - case FLM_CONTAINER_TAG: - if( uiRecType == FLM_FIELD_TAG) - { -Remove_Rec: - if (pPrevDictRec) - { - pPrevDictRec->pNext = pRecovDictRec->pNext; - } - else - { - pRecovDictInfo->pRecovRecs = pRecovDictRec->pNext; - } - - // Might as well use the old structure for the new record, - // so we don't have to allocate it below. - - pNewDictRec = pRecovDictRec; - - if( pRecovDictRec->pRec) - { - pRecovDictRec->pRec->Release(); - pRecovDictRec->pRec = NULL; - } - - f_memset( pNewDictRec, 0, sizeof( RECOV_DICT_REC)); - } - else - { - goto Exit; - } - break; - - case FLM_AREA_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG) - { - goto Remove_Rec; - } - else - { - goto Exit; - } - - case FLM_RESERVED_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG) - { - goto Remove_Rec; - } - else - { - goto Exit; - } - - case FLM_INDEX_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG || - uiRecType == FLM_RESERVED_TAG) - { - goto Remove_Rec; - } - else - { - goto Exit; - } - - default: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG || - uiRecType == FLM_RESERVED_TAG || - uiRecType == FLM_INDEX_TAG) - { - goto Remove_Rec; - } - else - { - goto Exit; - } - } - break; - } - } - - // Link the record into the list of records that need to be - // recovered. We don't add it right away, because we want to be sure - // and do them in a certain order, as follows: - // - // 1. Field definitions - // 2. Container definitions - // 3. Area definitions - // 4. Template definitions - // 5. Index definitions - // 6. Reserve definitions - // 7. Other - - if( !pNewDictRec) - { - // All elements of pNewDictRec are initialized below. - - if( (pNewDictRec = (RECOV_DICT_REC *)GedPoolAlloc( - &pRecovDictInfo->pool, sizeof( RECOV_DICT_REC))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pNewDictRec->pNext = NULL; - pNewDictRec->bAdded = FALSE; - } - - if( (pNewDictRec->pRec = pRecord->copy()) == NULL) - { - rc = RC_SET( FERR_MEM); - } - - pNewDictRec->bGotFromDataRec = bGotFromDataRec; - pNewDictRec->pRec->setID( uiDrn); - pNewDictRec->uiBlkAddress = uiBlkAddress; - pNewDictRec->uiElmOffset = uiElmOffset; - pPrevDictRec = NULL; - pRecovDictRec = pRecovDictInfo->pRecovRecs; - - while( pRecovDictRec) - { - switch( pRecovDictRec->pRec->getFieldID( pRecovDictRec->pRec->root())) - { - case FLM_FIELD_TAG: - break; - - case FLM_CONTAINER_TAG: - if( uiRecType == FLM_FIELD_TAG) - { - goto Insert_Rec; - } - break; - - case FLM_AREA_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG) - { - goto Insert_Rec; - } - break; - - case FLM_INDEX_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG) - { - goto Insert_Rec; - } - break; - - case FLM_RESERVED_TAG: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG || - uiRecType == FLM_INDEX_TAG) - { - goto Insert_Rec; - } - break; - - default: - if( uiRecType == FLM_FIELD_TAG || - uiRecType == FLM_CONTAINER_TAG || - uiRecType == FLM_AREA_TAG || - uiRecType == FLM_INDEX_TAG || - uiRecType == FLM_RESERVED_TAG) - { - goto Insert_Rec; - } - break; - } - - pPrevDictRec = pRecovDictRec; - pRecovDictRec = pRecovDictRec->pNext; - } - -Insert_Rec: - - pNewDictRec->pNext = pRecovDictRec; - if( pPrevDictRec) - { - pPrevDictRec->pNext = pNewDictRec; - } - else - { - pRecovDictInfo->pRecovRecs = pNewDictRec; - } - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: This routine frees all of the recovery dictionary information. -*****************************************************************************/ -FSTATIC void bldFreeRecovDictInfo( - RECOV_DICT_INFO * pRecovDictInfo) -{ - if( pRecovDictInfo) - { - RECOV_DICT_REC * pDictRec; - - pDictRec = pRecovDictInfo->pRecovRecs; - while (pDictRec) - { - if (pDictRec->pRec) - { - pDictRec->pRec->Release(); - pDictRec->pRec = NULL; - } - pDictRec = pDictRec->pNext; - } - - GedPoolFree( &pRecovDictInfo->pool); - f_free( &pRecovDictInfo); - } -} - -/*************************************************************************** -Desc: This routine adds all of the recovered dictionary records for a - specific dictionary. It makes sure to do parent dictionaries first. -*****************************************************************************/ -FSTATIC RCODE bldDoDict( - FDB * pDb, - REBUILD_STATE * pRebuildState, - RECOV_DICT_INFO * pDictToDo, - FLMBOOL * pbStartedTransRV) -{ - RCODE rc = FERR_OK; - RECOV_DICT_REC * pDictRec; - RECOV_DICT_REC * pFirstDictRecInTrans = NULL; - LFILE * pDictLFile; - STATUS_HOOK fnStatusFunc = pRebuildState->fnStatusFunc; - REBUILD_INFO * pCallbackData = &pRebuildState->CallbackData; - FLMBOOL bHaveLFile; - FLMBOOL bAddedAtLeastOne; - FLMBOOL bFailedAtLeastOne; - FlmRecord * pSaveRec; - FLMUINT uiRecordsPerTrans; - FLMUINT uiRecordInTrans; - FLMUINT uiDictRecId; - - // Commit the current update transaction - - if( *pbStartedTransRV) - { - *pbStartedTransRV = FALSE; - if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, FALSE))) - { - goto Exit; - } - } - - // Add all of the records for pDictToDo - one per transaction. - - bHaveLFile = FALSE; - uiRecordsPerTrans = 100; - -Do_Dict_Recs: - - pDictRec = pDictToDo->pRecovRecs; - bAddedAtLeastOne = FALSE; - bFailedAtLeastOne = FALSE; - uiRecordInTrans = 0; - - while (pDictRec) - { - if (!pDictRec->bAdded) - { - if( !uiRecordInTrans) - { - // Start an update transaction - - if( RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, 5))) - { - goto Exit; - } - - *pbStartedTransRV = TRUE; - pFirstDictRecInTrans = pDictRec; - } - uiRecordInTrans++; - - // Don't optimize and keep pDictLFile as a local variable! - - if( RC_BAD( rc = fdictGetContainer( - pDb->pDict, FLM_DICT_CONTAINER, &pDictLFile))) - { - rc = FERR_OK; - goto Exit; - } - bHaveLFile = TRUE; - - // Call the status callback to give the application a chance - // to change the definition record - - if( fnStatusFunc) - { - if( RC_BAD( rc = (*fnStatusFunc)( FLM_REBUILD_ADD_DICT_REC_STATUS, - (void *)pDictRec->pRec, - (void *)0, - pRebuildState->AppArg))) - { - goto Exit; - } - } - - // Add the dictionary record. - // NOTE: We are deliberately ignoring return codes here - so we - // can attempt to process as many records as possible. - - uiDictRecId = pDictRec->pRec->getID(); - - if (RC_BAD( flmLFileDictUpdate( pDb, pDictLFile, - &uiDictRecId, pDictRec->pRec, - NULL, FALSE, FALSE, NULL, TRUE))) - { - *pbStartedTransRV = FALSE; - (void)flmAbortDbTrans( pDb); - bFailedAtLeastOne = TRUE; - uiRecordInTrans = 0; - } - else if( (uiRecordInTrans >= uiRecordsPerTrans) || !pDictRec->pNext) - { - *pbStartedTransRV = FALSE; - if (RC_BAD( flmCommitDbTrans( pDb, 0, FALSE))) - { - bFailedAtLeastOne = TRUE; - } - else - { - // Set bAdded to TRUE on all dict recs in transaction. - - while( pFirstDictRecInTrans != pDictRec) - { - pFirstDictRecInTrans->bAdded = TRUE; - pFirstDictRecInTrans = pFirstDictRecInTrans->pNext; - } - - pDictRec->bAdded = bAddedAtLeastOne = TRUE; - pRebuildState->CallbackData.uiRecsRecov += uiRecordInTrans; - - if( fnStatusFunc) - { - if (RC_BAD( rc = (*fnStatusFunc)( FLM_REBUILD_STATUS, - (void *)pCallbackData, - (void *)0, - pRebuildState->AppArg))) - { - goto Exit; - } - } - - f_yieldCPU(); - } - - uiRecordInTrans = 0; - } - } - - pDictRec = pDictRec->pNext; - } - - // Retry the add loop until either they all FAIL or they all succeed. - // This is done to handle record template dependencies - or other - // dependencies for that matter - that may not have been in the proper - // order in the list. - - if( (bAddedAtLeastOne || uiRecordsPerTrans > 1) && bFailedAtLeastOne) - { - // We MUST do single record transactions from this point on - // so the commit above will be called if the last pDictRec - // was added on any prior pass. - - uiRecordsPerTrans = 1; - goto Do_Dict_Recs; - } - - // Log the records that failed - - pDictRec = pDictToDo->pRecovRecs; - pSaveRec = pRebuildState->pRecord; - - while (pDictRec) - { - if (!pDictRec->bAdded) - { - RCODE TempRc; - - pRebuildState->pRecord = pDictRec->pRec; - if (RC_BAD( TempRc = bldReportReason( pRebuildState, - FLM_DICT_REC_ADD_ERR, - pDictRec->uiBlkAddress, pDictRec->uiElmOffset, - pDictRec->pRec->getID(), 0xFFFF, 0))) - { - rc = TempRc; - } - } - pDictRec = pDictRec->pNext; - } - pRebuildState->pRecord = pSaveRec; - -Exit: - - bldFreeRecovDictInfo( pDictToDo); - if ((RC_OK( rc)) && (!(*pbStartedTransRV))) - { - if (RC_OK( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, 5))) - { - *pbStartedTransRV = TRUE; - } - } - - return( rc); -} diff --git a/flaim/src/flblddbo.cpp b/flaim/src/flblddbo.cpp deleted file mode 100644 index 7bff7db..0000000 --- a/flaim/src/flblddbo.cpp +++ /dev/null @@ -1,786 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Rebuild corrupted database. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flblddbo.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE bldDetermineBlkSize( - F_SuperFileHdl * pSFileHdl, - FLMUINT uiMaxFileSize, - FLMUINT * puiBlkSizeRV, - STATUS_HOOK fnStatusFunc, - REBUILD_INFO * pCallbackData, - void * AppArg); - -/**************************************************************************** -Desc: Extract create options from file header and log header pieces. -****************************************************************************/ -void flmGetCreateOpts( - FILE_HDR * pFileHdr, - FLMBYTE * pucLogHdr, - CREATE_OPTS * pCreateOpts) -{ - f_memset( pCreateOpts, 0, sizeof( CREATE_OPTS)); - if (pFileHdr) - { - pCreateOpts->uiBlockSize = pFileHdr->uiBlockSize; - pCreateOpts->uiVersionNum = pFileHdr->uiVersionNum; - pCreateOpts->uiDefaultLanguage = pFileHdr->uiDefaultLanguage; - pCreateOpts->uiAppMajorVer = pFileHdr->uiAppMajorVer; - pCreateOpts->uiAppMinorVer = pFileHdr->uiAppMinorVer; - } - else - { - pCreateOpts->uiBlockSize = DEFAULT_BLKSIZ; - pCreateOpts->uiVersionNum = FLM_CURRENT_VERSION_NUM; - pCreateOpts->uiDefaultLanguage = DEFAULT_LANG; - - // uiAppMajorVer and uiAppMinorVer are already zero. - } - - if (pucLogHdr) - { - pCreateOpts->uiMinRflFileSize = - (FLMUINT)FB2UD( &pucLogHdr [LOG_RFL_MIN_FILE_SIZE]); - pCreateOpts->uiMaxRflFileSize = - (FLMUINT)FB2UD( &pucLogHdr [LOG_RFL_MAX_FILE_SIZE]); - pCreateOpts->bKeepRflFiles = - (FLMBOOL)((pucLogHdr [LOG_KEEP_RFL_FILES]) ? TRUE : FALSE); - pCreateOpts->bLogAbortedTransToRfl = - (FLMBOOL)((pucLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL]) ? TRUE : FALSE); - } - else - { - pCreateOpts->uiMinRflFileSize = DEFAULT_MIN_RFL_FILE_SIZE; - pCreateOpts->uiMaxRflFileSize = DEFAULT_MAX_RFL_FILE_SIZE; - pCreateOpts->bKeepRflFiles = DEFAULT_KEEP_RFL_FILES_FLAG; - pCreateOpts->bLogAbortedTransToRfl = DEFAULT_LOG_ABORTED_TRANS_FLAG; - } -} - -/*API~*********************************************************************** -Desc: Rebuilds a damaged database. -Notes: This routine performs the following actions: 1) A temporary database - is created; 2) A copy of the source database is saved; 3) The source - database is scanned. Data records from all containers are extracted - and stored in the temporary database. 4) When the rebuild is - complete, the temporary database file is copied over the source - database file. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbRebuild( - const char * pszSourceDbPath, - const char * pszSourceDataDir, - const char * pszDestDbPath, - const char * pszDestDataDir, - const char * pszDestRflDir, - const char * pszDictPath, - CREATE_OPTS * pCreateOpts, - FLMUINT * puiTotRecsRV, - FLMUINT * puiRecsRecovRV, - STATUS_HOOK fnStatusFunc, - void * pvStatusData) -{ - RCODE rc = FERR_OK; - FDB * pDb = NULL; - FFILE * pFile; - F_SuperFileHdl * pSFileHdl = NULL; - FLMBOOL bFileLocked = FALSE; - FLMBOOL bWriteLocked = FALSE; - REBUILD_STATE * pRebuildState = NULL; - HDR_INFO * pHdrInfo; - CREATE_OPTS * pDefaultCreateOpts = NULL; - FLMUINT uiTransID; - ServerLockObject * pWriteLockObj = NULL; - ServerLockObject * pFileLockObj = NULL; - FLMBOOL bMutexLocked = FALSE; - F_FileHdlImp * pLockFileHdl = NULL; - FLOCK_INFO LockInfo; - FLMUINT uiFileNumber; - FLMUINT uiDbVersion = 0; - FLMBOOL bUsedFFile = FALSE; - FLMBOOL bBadHeader = FALSE; - FlmECache * pECacheMgr = NULL; - - f_mutexLock( gv_FlmSysData.hShareMutex); - bMutexLocked = TRUE; - - // See if there is an FFILE structure for this file - // May unlock and re-lock the global mutex. - - if( RC_BAD( rc = flmFindFile( pszSourceDbPath, pszSourceDataDir, - &pFile))) - { - goto Exit; - } - - // If we didn't find an FFILE structure, get an - // exclusive lock on the file. - - if( !pFile) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - bMutexLocked = FALSE; - - // Attempt to get an exclusive lock on the file. - - if( RC_BAD( rc = flmCreateLckFile( pszSourceDbPath, &pLockFileHdl))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = flmCheckFFileState( pFile))) - { - goto Exit; - } - - // The call to flmVerifyFileUse will wait if the file is in - // the process of being opened by another thread. - - if (RC_BAD( rc = flmVerifyFileUse( gv_FlmSysData.hShareMutex, &pFile))) - { - goto Exit; - } - - // Increment the use count on the FFILE so it will not - // disappear while we are copying the file. - - if (++pFile->uiUseCount == 1) - { - flmUnlinkFileFromNUList( pFile); - } - bUsedFFile = TRUE; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - bMutexLocked = FALSE; - - // See if the thread already has a file lock. If so, there - // is no need to obtain another. However, we also want to - // make sure there is no write lock. If there is, - // we cannot do the rebuild right now. - - pFile->pFileLockObj->GetLockInfo( (FLMINT)0, &LockInfo); - if (LockInfo.eCurrLockType == FLM_LOCK_EXCLUSIVE && - LockInfo.uiThreadId == f_threadId()) - { - - // See if there is already a transaction going. - - pFile->pWriteLockObj->GetLockInfo( (FLMINT)0, &LockInfo); - if ((LockInfo.eCurrLockType == FLM_LOCK_EXCLUSIVE) && - (LockInfo.uiThreadId == f_threadId())) - { - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - } - else - { - pFileLockObj = pFile->pFileLockObj; - pFileLockObj->AddRef(); - if (RC_BAD( rc = pFileLockObj->Lock( TRUE, NULL, FALSE, TRUE, - FLM_NO_TIMEOUT, 0))) - { - goto Exit; - } - bFileLocked = TRUE; - } - - // Lock the write object to eliminate contention with - // the checkpoint thread. - - pWriteLockObj = pFile->pWriteLockObj; - pWriteLockObj->AddRef(); - - // Only contention here is with the checkpoint thread. - // Wait forever for the checkpoint thread to give - // up the lock. - - if (RC_BAD( rc = dbWriteLock( pFile))) - { - goto Exit; - } - bWriteLocked = TRUE; - } - - if( RC_BAD( rc = f_calloc( - sizeof( REBUILD_STATE), &pRebuildState))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( - sizeof( HDR_INFO), &pRebuildState->pHdrInfo))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( - sizeof( STATE_INFO), &pRebuildState->pStateInfo))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( - sizeof( CREATE_OPTS), &pDefaultCreateOpts))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( - LOG_HEADER_SIZE, &pRebuildState->pLogHdr))) - { - goto Exit; - } - - if( RC_BAD( rc = f_calloc( - MAX_KEY_SIZ, &pRebuildState->pKeyBuffer))) - { - goto Exit; - } - - pRebuildState->AppArg = pvStatusData; - pRebuildState->fnStatusFunc = fnStatusFunc; - pHdrInfo = pRebuildState->pHdrInfo; - - /* Open the corrupted database. */ - - if ((pSFileHdl = f_new F_SuperFileHdl) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = pSFileHdl->Setup( NULL, pszSourceDbPath, - pszSourceDataDir))) - { - goto Exit; - } - - pRebuildState->pSFileHdl = pSFileHdl; - - /* - Check the header information to see if we were in the middle - of a previous copy. - */ - - if (RC_OK( rc = flmGetHdrInfo( pSFileHdl, - &pHdrInfo->FileHdr, - &pHdrInfo->LogHdr, - pRebuildState->pLogHdr))) - { - - if (!pCreateOpts) - { - flmGetCreateOpts( &pHdrInfo->FileHdr, - pRebuildState->pLogHdr, pDefaultCreateOpts); - pCreateOpts = pDefaultCreateOpts; - } - rc = FERR_OK; - uiDbVersion = pHdrInfo->FileHdr.uiVersionNum; - pRebuildState->uiMaxFileSize = flmGetMaxFileSize( uiDbVersion, - pRebuildState->pLogHdr); - } - else if ((rc == FERR_BLOCK_CHECKSUM) || - (rc == FERR_INCOMPLETE_LOG) || - (rc == FERR_DATA_ERROR) || - ((rc == FERR_UNSUPPORTED_VERSION) && - (pHdrInfo->FileHdr.uiVersionNum == 0))) - { - if ((rc == FERR_BLOCK_CHECKSUM) || - (rc == FERR_DATA_ERROR)) - { - bBadHeader = TRUE; - } - rc = FERR_OK; - if (!pCreateOpts) - { - flmGetCreateOpts( &pHdrInfo->FileHdr, - pRebuildState->pLogHdr, pDefaultCreateOpts); - pCreateOpts = pDefaultCreateOpts; - } - uiDbVersion = pHdrInfo->FileHdr.uiVersionNum; - pRebuildState->uiMaxFileSize = flmGetMaxFileSize( uiDbVersion, - pRebuildState->pLogHdr); - } - else if (rc == FERR_UNSUPPORTED_VERSION || rc == FERR_NEWER_FLAIM) - { - goto Exit; - } - else if ((rc == FERR_NOT_FLAIM) || - (!VALID_BLOCK_SIZE( pHdrInfo->FileHdr.uiBlockSize))) - { - FLMUINT uiSaveBlockSize; - FLMUINT uiCalcBlockSize = 0; - FLMBYTE ucFileHdrBuf[ FLM_FILE_HEADER_SIZE]; - - uiDbVersion = (FLMUINT)((rc != FERR_NOT_FLAIM) - ? pHdrInfo->FileHdr.uiVersionNum - : FLM_CURRENT_VERSION_NUM); - pSFileHdl->SetDbVersion( uiDbVersion); - pRebuildState->uiMaxFileSize = flmGetMaxFileSize( uiDbVersion, - pRebuildState->pLogHdr); - if (!pCreateOpts) - { - if (rc != FERR_NOT_FLAIM) - { - flmGetCreateOpts( &pHdrInfo->FileHdr, - pRebuildState->pLogHdr, pDefaultCreateOpts); - } - else - { - flmGetCreateOpts( NULL, NULL, pDefaultCreateOpts); - } - - // Set block size to zero, so we will always take the calculated - // block size below. - - pDefaultCreateOpts->uiBlockSize = 0; - pCreateOpts = pDefaultCreateOpts; - } - - /* Try to determine the correct block size. */ - - if (RC_BAD( rc = bldDetermineBlkSize( pSFileHdl, - pRebuildState->uiMaxFileSize, - &uiCalcBlockSize, - fnStatusFunc, &pRebuildState->CallbackData, - pRebuildState->AppArg))) - { - goto Exit; - } - - uiSaveBlockSize = pCreateOpts->uiBlockSize; - pCreateOpts->uiBlockSize = uiCalcBlockSize; - - // Initialize pHdrInfo->FileHdr to useable values. - - flmInitFileHdrInfo( pCreateOpts, &pHdrInfo->FileHdr, ucFileHdrBuf); - - /* - Only use the passed-in block size (uiSaveBlockSize) if it - was non-zero. - */ - - if (uiSaveBlockSize) - pCreateOpts->uiBlockSize = uiSaveBlockSize; - } - else - { - goto Exit; - } - - // Calculate the file size. - - pSFileHdl->SetDbVersion( uiDbVersion); - pRebuildState->CallbackData.ui64DatabaseSize = 0; - for (uiFileNumber = 1;;uiFileNumber++) - { - FLMUINT uiTmpSize; - - if (RC_BAD( pSFileHdl->GetFileSize( uiFileNumber, &uiTmpSize))) - { - break; - } - pRebuildState->CallbackData.ui64DatabaseSize += (FLMUINT64)uiTmpSize; - } - - // Delete the destination database in case it already exists. - - if (RC_BAD( rc = FlmDbRemove( pszDestDbPath, pszDestDataDir, - pszDestRflDir, TRUE))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - } - else - { - goto Exit; - } - } - - /* - If no block size has been specified or determined yet, use what we - read from the file header. - */ - - if (!pCreateOpts->uiBlockSize) - pCreateOpts->uiBlockSize = pHdrInfo->FileHdr.uiBlockSize; - - pSFileHdl->SetDbVersion( pHdrInfo->FileHdr.uiVersionNum); - pSFileHdl->SetBlockSize( pHdrInfo->FileHdr.uiBlockSize); - - /* - Set the ECache manger into the super file handle - */ - - if( pFile && pFile->pECacheMgr) - { - pSFileHdl->setECacheMgr( pFile->pECacheMgr); - } - else if( gv_FlmSysData.bOkToUseESM) - { - if( (pECacheMgr = f_new FlmECache) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( !pECacheMgr->setupECache( pHdrInfo->FileHdr.uiBlockSize, - pRebuildState->uiMaxFileSize)) - { - pECacheMgr->Release(); - pECacheMgr = NULL; - } - else - { - pSFileHdl->setECacheMgr( pECacheMgr); - } - } - - /* - When creating the new file, set the transaction ID to one greater than it - is in the corrupt file. However, don't let it get greater than about - 2 billion - want to leave room for 2 billion transactions in case they - were corrupted somehow in our old file. - */ - - uiTransID = - ((FLMUINT)FB2UD( &pRebuildState->pLogHdr [LOG_CURR_TRANS_ID]) + 1) & 0x7FFFFFFF; - - if (RC_BAD( rc = flmCreateNewFile( pszDestDbPath, pszDestDataDir, - pszDestRflDir, - pszDictPath, NULL, - pCreateOpts, uiTransID, (FDB_p *)&pRebuildState->hDb, - pRebuildState))) - { - goto Exit; - } - pDb = (FDB *)pRebuildState->hDb; - - /* Rebuild the database */ - - if (RC_BAD( rc = flmDbRebuildFile( pRebuildState, bBadHeader))) - { - goto Exit; - } - -Exit: - - /* Close the temporary database, if it is still open. */ - - if (pDb) - { - FFILE * pTmpFile; - FFILE * pTmpFile1; - - // Get the FFILE pointer for the temporary file before closing it. - - pTmpFile = pDb->pFile; - - (void)FlmDbClose( (HFDB *)&pDb); - - // Force temporary FFILE structure to be cleaned up, if it - // isn't already gone. The following code searches for the - // temporary file in the not-used list. If it finds it, - // it will unlink it. - - if (!bMutexLocked) - { - f_mutexLock( gv_FlmSysData.hShareMutex); - bMutexLocked = TRUE; - } - pTmpFile1 = gv_FlmSysData.pLrnuFile; - while (pTmpFile1) - { - if (pTmpFile1 == pTmpFile) - { - flmFreeFile( pTmpFile); - break; - } - pTmpFile1 = pTmpFile1->pNextNUFile; - } - } - - if (bUsedFFile) - { - if (!bMutexLocked) - { - f_mutexLock( gv_FlmSysData.hShareMutex); - bMutexLocked = TRUE; - } - if (!(--pFile->uiUseCount)) - { - flmLinkFileToNUList( pFile); - } - } - if (bMutexLocked) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - bMutexLocked = FALSE; - } - - /* Unlock the file, if it is locked. */ - - if (bWriteLocked) - { - dbWriteUnlock( pFile); - bWriteLocked = FALSE; - } - - if (bFileLocked) - { - RCODE rc3; - - if (RC_BAD( rc3 = pFileLockObj->Unlock( TRUE, NULL))) - { - if (RC_OK( rc)) - { - rc = rc3; - } - } - bFileLocked = FALSE; - } - - if( pSFileHdl) - { - pSFileHdl->Release(); - } - - if( pECacheMgr) - { - pECacheMgr->Release(); - pECacheMgr = NULL; - } - - if (pWriteLockObj) - { - pWriteLockObj->Release(); - pWriteLockObj = NULL; - } - if (pFileLockObj) - { - pFileLockObj->Release(); - pFileLockObj = NULL; - } - - if (pLockFileHdl) - { - (void)pLockFileHdl->Close(); - pLockFileHdl->Release(); - pLockFileHdl = NULL; - } - - if( pDefaultCreateOpts) - { - f_free( &pDefaultCreateOpts); - } - - if (pRebuildState) - { - if( puiTotRecsRV) - { - *puiTotRecsRV = pRebuildState->CallbackData.uiTotRecs; - } - - if( puiRecsRecovRV) - { - *puiRecsRecovRV = pRebuildState->CallbackData.uiRecsRecov; - } - - if ((pRebuildState->pStateInfo) && - (pRebuildState->pStateInfo->pRecord)) - { - pRebuildState->pStateInfo->pRecord->Release(); - - } - - if (pRebuildState->pRecord) - { - pRebuildState->pRecord->Release(); - pRebuildState->pRecord = NULL; - } - - if( pRebuildState->pHdrInfo) - { - f_free( &pRebuildState->pHdrInfo); - } - - if( pRebuildState->pStateInfo) - { - f_free( &pRebuildState->pStateInfo); - } - - if( pRebuildState->pLogHdr) - { - f_free( &pRebuildState->pLogHdr); - } - - if( pRebuildState->pKeyBuffer) - { - f_free( &pRebuildState->pKeyBuffer); - } - - f_free( &pRebuildState); - } - else - { - if( puiTotRecsRV) - { - *puiTotRecsRV = 0; - } - - if( puiRecsRecovRV) - { - *puiRecsRecovRV = 0; - } - } - - return( rc); -} - - -/*************************************************************************** -Desc: This routine reads through a database and makes a best guess as to - the true block size of the database. -*****************************************************************************/ -FSTATIC RCODE bldDetermineBlkSize( - F_SuperFileHdl * pSFileHdl, // Super file handle for database. - FLMUINT uiMaxFileSize, - FLMUINT * puiBlkSizeRV, // Calculated block size is returned here. - STATUS_HOOK fnStatusFunc, // Callback function. - REBUILD_INFO * pCallbackData, // Callback structure. - void * AppArg) // User data for callback. -{ - RCODE rc = FERR_OK; - FLMBYTE ucBlkHeader [BH_OVHD]; - FLMUINT uiBytesRead; - FLMUINT uiBlkAddress; - FLMUINT uiFileNumber = 0; - FLMUINT uiOffset = 0; - FLMUINT uiCount4K = 0; - FLMUINT uiCount8K = 0; - FLMUINT64 ui64BytesDone = 0; - F_FileHdlImp * pFileHdl = NULL; - - /* Start from byte offset 0 in the first file. */ - - pCallbackData->iDoingFlag = REBUILD_GET_BLK_SIZ; - pCallbackData->bStartFlag = TRUE; - for (;;) - { - if (uiOffset >= uiMaxFileSize || !uiFileNumber) - { - uiOffset = 0; - uiFileNumber++; - if (RC_BAD( rc = pSFileHdl->GetFileHdl( - uiFileNumber, FALSE, &pFileHdl))) - { - if (rc == FERR_IO_PATH_NOT_FOUND) - { - rc = RC_SET( FERR_IO_END_OF_FILE); - break; - } - goto Exit; - } - } - - if ((RC_OK(rc = pFileHdl->Read( uiOffset, BH_OVHD, ucBlkHeader, - &uiBytesRead))) || - (rc == FERR_IO_END_OF_FILE)) - { - if (RC_OK( rc)) - { - ui64BytesDone += (FLMUINT64)MIN_BLOCK_SIZE; - } - else - { - ui64BytesDone += (FLMUINT64)uiBytesRead; - } - uiBlkAddress = GET_BH_ADDR( ucBlkHeader); - if ((uiBytesRead == BH_OVHD) && - (FSGetFileOffset( uiBlkAddress) == uiOffset)) - { - if (uiOffset % 4096 == 0) - uiCount4K++; - if (uiOffset % 8192 == 0) - uiCount8K++; - } - if (rc != FERR_OK || uiBytesRead < BH_OVHD) - { - - // Even if the file is not full size, set offset to - // the maximum file offset so we will attempt to go - // to the next file at the top of this loop. If that - // fails, we will assume we truly are at EOF. - - uiOffset = uiMaxFileSize; - } - else - { - uiOffset += MIN_BLOCK_SIZE; - } - - /* Call the callback function to report copy progress. */ - - if (fnStatusFunc != NULL) - { - pCallbackData->ui64BytesExamined = ui64BytesDone; - if (RC_BAD( rc = (*fnStatusFunc)( FLM_REBUILD_STATUS, - (void *)pCallbackData, - (void *)0, - AppArg))) - { - goto Exit; - } - pCallbackData->bStartFlag = FALSE; - } - - f_yieldCPU(); - } - else - { - goto Exit; - } - } - if (rc == FERR_IO_END_OF_FILE) - rc = FERR_OK; - - // If our count of 4K blocks is greater than 66% of the number - // of 4K blocks that would fit in the database, we will use - // a 4K block size. Otherwise, we will use an 8K block size. - - if (uiCount4K > - (FLMUINT)(((ui64BytesDone / - (FLMUINT64)4096) * (FLMUINT64)66) / (FLMUINT64)100)) - { - *puiBlkSizeRV = 4096; - } - else - { - *puiBlkSizeRV = 8192; - } -Exit: - return( rc); -} diff --git a/flaim/src/flblksum.cpp b/flaim/src/flblksum.cpp deleted file mode 100644 index d66dcd1..0000000 --- a/flaim/src/flblksum.cpp +++ /dev/null @@ -1,301 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Calculate block checksum. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flblksum.cpp 12260 2006-01-19 14:40:25 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/******************************************************************** -Desc: Compares or sets the checksum value in a block. - Operates to compare the block checksum with the actual checksum. -Ret: if (Compare) returns FERR_BLOCK_CHECKSUM block checksum does - not agree with checksum header values. -*********************************************************************/ -RCODE BlkCheckSum( - FLMBYTE * pucBlkPtr, // Points to block - FLMINT iCompare, // TRUE compare checksums, FALSE set chksum - // Use CHECKSUM_CHECK or CHECKSUM_SET - FLMUINT uiBlkAddress, // Expected block address (3.x version) - FLMUINT uiBlkSize // Used to verify that we don't read outside - // of an allocation. - ) -{ - RCODE rc = FERR_OK; -#if !((defined( FLM_WIN) && !defined( FLM_64BIT)) || defined( FLM_NLM)) - FLMBYTE ucTmp; - FLMBYTE * pucCur; - FLMBYTE * pucEnd; -#endif - FLMUINT uiAdds; - FLMUINT uiXORs; - FLMUINT uiCurrCheckSum = 0; - FLMUINT uiNewCheckSum; - FLMUINT uiEncryptSize; - FLMBYTE * pucSaveBlkPtr = pucBlkPtr; - - // Check the block length against the maximum block size - - uiEncryptSize = (FLMUINT)getEncryptSize( pucBlkPtr); - if( uiEncryptSize > uiBlkSize || uiEncryptSize < BH_OVHD) - { - rc = RC_SET( FERR_BLOCK_CHECKSUM); - goto Exit; - } - - // If we are comparing, but there is no current checksum just return. - // The next time the checksum is modified, the comparison will be performed. - // Version 3.x will store the full block address or if - // a checksum is used, the lost low byte of block address is checksummed. - - if( iCompare == CHECKSUM_CHECK) - { - uiCurrCheckSum = (FLMUINT)(((FLMUINT)pucBlkPtr[ BH_CHECKSUM_HIGH] << 8) + - (FLMUINT)pucBlkPtr[ BH_CHECKSUM_LOW]); - } - - // We need to checksum the data that is encrypted. - // This is done by the getEncryptSize() call. - - // Check all of block, except for embedded checksum bytes. - // For speed, the initial values of uiAdds and uiXORs effectively ignore/skip - // the checksum values already embedded in the source: (a - a) == 0 and - // (a ^ a) == 0 so the initial values, net of the 2nd operations, equal zero - // too. - - uiAdds = 0 - (pucBlkPtr[ BH_CHECKSUM_LOW] + pucBlkPtr[ BH_CHECKSUM_HIGH]); - uiXORs = pucBlkPtr[ BH_CHECKSUM_LOW] ^ pucBlkPtr[ BH_CHECKSUM_HIGH]; - - // The 3.x version checksums the low byte of the address. - - if( uiBlkAddress != BT_END) - { - uiAdds += (FLMBYTE)uiBlkAddress; - uiXORs ^= (FLMBYTE)uiBlkAddress; - } - -#if defined( FLM_NLM) || (defined( FLM_WIN) && !defined( FLM_64BIT)) - - FastBlockCheckSum( pucBlkPtr, &uiAdds, &uiXORs, - (unsigned long)uiEncryptSize); - -#else - -#ifdef FLM_64BIT - pucCur = pucBlkPtr; - pucEnd = pucBlkPtr + (uiEncryptSize & 0xFFFFFFFFFFFFFFF8); -#else - pucCur = pucBlkPtr; - pucEnd = pucBlkPtr + (uiEncryptSize & 0xFFFFFFFC); -#endif - - while( pucCur < pucEnd) - { - FLMUINT uiValue = *(FLMUINT *)pucCur; - - uiXORs ^= uiValue; - - uiAdds += (FLMBYTE)uiValue; - - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; - - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; - -#ifdef FLM_64BIT - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; - - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; - - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; - - uiValue >>= 8; - uiAdds += (FLMBYTE)uiValue; -#endif - - uiAdds += (FLMBYTE)(uiValue >> 8); - pucCur += sizeof( FLMUINT); - } - - ucTmp = (FLMBYTE)uiXORs; - ucTmp ^= (FLMBYTE)(uiXORs >> 8); - ucTmp ^= (FLMBYTE)(uiXORs >> 16); - ucTmp ^= (FLMBYTE)(uiXORs >> 24); -#ifdef FLM_64BIT - ucTmp ^= (FLMBYTE)(uiXORs >> 32); - ucTmp ^= (FLMBYTE)(uiXORs >> 40); - ucTmp ^= (FLMBYTE)(uiXORs >> 48); - ucTmp ^= (FLMBYTE)(uiXORs >> 56); -#endif - uiXORs = ucTmp; - - pucCur = pucEnd; - pucEnd = pucBlkPtr + uiEncryptSize; - - while( pucCur < pucEnd) - { - uiAdds += *pucCur; - uiXORs ^= *pucCur++; - } -#endif - - uiNewCheckSum = (((uiAdds << 8) + uiXORs) & 0xFFFF); - - // Set the checksum - - if (iCompare == CHECKSUM_SET) - { - pucSaveBlkPtr[ BH_CHECKSUM_HIGH] = (FLMBYTE)(uiNewCheckSum >> 8); - pucSaveBlkPtr[ BH_CHECKSUM_LOW] = (FLMBYTE)uiNewCheckSum; - goto Exit; - } - - - // The checksum is different from the stored checksum. - // For version 3.x database we don't store the low byte of the - // address. Thus, it will have to be computed from the checksum. - - if( uiBlkAddress == BT_END) - { - FLMBYTE byXor; - FLMBYTE byAdd; - FLMBYTE byDelta; - - // If there is a one byte value that will satisfy both - // sides of the checksum, the checksum is OK and that value - // is the first byte value. - - byXor = (FLMBYTE) uiNewCheckSum; - byAdd = (FLMBYTE) (uiNewCheckSum >> 8); - byDelta = byXor ^ pucSaveBlkPtr [BH_CHECKSUM_LOW]; - - // Here is the big check, if byDelta is also what is - // off with the add portion of the checksum, we have - // a good value. - - if( ((FLMBYTE) (byAdd + byDelta)) == pucSaveBlkPtr[ BH_CHECKSUM_HIGH] ) - { - // Set the low checksum value with the computed value. - - pucSaveBlkPtr[ BH_CHECKSUM_LOW] = byDelta; - goto Exit; - } - } - else - { - // This has the side effect of setting the low block address byte - // in the block thus getting rid of the low checksum byte. - - // NOTE: We are allowing the case where the calculated checksum is - // zero and the stored checksum is one because we used to change - // a calculated zero to a one in old databases and store the one. - // This is probably a somewhat rare case (1 out of 65536 checksums - // will be zero), so forgiving it will be OK most of the time. - // So that those don't cause us to report block checksum errors, - // we just allow it - checksumming isn't a perfect check anyway. - // VISIT: We do eventually want to get rid of this forgiving code. - - if (uiNewCheckSum == uiCurrCheckSum || - ((!uiNewCheckSum) && (uiCurrCheckSum == 1))) - { - pucSaveBlkPtr [BH_CHECKSUM_LOW] = (FLMBYTE) uiBlkAddress; - goto Exit; - } - } - - // Otherwise, we have a checksum error. - - rc = RC_SET( FERR_BLOCK_CHECKSUM); - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: ? -*********************************************************************/ -FLMUINT lgHdrCheckSum( - FLMBYTE * pucLogHdr, - FLMBOOL bCompare - ) -{ - FLMUINT uiCnt; - FLMUINT uiTempSum; - FLMUINT uiCurrCheckSum; - FLMUINT uiTempSum2; - FLMUINT uiBytesToChecksum; - - uiBytesToChecksum = (FB2UW( &pucLogHdr [LOG_FLAIM_VERSION]) < FLM_VER_4_3) - ? LOG_HEADER_SIZE_VER40 - : LOG_HEADER_SIZE; - -/* -If we are comparing, but there is no current checksum, return -zero to indicate success. The next time the checksum is -modified, the comparison will be performed. -*/ - -/* -Unconverted databases may have a 0xFFFF or a zero in the checksum -If 0xFFFF, change to a zero so we only have to deal with one value. -*/ - - if( (uiCurrCheckSum = (FLMUINT)FB2UW( &pucLogHdr[ LOG_HDR_CHECKSUM])) == 0xFFFF) - uiCurrCheckSum = 0; - - if( (bCompare) && (!uiCurrCheckSum)) - return( 0); - - for( - /* - Check all of log header except for the bytes which contain the - checksum. - - For speed, uiTempSum is initialized to effectively ignore or skip - the checksum embedded in the source: (a - a) == 0 so we store a negative - that the later addition clears out. Also, the loop counter, i, - is 1 larger than the number of FLMUINT16's so that we can - pre-decrement by "for(;--i != 0;)" -- basically "loop-non-zero". - */ - - uiTempSum = 0 - (FLMUINT)FB2UW( &pucLogHdr[ LOG_HDR_CHECKSUM]), - uiCnt = 1 + uiBytesToChecksum / sizeof( FLMUINT16) - ; --uiCnt != 0; ) - { - uiTempSum += (FLMUINT)FB2UW( pucLogHdr); - pucLogHdr += sizeof( FLMUINT16); - } - -/* Don't want a zero or 0xFFFF checksum - change to 1 */ - - if( (0 == (uiTempSum2 = (uiTempSum & 0xFFFF))) || (uiTempSum2 == 0xFFFF)) - uiTempSum2 = 1; - - return( (FLMUINT)(((bCompare) && (uiTempSum2 == uiCurrCheckSum)) - ? (FLMUINT)0 - : uiTempSum2) ); -} - diff --git a/flaim/src/flchkdb.cpp b/flaim/src/flchkdb.cpp index f35825e..eecef56 100644 --- a/flaim/src/flchkdb.cpp +++ b/flaim/src/flchkdb.cpp @@ -1,626 +1,4835 @@ -//------------------------------------------------------------------------- -// Desc: Check database for corruptions. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flchkdb.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE chkGetDictInfo( - DB_INFO * pDbInfo); - -FSTATIC RCODE chkVerifyBlkChain( - DB_INFO * pDbInfo, - BLOCK_INFO * pBlkInfo, - eCorruptionLocale eLocale, - FLMUINT uiFirstBlkAddr, - FLMUINT uiBlkType, - FLMUINT * puiBlkCount, - FLMBOOL * pbStartOverRV); - -FSTATIC RCODE chkVerifyLFHBlocks( - DB_INFO * pDbInfo, - FLMBOOL * pbStartOverRV); - -FSTATIC RCODE chkVerifyAvailList( - DB_INFO * pDbInfo, - FLMBOOL * pbStartOverRV); - -/*API~*********************************************************************** -Desc: Checks for physical corruption in a FLAIM database. -Note: The routine verifies the database by first reading through - the database to count certain block types which are in linked lists. - It then verifies the linked lists. It also verifies the B-TREEs - in the database. The reason for the first pass is so that when we - verify the linked lists, we can keep ourselves from getting into - an infinite loop if there is a loop in the lists. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbCheck( - HFDB hDb, - const char * pDbFileName, - const char * pszDataDir, - const char * pRflDir, - FLMUINT uiCheckFlags, - POOL * pPool, - DB_CHECK_PROGRESS * pCheckProgress, - STATUS_HOOK fnStatusFunc, - void * AppArg) -{ - RCODE rc = FERR_OK; - F_SuperFileHdl * pSFileHdl = NULL; - FLMBYTE * pBlk = NULL; - FLMUINT uiFileEnd; - FLMUINT uiBlockSize; - DB_CHECK_PROGRESS Progress; - FLMBOOL bOpenedDb = FALSE; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - FLMUINT uiLoop; - FLMUINT uiTmpSize; - FLMBOOL bStartOver; - FLMBOOL bOkToCloseTrans = FALSE; - DB_INFO * pDbInfo; - POOL localPool; - void * pvDbInfoMark; - - if( hDb != HFDB_NULL && IsInCSMode( hDb)) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto ExitCS; - } - - GedPoolInit( &localPool, 512); - - if( !pPool) - { - pPool = &localPool; - } - - pDbInfo = (DB_INFO *)GedPoolCalloc( pPool, sizeof( DB_INFO)); - - pvDbInfoMark = GedPoolMark( pPool); - - if( hDb == HFDB_NULL) - { - if( RC_BAD( rc = FlmDbOpen( pDbFileName, pszDataDir, - pRflDir, 0, NULL, &hDb))) - { - goto Exit; - } - - bOpenedDb = TRUE; - pDb = (FDB *)hDb; - } - - pDbInfo->fnStatusFunc = fnStatusFunc; - pDbInfo->LastStatusRc = FERR_OK; - pDbInfo->pDb = pDb; - - if( pCheckProgress) - { - pDbInfo->pProgress = pCheckProgress; - } - else - { - pDbInfo->pProgress = &Progress; - } - - f_memset( pDbInfo->pProgress, 0, sizeof( DB_CHECK_PROGRESS)); - - pDbInfo->bDbInitialized = TRUE; - if( RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, 0, 0, &bIgnore))) - { - goto Exit; - } - - // Initialize the information block and Progress structure. - - // Because FlmDbCheck will start and stop read transactions during its - // processing we can't allow any existing read transactions to exist. - // However, it is OK for an update transaction to be in progress. An update - // transaction will NOT be stopped and restarted. The only reason a read - // transaction may be stopped and restarted is if we get an old view - // error - something that cannot normally happen during an update - // transaction. - - if( flmGetDbTransType( pDb) == FLM_READ_TRANS) - { - // If it is an invisible transaction, it may be aborted. - - if( pDb->uiFlags & FDB_INVISIBLE_TRANS) - { - if( RC_BAD( rc = flmAbortDbTrans( pDb))) - { - goto Exit; - } - } - else - { - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - } - - // Since we know that the check will start read transactions - // during its processing, set the flag to indicate that the KRef table - // should be cleaned up on exit if we are still in a read transaction. - - bOkToCloseTrans = TRUE; - uiBlockSize = pDb->pFile->FileHdr.uiBlockSize; - - // Check does its own reads using the handle to the file. - - pSFileHdl = pDb->pSFileHdl; - pDbInfo->pSFileHdl = pSFileHdl; - - // Allocate memory to use for reading through the data blocks. - - if( RC_BAD( rc = f_alloc( uiBlockSize, &pBlk))) - { - goto Exit; - } - -Begin_Check: - - // Initialize all statistics in the DB_INFO structure. - - rc = FERR_OK; - bStartOver = FALSE; - - GedPoolReset( pPool, pvDbInfoMark); - pDbInfo->pProgress->bPhysicalCorrupt = FALSE; - pDbInfo->pProgress->bLogicalIndexCorrupt = FALSE; - pDbInfo->pProgress->ui64DatabaseSize = 0; - pDbInfo->pProgress->uiNumFields = 0; - pDbInfo->pProgress->uiNumIndexes = 0; - pDbInfo->pProgress->uiNumContainers = 0; - pDbInfo->pProgress->uiNumLogicalFiles = 0; - pDbInfo->pLogicalFiles = NULL; - pDbInfo->pProgress->pLfStats = NULL; - pDbInfo->uiFlags = uiCheckFlags; - pDbInfo->uiMaxLockWait = 15; - pDbInfo->bStartedUpdateTrans = FALSE; - f_memset( &pDbInfo->pProgress->AvailBlocks, 0, sizeof( BLOCK_INFO)); - f_memset( &pDbInfo->pProgress->LFHBlocks, 0, sizeof( BLOCK_INFO)); - f_memset( &pDbInfo->FileHdr, 0, sizeof( FILE_HDR)); - f_memset( &Progress, 0, sizeof( DB_CHECK_PROGRESS)); - Progress.AppArg = AppArg; - - // Get the dictionary information for the file - - if (RC_BAD( rc = chkGetDictInfo( pDbInfo))) - { - goto Exit; - } - - Progress.ui64BytesExamined = 0; - - for (uiLoop = 1; - uiLoop <= - MAX_DATA_BLOCK_FILE_NUMBER( - pDb->pFile->FileHdr.uiVersionNum); - uiLoop++) - { - if (RC_BAD( pSFileHdl->GetFileSize( uiLoop, &uiTmpSize))) - { - break; - } - Progress.ui64DatabaseSize += (FLMUINT64)uiTmpSize; - } - - // See if we have a valid end of file - - uiFileEnd = pDbInfo->pDb->LogHdr.uiLogicalEOF; - if( FSGetFileOffset( uiFileEnd) % uiBlockSize != 0) - { - if( RC_BAD( rc = chkReportError( pDbInfo, FLM_BAD_FILE_SIZE, - LOCALE_NONE, 0, 0, 0xFF, uiFileEnd, 0, 0, 0, 0xFFFF, 0, NULL))) - { - goto Exit; - } - } - else if (Progress.ui64DatabaseSize < FSGetSizeInBytes( - pDbInfo->pDb->pFile->uiMaxFileSize, - uiFileEnd)) - { - Progress.ui64DatabaseSize = FSGetSizeInBytes( - pDbInfo->pDb->pFile->uiMaxFileSize, - uiFileEnd); - } - - // Verify and count the LFH and PCODE blocks, B-Trees, and the - // AVAIL list. - - if( RC_BAD( rc = chkVerifyLFHBlocks( pDbInfo, &bStartOver))) - { - goto Exit; - } - - if( bStartOver) - { - goto Begin_Check; - } - - // Check the b-trees. - - if (RC_BAD( rc = chkVerifyBTrees( pDbInfo, pPool, &bStartOver))) - { - goto Exit; - } - if (bStartOver) - { - goto Begin_Check; - } - - // Check the avail list. - - if (RC_BAD( rc = chkVerifyAvailList( pDbInfo, &bStartOver))) - { - goto Exit; - } - if (bStartOver) - { - goto Begin_Check; - } - - // Signal that we are finished. - - pDbInfo->pProgress->iCheckPhase = CHECK_FINISHED; - pDbInfo->pProgress->bStartFlag = TRUE; - if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) - { - goto Exit; - } - pDbInfo->pProgress->bStartFlag = FALSE; - -Exit: - - // Pass out any error code returned by the callback. - - if ((RC_OK( rc)) && (RC_BAD( pDbInfo->LastStatusRc))) - { - rc = pDbInfo->LastStatusRc; - } - - if (pDb && pDbInfo->bDbInitialized) - { - - // Close down the transaction, if one is going - - if( bOkToCloseTrans && - flmGetDbTransType( pDb) == FLM_READ_TRANS) - { - KrefCntrlFree( pDb); - (void)flmAbortDbTrans( pDb); - } - - fdbExit( pDb); - } - - // Free memory, if allocated - - if (pBlk) - { - f_free( &pBlk); - } - - // Close the database we opened. - - if( bOpenedDb) - { - (void)FlmDbClose( &hDb); - } - - GedPoolFree( &localPool); - -ExitCS: - - return( rc); -} - -/*************************************************************************** -Desc: This routine opens a file and reads its dictionary into memory. -*****************************************************************************/ -FSTATIC RCODE chkGetDictInfo( - DB_INFO * pDbInfo) -{ - RCODE rc = FERR_OK; - FDB * pDb = pDbInfo->pDb; - - // Close down the transaction, if one is going. - - if (flmGetDbTransType( pDb) != FLM_UPDATE_TRANS) - { - if (pDb->uiTransType == FLM_READ_TRANS) - { - (void)flmAbortDbTrans( pDb); - } - - // Start a read transaction on the file to ensure we are connected - // to the file's dictionary structures. - - if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_READ_TRANS, - 0, FLM_DONT_POISON_CACHE))) - { - goto Exit; - } - f_memcpy( &pDbInfo->FileHdr, &pDb->pFile->FileHdr, sizeof( FILE_HDR)); - pDbInfo->pProgress->uiVersionNum = pDbInfo->FileHdr.uiVersionNum; - pDbInfo->pProgress->uiBlockSize = pDbInfo->FileHdr.uiBlockSize; - pDbInfo->pProgress->uiDefaultLanguage = pDbInfo->FileHdr.uiDefaultLanguage; - } - -Exit: - return( rc); -} - -/******************************************************************** -Desc: This routine follows all of the blocks in a chain, verifying - that they are properly linked. It also verifies each block's - header. -*********************************************************************/ -FSTATIC RCODE chkVerifyBlkChain( - DB_INFO * pDbInfo, - BLOCK_INFO * pBlkInfo, - eCorruptionLocale eLocale, - FLMUINT uiFirstBlkAddr, - FLMUINT uiBlkType, - FLMUINT * puiBlkCount, - FLMBOOL * pbStartOverRV) -{ - RCODE rc = FERR_OK; - eCorruptionType eCorruption = FLM_NO_CORRUPTION; - SCACHE * pSCache = NULL; - FLMBYTE * pBlk = NULL; - FLMUINT uiPrevBlkAddress; - FLMUINT uiBlkCount = 0; - STATE_INFO StateInfo; - FLMBOOL bStateInitialized = FALSE; - FLMUINT64 ui64SaveBytesExamined; - FDB * pDb = pDbInfo->pDb; - FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; - FLMUINT uiVersionNum = pFileHdr->uiVersionNum; - FLMUINT uiBlockSize = pFileHdr->uiBlockSize; - FLMUINT uiMaxBlocks = - (FLMUINT)(FSGetSizeInBytes( - pDb->pFile->uiMaxFileSize, - pDb->LogHdr.uiLogicalEOF) / - (FLMUINT64)uiBlockSize); - - uiPrevBlkAddress = BT_END; - - /* There must be at least ONE block if it is the LFH chain. */ - - if ((uiBlkType == BHT_LFH_BLK) && (uiFirstBlkAddr == BT_END)) - { - eCorruption = FLM_BAD_LFH_LIST_PTR; - (void)chkReportError( pDbInfo, eCorruption, eLocale, - 0, 0, 0xFF, 0, 0, 0, 0, 0xFFFF, 0, NULL); - goto Exit; - } - - /* Read through all of the blocks, verifying them as we go. */ - -Restart_Chain: - uiBlkCount = 0; - flmInitReadState( &StateInfo, &bStateInitialized, uiVersionNum, - pDb, NULL, - (FLMUINT)((uiBlkType == BHT_FREE) ? (FLMUINT)0xFF : (FLMUINT)0), - uiBlkType, NULL); - ui64SaveBytesExamined = pDbInfo->pProgress->ui64BytesExamined; - StateInfo.uiBlkAddress = uiFirstBlkAddr; - while ((StateInfo.uiBlkAddress != BT_END) && (uiBlkCount < uiMaxBlocks)) - { - StateInfo.pBlk = NULL; - if (RC_BAD( rc = chkBlkRead( pDbInfo, - StateInfo.uiBlkAddress, - StateInfo.pLogicalFile ? StateInfo.pLogicalFile->pLFile : NULL, - &pBlk, &pSCache, &eCorruption))) - { - if (rc == FERR_OLD_VIEW) - { - FLMUINT uiSaveDictSeq = pDb->pDict->uiDictSeq; - - if (RC_BAD( rc = chkGetDictInfo( pDbInfo))) - goto Exit; - - /* If the dictionary ID changed, start over. */ - - if (pDb->pDict->uiDictSeq != uiSaveDictSeq) - { - *pbStartOverRV = TRUE; - goto Exit; - } - - pDbInfo->pProgress->ui64BytesExamined = ui64SaveBytesExamined; - goto Restart_Chain; - } - pBlkInfo->eCorruption = eCorruption; - pBlkInfo->uiNumErrors++; - rc = chkReportError( pDbInfo, eCorruption, - eLocale, 0, 0, 0xFF, - StateInfo.uiBlkAddress, - 0, 0, 0, 0xFFFF, 0, pBlk); - } - StateInfo.pBlk = pBlk; - uiBlkCount++; - pDbInfo->pProgress->ui64BytesExamined += (FLMUINT64)uiBlockSize; - if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) - { - goto Exit; - } - - f_yieldCPU(); - - if ((eCorruption = flmVerifyBlockHeader( &StateInfo, pBlkInfo, - uiBlockSize, 0, - (uiBlkType == BHT_FREE) - ? 0L : uiPrevBlkAddress, TRUE, TRUE)) != FLM_NO_CORRUPTION) - { - pBlkInfo->eCorruption = eCorruption; - pBlkInfo->uiNumErrors++; - chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, - StateInfo.uiBlkAddress, - 0, 0, 0, 0xFFFF, 0, pBlk); - goto Exit; - } - uiPrevBlkAddress = StateInfo.uiBlkAddress; - StateInfo.uiBlkAddress = (FLMUINT)FB2UD( &pBlk [BH_NEXT_BLK]); - } - if ((StateInfo.uiBlkAddress != BT_END) && - (RC_OK( pDbInfo->LastStatusRc))) - { - switch (uiBlkType) - { - case BHT_LFH_BLK: - eCorruption = FLM_BAD_LFH_LIST_END; - break; - case BHT_PCODE_BLK: - eCorruption = FLM_BAD_PCODE_LIST_END; - break; - case BHT_FREE: - eCorruption = FLM_BAD_AVAIL_LIST_END; - break; - } - pBlkInfo->eCorruption = eCorruption; - pBlkInfo->uiNumErrors++; - chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, - uiPrevBlkAddress, 0, 0, 0, 0xFFFF, 0, - pBlk); - goto Exit; - } - -Exit: - if (puiBlkCount) - { - *puiBlkCount = uiBlkCount; - } - if (bStateInitialized && StateInfo.pRecord) - { - StateInfo.pRecord->Release(); - } - - if( pSCache) - { - ScaReleaseCache( pSCache, FALSE); - } - else if( pBlk) - { - f_free( &pBlk); - } - - if (RC_OK(rc) && (eCorruption != FLM_NO_CORRUPTION)) - { - rc = (uiBlkType == BHT_FREE) - ? RC_SET( FERR_DATA_ERROR) - : RC_SET( FERR_DD_ERROR); - } - - return( rc); -} - - -/*************************************************************************** -Desc: This routine verifies the LFH blocks. -*****************************************************************************/ -FSTATIC RCODE chkVerifyLFHBlocks( - DB_INFO * pDbInfo, - FLMBOOL * pbStartOverRV) -{ - RCODE rc = FERR_OK; - - pDbInfo->pProgress->uiLfNumber = 0; - pDbInfo->pProgress->uiLfType = 0; - pDbInfo->pProgress->iCheckPhase = CHECK_LFH_BLOCKS; - pDbInfo->pProgress->bStartFlag = TRUE; - if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) - { - goto Exit; - } - pDbInfo->pProgress->bStartFlag = FALSE; - - f_yieldCPU(); - - // Go through the LFH blocks. - - if (RC_BAD( rc = chkVerifyBlkChain( pDbInfo, &pDbInfo->pProgress->LFHBlocks, - LOCALE_LFH_LIST, - pDbInfo->pDb->pFile->FileHdr.uiFirstLFHBlkAddr, - BHT_LFH_BLK, NULL, pbStartOverRV)) || - *pbStartOverRV) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: This routine reads through the blocks in the AVAIL list and verifies - that we don't have a loop or some other corruption in the list. -*****************************************************************************/ -FSTATIC RCODE chkVerifyAvailList( - DB_INFO * pDbInfo, /* Pointer to structure where statistics - and other information are returned. */ - FLMBOOL * pbStartOverRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiBlkCount; - - pDbInfo->pProgress->uiLfNumber = 0; - pDbInfo->pProgress->uiLfType = 0; - pDbInfo->pProgress->iCheckPhase = CHECK_AVAIL_BLOCKS; - pDbInfo->pProgress->bStartFlag = TRUE; - if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) - { - goto Exit; - } - pDbInfo->pProgress->bStartFlag = FALSE; - - f_yieldCPU(); - - if (RC_BAD( rc = chkVerifyBlkChain( pDbInfo, - &pDbInfo->pProgress->AvailBlocks, - LOCALE_AVAIL_LIST, - pDbInfo->pDb->LogHdr.uiFirstAvailBlkAddr, - BHT_FREE, &uiBlkCount, pbStartOverRV)) || - *pbStartOverRV) - { - goto Exit; - } - - // See if the block count matches the block count stored in the - // log header. - - if (uiBlkCount != pDbInfo->pDb->LogHdr.uiAvailBlkCount) - { - (void)chkReportError( pDbInfo, FLM_BAD_AVAIL_BLOCK_COUNT, - LOCALE_AVAIL_LIST, - 0, 0, 0xFF, 0, 0, 0, 0, 0xFFFF, 0, NULL); - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - -Exit: - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Check database for corruptions. +// Tabs: 3 +// +// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: flchkdb.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC RCODE chkGetDictInfo( + DB_INFO * pDbInfo); + +FSTATIC RCODE chkVerifyBlkChain( + DB_INFO * pDbInfo, + BLOCK_INFO * pBlkInfo, + eCorruptionLocale eLocale, + FLMUINT uiFirstBlkAddr, + FLMUINT uiBlkType, + FLMUINT * puiBlkCount, + FLMBOOL * pbStartOverRV); + +FSTATIC RCODE chkVerifyLFHBlocks( + DB_INFO * pDbInfo, + FLMBOOL * pbStartOverRV); + +FSTATIC RCODE chkVerifyAvailList( + DB_INFO * pDbInfo, + FLMBOOL * pbStartOverRV); + +FSTATIC RCODE chkVerifyTrackerCounts( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndexNum, + FLMUINT uiKeyCount, + FLMUINT uiRefCount); + +FSTATIC RCODE chkIsCountIndex( + STATE_INFO * pStateInfo, + FLMUINT uiIndexNum, + FLMBOOL * pbIsCountIndex); + +FSTATIC RCODE chkResolveRSetMissingKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIxRefDrn); + +FSTATIC RCODE chkVerifyDelNonUniqueRec( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiRecDrn, + FLMUINT * puiRecContainerRV, + FLMBOOL * pbDelRecRV); + +FSTATIC RCODE chkVerifyKeyExists( + FDB * pDb, + LFILE * pLFile, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiRefDrn, + FLMBOOL * pbFoundRV); + +FSTATIC RCODE chkAddDelKeyRef( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndexNum, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn, + FLMUINT uiFlags); + +FSTATIC RCODE chkGetKeySource( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn, + FLMUINT * puiRecordContainerRV, + FLMBOOL * pbKeyInRecRV, + FLMBOOL * pbKeyInIndexRV); + +FSTATIC RCODE chkReportIxError( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + eCorruptionType eCorruption, + FLMUINT uiErrIx, + FLMUINT uiErrDrn, + FLMBYTE * pucErrKey, + FLMUINT uiErrKeyLen, + FLMBOOL * pbFixErrRV); + +FSTATIC RCODE chkGetNextRSKey( + IX_CHK_INFO * pIxChkInfo); + +FSTATIC RCODE chkResolveIXMissingKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo); + +FSTATIC RCODE chkRSInit( + const char * pszIoPath, + void ** pRSetRV); + +FSTATIC RCODE chkRSFinalize( + IX_CHK_INFO * pIxChkInfo, + FLMUINT64 * pui64TotalEntries); + +FSTATIC FLMINT chkCompareKeySet( + FLMUINT uiIxNum1, + FLMBYTE * pData1, + FLMUINT uiLength1, + FLMUINT uiDrn1, + FLMUINT uiIxNum2, + FLMBYTE * pData2, + FLMUINT uiLength2, + FLMUINT uiDrn2); + +FSTATIC RCODE chkBlkRead( + DB_INFO * pDbInfo, + FLMUINT uiBlkAddress, + LFILE * pLFile, + FLMBYTE ** ppBlk, + SCACHE ** ppSCache, + eCorruptionType * peCorruption); + +FSTATIC RCODE chkVerifyBTrees( + DB_INFO * pDbInfo, + POOL * pPool, + FLMBOOL * pbStartOverRV); + +FSTATIC RCODE chkReportError( + DB_INFO * pDbInfo, + eCorruptionType eCorruption, + eCorruptionLocale eErrLocale, + FLMUINT uiErrLfNumber, + FLMUINT uiErrLfType, + FLMUINT uiErrBTreeLevel, + FLMUINT uiErrBlkAddress, + FLMUINT uiErrParentBlkAddress, + FLMUINT uiErrElmOffset, + FLMUINT uiErrDrn, + FLMUINT uiErrElmRecOffset, + FLMUINT uiErrFieldNum, + FLMBYTE * pBlk); + +FSTATIC RCODE chkGetNextRSKey( + IX_CHK_INFO * pIxChkInfo); + +FSTATIC RCODE chkVerifyKeyNotUnique( + STATE_INFO * pStateInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT * puiRefCountRV); + +FSTATIC RCODE chkStartUpdate( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo); + +FSTATIC RCODE chkEndUpdate( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo); + +FSTATIC FLMINT chkRSCallbackFunc( + RSET_CB_INFO * pCBInfo); + +FSTATIC RCODE chkCompareIxRSEntries( + void * vpData1, + FLMUINT uiLength1, + void * vpData2, + FLMUINT uiLength2, + void * UserValue, + FLMINT * piCompare); + +FSTATIC RCODE chkReadBlkFromDisk( + FILE_HDR * pFileHdr, + F_SuperFileHdl * pSFileHdl, + FLMUINT uiFilePos, + FLMUINT uiBlkAddress, + LFILE * pLFile, + FFILE * pFile, + FLMBYTE * pBlk); + +FSTATIC RCODE chkVerifyElmFields( + STATE_INFO * pStateInfo, + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxChkInfo, + POOL * pTmpPool, + FLMUINT * puiErrElmRecOffsetRV, + eCorruptionType * peElmErrCorruptCode); + +FSTATIC RCODE chkVerifySubTree( + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxChkInfo, + STATE_INFO * ParentState, + STATE_INFO * pStateInfo, + FLMUINT uiBlkAddress, + POOL * pTmpPool, + FLMBYTE * pucResetKey, + FLMUINT uiResetKeyLen, + FLMUINT uiResetDrn); + +FSTATIC RCODE chkGetLfInfo( + DB_INFO * pDbInfo, + POOL * pPool, + LF_STATS * pLfStats, + LFILE * pLFile, + LF_STATS * pCurrLfStats, + FLMBOOL * pbCurrLfLevelChangedRV); + +FSTATIC RCODE chkSetupLfTable( + DB_INFO * pDbInfo, + POOL * pPool); + +FSTATIC RCODE chkSetupIxInfo( + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxInfoRV); + +FSTATIC RCODE chkOutputIndexKeys( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + IXD * pIxd, + REC_KEY * pKeyList); + +/**************************************************************************** +Desc: +****************************************************************************/ +FINLINE RCODE chkCallProgFunc( + DB_INFO * pDbInfo) +{ + if( (pDbInfo->fnStatusFunc) && (RC_OK( pDbInfo->LastStatusRc))) + { + pDbInfo->LastStatusRc = (*pDbInfo->fnStatusFunc)( FLM_CHECK_STATUS, + (void *)pDbInfo->pProgress, + (void *)0, + pDbInfo->pProgress->AppArg); + } + return( pDbInfo->LastStatusRc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FINLINE RCODE chkRSGetNext( + void * pRSet, + FLMBYTE * pBuffer, + FLMUINT uiBufferLength, + FLMUINT * puiReturnLength) +{ + FLMUINT uiReturnLen; + RCODE rc; + + rc = ((FResultSet *) pRSet)->GetNext( (void *) pBuffer, uiBufferLength, + &uiReturnLen); + *puiReturnLength = (rc == FERR_OK) ? uiReturnLen : 0; + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FINLINE RCODE chkKeyToTree( + IXD * pIxd, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FlmRecord ** ppKeyRV) +{ + return (flmIxKeyOutput( pIxd, pucKey, uiKeyLen, ppKeyRV, FALSE)); +} + +/**************************************************************************** +Desc: Frees memory allocated to a result set and deletes any temporary + files that may have been created. +****************************************************************************/ +FINLINE void chkRSFree(void ** ppRSetRV) +{ + FResultSet * pRSet; + + pRSet = *((FResultSet **) ppRSetRV); + pRSet->Release(); + *ppRSetRV = (void *) 0; +} + +/**************************************************************************** +Desc: Adds a variable-length entry to a result set. +****************************************************************************/ +FINLINE RCODE chkRSAddEntry( + void * pRSet, + FLMBYTE * pEntry, + FLMUINT uiEntryLength) +{ + return (((FResultSet *) pRSet)->AddEntry( pEntry, uiEntryLength)); +} + +/**************************************************************************** +Desc: This routine counts the number of fields in an object table. +****************************************************************************/ +FINLINE void chkCountFields( + FDICT * pDict, + FLMUINT * puiNumFieldsRV) +{ + FLMUINT uiTblSize = pDict->uiIttCnt; + ITT * pItt = pDict->pIttTbl; + FLMUINT uiCount = 0; + FLMUINT uiCurrObj; + + for (uiCurrObj = 0; uiCurrObj < uiTblSize; uiCurrObj++, pItt++) + { + if (ITT_IS_FIELD( pItt)) + { + uiCount++; + } + } + + (*puiNumFieldsRV) += uiCount; +} + +/**************************************************************************** +Desc: Frees memory allocated to an IX_CHK_INFO structure +****************************************************************************/ +FINLINE RCODE chkFreeIxInfo( + IX_CHK_INFO * pIxInfoRV) +{ + GedPoolFree( &(pIxInfoRV->pool)); + chkRSFree( &(pIxInfoRV->pRSet)); + f_free( &(pIxInfoRV->puiIxArray)); + f_memset( pIxInfoRV, 0, sizeof(IX_CHK_INFO)); + + return (FERR_OK); +} + +/**************************************************************************** +Desc: Checks for physical corruption in a FLAIM database. Note: The + routine verifies the database by first reading through the database to + count certain block types which are in linked lists. It then verifies + the linked lists. It also verifies the B-TREEs in the database. The + reason for the first pass is so that when we verify the linked lists, + we can keep ourselves from getting into an infinite loop if there is + a loop in the lists. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbCheck( + HFDB hDb, + const char * pDbFileName, + const char * pszDataDir, + const char * pRflDir, + FLMUINT uiCheckFlags, + POOL * pPool, + DB_CHECK_PROGRESS * pCheckProgress, + STATUS_HOOK fnStatusFunc, + void * AppArg) +{ + RCODE rc = FERR_OK; + F_SuperFileHdl * pSFileHdl = NULL; + FLMBYTE * pBlk = NULL; + FLMUINT uiFileEnd; + FLMUINT uiBlockSize; + DB_CHECK_PROGRESS Progress; + FLMBOOL bOpenedDb = FALSE; + FDB * pDb = (FDB *) hDb; + FLMBOOL bIgnore; + FLMUINT uiLoop; + FLMUINT uiTmpSize; + FLMBOOL bStartOver; + FLMBOOL bOkToCloseTrans = FALSE; + DB_INFO * pDbInfo; + POOL localPool; + void * pvDbInfoMark; + + if (hDb != HFDB_NULL && IsInCSMode( hDb)) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto ExitCS; + } + + GedPoolInit( &localPool, 512); + + if (!pPool) + { + pPool = &localPool; + } + + pDbInfo = (DB_INFO *) GedPoolCalloc( pPool, sizeof(DB_INFO)); + + pvDbInfoMark = GedPoolMark( pPool); + + if (hDb == HFDB_NULL) + { + if (RC_BAD( rc = FlmDbOpen( pDbFileName, pszDataDir, pRflDir, 0, NULL, + &hDb))) + { + goto Exit; + } + + bOpenedDb = TRUE; + pDb = (FDB *) hDb; + } + + pDbInfo->fnStatusFunc = fnStatusFunc; + pDbInfo->LastStatusRc = FERR_OK; + pDbInfo->pDb = pDb; + + if (pCheckProgress) + { + pDbInfo->pProgress = pCheckProgress; + } + else + { + pDbInfo->pProgress = &Progress; + } + + f_memset( pDbInfo->pProgress, 0, sizeof(DB_CHECK_PROGRESS)); + + pDbInfo->bDbInitialized = TRUE; + if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, 0, 0, &bIgnore))) + { + goto Exit; + } + + // Initialize the information block and Progress structure. Because + // FlmDbCheck will start and stop read transactions during its + // processing we can't allow any existing read transactions to exist. + // However, it is OK for an update transaction to be in progress. An + // update transaction will NOT be stopped and restarted. The only + // reason a read transaction may be stopped and restarted is if we get + // an old view error - something that cannot normally happen during an + // update transaction. + + if (flmGetDbTransType( pDb) == FLM_READ_TRANS) + { + + // If it is an invisible transaction, it may be aborted. + + if (pDb->uiFlags & FDB_INVISIBLE_TRANS) + { + if (RC_BAD( rc = flmAbortDbTrans( pDb))) + { + goto Exit; + } + } + else + { + rc = RC_SET( FERR_TRANS_ACTIVE); + goto Exit; + } + } + + // Since we know that the check will start read transactions during + // its processing, set the flag to indicate that the KRef table should + // be cleaned up on exit if we are still in a read transaction. + + bOkToCloseTrans = TRUE; + uiBlockSize = pDb->pFile->FileHdr.uiBlockSize; + + // Check does its own reads using the handle to the file. + + pSFileHdl = pDb->pSFileHdl; + pDbInfo->pSFileHdl = pSFileHdl; + + // Allocate memory to use for reading through the data blocks. + + if (RC_BAD( rc = f_alloc( uiBlockSize, &pBlk))) + { + goto Exit; + } + +Begin_Check: + + // Initialize all statistics in the DB_INFO structure. + + rc = FERR_OK; + bStartOver = FALSE; + + GedPoolReset( pPool, pvDbInfoMark); + pDbInfo->pProgress->bPhysicalCorrupt = FALSE; + pDbInfo->pProgress->bLogicalIndexCorrupt = FALSE; + pDbInfo->pProgress->ui64DatabaseSize = 0; + pDbInfo->pProgress->uiNumFields = 0; + pDbInfo->pProgress->uiNumIndexes = 0; + pDbInfo->pProgress->uiNumContainers = 0; + pDbInfo->pProgress->uiNumLogicalFiles = 0; + pDbInfo->pLogicalFiles = NULL; + pDbInfo->pProgress->pLfStats = NULL; + pDbInfo->uiFlags = uiCheckFlags; + pDbInfo->uiMaxLockWait = 15; + pDbInfo->bStartedUpdateTrans = FALSE; + f_memset( &pDbInfo->pProgress->AvailBlocks, 0, sizeof(BLOCK_INFO)); + f_memset( &pDbInfo->pProgress->LFHBlocks, 0, sizeof(BLOCK_INFO)); + f_memset( &pDbInfo->FileHdr, 0, sizeof(FILE_HDR)); + f_memset( &Progress, 0, sizeof(DB_CHECK_PROGRESS)); + Progress.AppArg = AppArg; + + // Get the dictionary information for the file + + if (RC_BAD( rc = chkGetDictInfo( pDbInfo))) + { + goto Exit; + } + + Progress.ui64BytesExamined = 0; + + for (uiLoop = 1; + uiLoop <= MAX_DATA_BLOCK_FILE_NUMBER( pDb->pFile->FileHdr.uiVersionNum); + uiLoop++) + { + if (RC_BAD( pSFileHdl->GetFileSize( uiLoop, &uiTmpSize))) + { + break; + } + + Progress.ui64DatabaseSize += (FLMUINT64) uiTmpSize; + } + + // See if we have a valid end of file + + uiFileEnd = pDbInfo->pDb->LogHdr.uiLogicalEOF; + if (FSGetFileOffset( uiFileEnd) % uiBlockSize != 0) + { + if (RC_BAD( rc = chkReportError( pDbInfo, FLM_BAD_FILE_SIZE, LOCALE_NONE, + 0, 0, 0xFF, uiFileEnd, 0, 0, 0, 0xFFFF, 0, NULL))) + { + goto Exit; + } + } + else if (Progress.ui64DatabaseSize < FSGetSizeInBytes( pDbInfo->pDb->pFile->uiMaxFileSize, + uiFileEnd)) + { + Progress.ui64DatabaseSize = FSGetSizeInBytes( pDbInfo->pDb->pFile->uiMaxFileSize, + uiFileEnd); + } + + // Verify and count the LFH and PCODE blocks, B-Trees, and the AVAIL + // list. + + if (RC_BAD( rc = chkVerifyLFHBlocks( pDbInfo, &bStartOver))) + { + goto Exit; + } + + if (bStartOver) + { + goto Begin_Check; + } + + // Check the b-trees. + + if (RC_BAD( rc = chkVerifyBTrees( pDbInfo, pPool, &bStartOver))) + { + goto Exit; + } + + if (bStartOver) + { + goto Begin_Check; + } + + // Check the avail list. + + if (RC_BAD( rc = chkVerifyAvailList( pDbInfo, &bStartOver))) + { + goto Exit; + } + + if (bStartOver) + { + goto Begin_Check; + } + + // Signal that we are finished. + + pDbInfo->pProgress->iCheckPhase = CHECK_FINISHED; + pDbInfo->pProgress->bStartFlag = TRUE; + if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) + { + goto Exit; + } + + pDbInfo->pProgress->bStartFlag = FALSE; + +Exit: + + // Pass out any error code returned by the callback. + + if ((RC_OK( rc)) && (RC_BAD( pDbInfo->LastStatusRc))) + { + rc = pDbInfo->LastStatusRc; + } + + if (pDb && pDbInfo->bDbInitialized) + { + + // Close down the transaction, if one is going + + if (bOkToCloseTrans && flmGetDbTransType( pDb) == FLM_READ_TRANS) + { + KrefCntrlFree( pDb); + (void) flmAbortDbTrans( pDb); + } + + fdbExit( pDb); + } + + // Free memory, if allocated + + if (pBlk) + { + f_free( &pBlk); + } + + // Close the database we opened. + + if (bOpenedDb) + { + (void) FlmDbClose( &hDb); + } + + GedPoolFree( &localPool); + +ExitCS: + + return (rc); +} + +/**************************************************************************** +Desc: This routine opens a file and reads its dictionary into memory. +****************************************************************************/ +FSTATIC RCODE chkGetDictInfo( + DB_INFO * pDbInfo) +{ + RCODE rc = FERR_OK; + FDB * pDb = pDbInfo->pDb; + + // Close down the transaction, if one is going. + + if (flmGetDbTransType( pDb) != FLM_UPDATE_TRANS) + { + if (pDb->uiTransType == FLM_READ_TRANS) + { + (void) flmAbortDbTrans( pDb); + } + + // Start a read transaction on the file to ensure we are connected + // to the file's dictionary structures. + + if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_READ_TRANS, 0, + FLM_DONT_POISON_CACHE))) + { + goto Exit; + } + + f_memcpy( &pDbInfo->FileHdr, &pDb->pFile->FileHdr, sizeof(FILE_HDR)); + pDbInfo->pProgress->uiVersionNum = pDbInfo->FileHdr.uiVersionNum; + pDbInfo->pProgress->uiBlockSize = pDbInfo->FileHdr.uiBlockSize; + pDbInfo->pProgress->uiDefaultLanguage = pDbInfo->FileHdr.uiDefaultLanguage; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: This routine follows all of the blocks in a chain, verifying that + they are properly linked. It also verifies each block's header. +****************************************************************************/ +FSTATIC RCODE chkVerifyBlkChain( + DB_INFO * pDbInfo, + BLOCK_INFO * pBlkInfo, + eCorruptionLocale eLocale, + FLMUINT uiFirstBlkAddr, + FLMUINT uiBlkType, + FLMUINT * puiBlkCount, + FLMBOOL * pbStartOverRV) +{ + RCODE rc = FERR_OK; + eCorruptionType eCorruption = FLM_NO_CORRUPTION; + SCACHE * pSCache = NULL; + FLMBYTE * pBlk = NULL; + FLMUINT uiPrevBlkAddress; + FLMUINT uiBlkCount = 0; + STATE_INFO StateInfo; + FLMBOOL bStateInitialized = FALSE; + FLMUINT64 ui64SaveBytesExamined; + FDB * pDb = pDbInfo->pDb; + FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; + FLMUINT uiVersionNum = pFileHdr->uiVersionNum; + FLMUINT uiBlockSize = pFileHdr->uiBlockSize; + FLMUINT uiMaxBlocks; + + uiMaxBlocks = (FLMUINT)(FSGetSizeInBytes( pDb->pFile->uiMaxFileSize, + pDb->LogHdr.uiLogicalEOF) / (FLMUINT64) uiBlockSize); + + uiPrevBlkAddress = BT_END; + + // There must be at least ONE block if it is the LFH chain. + + if ((uiBlkType == BHT_LFH_BLK) && (uiFirstBlkAddr == BT_END)) + { + eCorruption = FLM_BAD_LFH_LIST_PTR; + (void) chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, 0, 0, 0, + 0, 0xFFFF, 0, NULL); + goto Exit; + } + + // Read through all of the blocks, verifying them as we go. + +Restart_Chain: + + uiBlkCount = 0; + flmInitReadState( &StateInfo, &bStateInitialized, uiVersionNum, pDb, NULL, + (FLMUINT) ((uiBlkType == BHT_FREE) + ? (FLMUINT) 0xFF + : (FLMUINT) 0), uiBlkType, NULL); + + ui64SaveBytesExamined = pDbInfo->pProgress->ui64BytesExamined; + StateInfo.uiBlkAddress = uiFirstBlkAddr; + + while ((StateInfo.uiBlkAddress != BT_END) && (uiBlkCount < uiMaxBlocks)) + { + StateInfo.pBlk = NULL; + if (RC_BAD( rc = chkBlkRead( pDbInfo, StateInfo.uiBlkAddress, + StateInfo.pLogicalFile ? StateInfo.pLogicalFile->pLFile : NULL, + &pBlk, &pSCache, &eCorruption))) + { + if (rc == FERR_OLD_VIEW) + { + FLMUINT uiSaveDictSeq = pDb->pDict->uiDictSeq; + + if (RC_BAD( rc = chkGetDictInfo( pDbInfo))) + { + goto Exit; + } + + // If the dictionary ID changed, start over. + + if (pDb->pDict->uiDictSeq != uiSaveDictSeq) + { + *pbStartOverRV = TRUE; + goto Exit; + } + + pDbInfo->pProgress->ui64BytesExamined = ui64SaveBytesExamined; + goto Restart_Chain; + } + + pBlkInfo->eCorruption = eCorruption; + pBlkInfo->uiNumErrors++; + rc = chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, + StateInfo.uiBlkAddress, 0, 0, 0, 0xFFFF, 0, pBlk); + } + + StateInfo.pBlk = pBlk; + uiBlkCount++; + pDbInfo->pProgress->ui64BytesExamined += (FLMUINT64) uiBlockSize; + if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) + { + goto Exit; + } + + f_yieldCPU(); + + if (( eCorruption = flmVerifyBlockHeader( &StateInfo, pBlkInfo, + uiBlockSize, 0, (uiBlkType == BHT_FREE) ? 0L : uiPrevBlkAddress, + TRUE, TRUE)) != FLM_NO_CORRUPTION) + { + pBlkInfo->eCorruption = eCorruption; + pBlkInfo->uiNumErrors++; + chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, + StateInfo.uiBlkAddress, 0, 0, 0, 0xFFFF, 0, pBlk); + goto Exit; + } + + uiPrevBlkAddress = StateInfo.uiBlkAddress; + StateInfo.uiBlkAddress = (FLMUINT) FB2UD( &pBlk[BH_NEXT_BLK]); + } + + if ((StateInfo.uiBlkAddress != BT_END) && (RC_OK( pDbInfo->LastStatusRc))) + { + switch (uiBlkType) + { + case BHT_LFH_BLK: + eCorruption = FLM_BAD_LFH_LIST_END; + break; + case BHT_PCODE_BLK: + eCorruption = FLM_BAD_PCODE_LIST_END; + break; + case BHT_FREE: + eCorruption = FLM_BAD_AVAIL_LIST_END; + break; + } + + pBlkInfo->eCorruption = eCorruption; + pBlkInfo->uiNumErrors++; + chkReportError( pDbInfo, eCorruption, eLocale, 0, 0, 0xFF, + uiPrevBlkAddress, 0, 0, 0, 0xFFFF, 0, pBlk); + goto Exit; + } + +Exit: + + if (puiBlkCount) + { + *puiBlkCount = uiBlkCount; + } + + if (bStateInitialized && StateInfo.pRecord) + { + StateInfo.pRecord->Release(); + } + + if (pSCache) + { + ScaReleaseCache( pSCache, FALSE); + } + else if (pBlk) + { + f_free( &pBlk); + } + + if (RC_OK( rc) && (eCorruption != FLM_NO_CORRUPTION)) + { + rc = (uiBlkType == BHT_FREE) + ? RC_SET( FERR_DATA_ERROR) + : RC_SET( FERR_DD_ERROR); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine verifies the LFH blocks. +****************************************************************************/ +FSTATIC RCODE chkVerifyLFHBlocks( + DB_INFO * pDbInfo, + FLMBOOL * pbStartOverRV) +{ + RCODE rc = FERR_OK; + + pDbInfo->pProgress->uiLfNumber = 0; + pDbInfo->pProgress->uiLfType = 0; + pDbInfo->pProgress->iCheckPhase = CHECK_LFH_BLOCKS; + pDbInfo->pProgress->bStartFlag = TRUE; + + if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) + { + goto Exit; + } + + pDbInfo->pProgress->bStartFlag = FALSE; + + // Go through the LFH blocks. + + if (RC_BAD( rc = chkVerifyBlkChain( pDbInfo, &pDbInfo->pProgress->LFHBlocks, + LOCALE_LFH_LIST, pDbInfo->pDb->pFile->FileHdr.uiFirstLFHBlkAddr, + BHT_LFH_BLK, NULL, pbStartOverRV)) || + *pbStartOverRV) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: This routine reads through the blocks in the AVAIL list and + verifies that we don't have a loop or some other corruption in the + list. +****************************************************************************/ +FSTATIC RCODE chkVerifyAvailList( + DB_INFO * pDbInfo, + FLMBOOL * pbStartOverRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiBlkCount; + + pDbInfo->pProgress->uiLfNumber = 0; + pDbInfo->pProgress->uiLfType = 0; + pDbInfo->pProgress->iCheckPhase = CHECK_AVAIL_BLOCKS; + pDbInfo->pProgress->bStartFlag = TRUE; + + if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) + { + goto Exit; + } + + pDbInfo->pProgress->bStartFlag = FALSE; + + f_yieldCPU(); + + if (RC_BAD( rc = chkVerifyBlkChain( pDbInfo, + &pDbInfo->pProgress->AvailBlocks, LOCALE_AVAIL_LIST, + pDbInfo->pDb->LogHdr.uiFirstAvailBlkAddr, BHT_FREE, &uiBlkCount, + pbStartOverRV)) || + *pbStartOverRV) + { + goto Exit; + } + + // See if the block count matches the block count stored in the log + // header. + + if (uiBlkCount != pDbInfo->pDb->LogHdr.uiAvailBlkCount) + { + (void) chkReportError( pDbInfo, FLM_BAD_AVAIL_BLOCK_COUNT, + LOCALE_AVAIL_LIST, 0, 0, 0xFF, 0, 0, 0, 0, 0xFFFF, + 0, NULL); + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Verifies the key and reference counts against the counts that are + stored in the tracker record. +****************************************************************************/ +FSTATIC RCODE chkVerifyTrackerCounts( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndexNum, + FLMUINT uiKeyCount, + FLMUINT uiRefCount) +{ + RCODE rc = FERR_OK; + FDB * pDb = pStateInfo->pDb; + FlmRecord * pRecord = NULL; + eCorruptionType eCorruption; + FLMUINT uiTrackerKeyCount = 0; + FLMUINT uiTrackerRefCount = 0; + void * pvField; + + // Retrieve the tracker record from record cache. + + if (RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, FLM_TRACKER_CONTAINER, + uiIndexNum, TRUE, NULL, NULL, &pRecord))) + { + if (rc != FERR_NOT_FOUND) + { + goto Exit; + } + + rc = FERR_OK; + } + else + { + if ((pvField = pRecord->find( pRecord->root(), FLM_KEY_TAG)) != NULL) + { + if (RC_BAD( rc = pRecord->getUINT( pvField, &uiTrackerKeyCount))) + { + goto Exit; + } + } + + if ((pvField = pRecord->find( pRecord->root(), FLM_REFS_TAG)) != NULL) + { + if (RC_BAD( rc = pRecord->getUINT( pvField, &uiTrackerRefCount))) + { + goto Exit; + } + } + } + + // See if the counts match what we got from the tracker record. + + if (uiKeyCount != uiTrackerKeyCount || uiRefCount != uiTrackerRefCount) + { + + // Log an error. + + eCorruption = (eCorruptionType) ((uiKeyCount != uiTrackerKeyCount) + ? FLM_KEY_COUNT_MISMATCH + : FLM_REF_COUNT_MISMATCH); + + if (RC_BAD( rc = chkReportError( pIxChkInfo->pDbInfo, eCorruption, + LOCALE_INDEX, uiIndexNum, LF_INDEX, 0xFF, 0, 0, 0, 0, 0xFFFF, + 0, NULL))) + { + goto Exit; + } + } + +Exit: + + if (pRecord) + { + pRecord->Release(); + } + + return (rc); +} + +/**************************************************************************** +Desc: Determine if an index is an index that keeps key and reference + counts. +****************************************************************************/ +FSTATIC RCODE chkIsCountIndex( + STATE_INFO * pStateInfo, + FLMUINT uiIndexNum, + FLMBOOL * pbIsCountIndex) +{ + RCODE rc = FERR_OK; + FDB * pDb = pStateInfo->pDb; + IXD * pIxd; + + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, + uiIndexNum, NULL, &pIxd, TRUE))) + { + goto Exit; + } + + *pbIsCountIndex = (FLMBOOL) ((pIxd->uiFlags & IXD_COUNT) + ? (FLMBOOL) TRUE + : (FLMBOOL) FALSE); + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Verifies the current index key against the result set. +****************************************************************************/ +RCODE chkVerifyIXRSet( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIxRefDrn) +{ + RCODE rc = FERR_OK; + FLMINT iCmpVal = 0; + FLMUINT uiIteration = 0; + FLMBOOL bRSetEmpty = FALSE; + RS_IX_KEY * pCurrRSKey; + RS_IX_KEY * pPrevRSKey; + + if (!pIxChkInfo->pCurrRSKey) + { + pIxChkInfo->pCurrRSKey = &pIxChkInfo->IxKey1; + pIxChkInfo->pPrevRSKey = &pIxChkInfo->IxKey2; + } + + // Compare index and result set keys + + while (!bRSetEmpty) + { + if (pIxChkInfo->bGetNextRSKey) + { + + // Get the next key from the result set. If the result set is + // empty, then pIxChkInfo->uiRSKeyLen will be set to zero, + // forcing the problem to be resolved below. + + if (RC_BAD( rc = chkGetNextRSKey( pIxChkInfo))) + { + if (rc == FERR_EOF_HIT || rc == FERR_NOT_FOUND) + { + + // Set bRSetEmpty to TRUE so that the loop will exit after + // the current key is resolved. Otherwise, conflict + // resolution on the current key will be repeated forever + // (infinite loop). + + bRSetEmpty = TRUE; + rc = FERR_OK; + } + else + { + goto Exit; + } + } + else + { + + // Updated statistics + + pIxChkInfo->pDbInfo->pProgress->ui64NumKeysExamined++; + } + } + + pCurrRSKey = pIxChkInfo->pCurrRSKey; + pPrevRSKey = pIxChkInfo->pPrevRSKey; + + if (pCurrRSKey->uiRSKeyLen == 0 || bRSetEmpty) + { + + // We don't have a key because we got an EOF when reading the + // result set. Need to resolve the fact that the result set does + // not have a key that is found in the index. Set iCmpVal to 1 to + // force this resolution. + + iCmpVal = 1; + } + else + { + + // Compare the index key and result set key. + + iCmpVal = chkCompareKeySet( pCurrRSKey->uiRSIxNum, + &(pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET]), + pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD, + pCurrRSKey->uiRSRefDrn, + pStateInfo->pLogicalFile->pLFile->uiLfNum, + pStateInfo->pCurKey, + pStateInfo->uiCurKeyLen, uiIxRefDrn); + } + + if (iCmpVal < 0) + { + + // If a comparison is done where the keys from the result set + // don't match what we got from the index, we will forego + // verifying the tracker counts. Verifying of tracker counts can + // only occur if we have an otherwise clean check of the index + // keys. + + pIxChkInfo->bCheckCounts = FALSE; + + // The result set key is less than the index key. This could mean + // that the result set key needs to be added to the index. + + if ((RC_BAD( rc = chkResolveIXMissingKey( pStateInfo, pIxChkInfo))) || + (pIxChkInfo->pDbInfo->bReposition)) + { + + // If the key was added to the index (bReposition == TRUE) or + // we got some other error, we don't want to get the next + // result set key. + + pIxChkInfo->bGetNextRSKey = FALSE; + goto Exit; + } + else + { + + // False alarm. The index is missing the key because of a + // concurrent update. We want to get the next RS key. + + pIxChkInfo->bGetNextRSKey = TRUE; + } + } + else if (iCmpVal > 0) + { + + // If a comparison is done where the keys from the result set + // don't match what we got from the index, we will forego + // verifying the tracker counts. Verifying of tracker counts can + // only occur if we have an otherwise clean check of the index + // keys. + + pIxChkInfo->bCheckCounts = FALSE; + + // The result set key is greater than the index key. This could + // mean that the index key needs to be deleted from the index. + // Whether we delete the index key or not, we don't need to get + // the next result set key, but we do want to reposition and get + // the next index key. + + pIxChkInfo->bGetNextRSKey = FALSE; + if ((RC_BAD( rc = chkResolveRSetMissingKey( pStateInfo, + pIxChkInfo, uiIxRefDrn))) || pIxChkInfo->pDbInfo->bReposition) + { + goto Exit; + } + break; + } + else + { + + // The index and result set keys are equal. We want to get the + // next result set and index keys. + + pIxChkInfo->bGetNextRSKey = TRUE; + + // Determine if we have switched indexes. If so, verify the key + // and reference counts against the counts in the tracker record. + + if (pCurrRSKey->uiRSIxNum != pPrevRSKey->uiRSIxNum) + { + if (pIxChkInfo->bCheckCounts) + { + + // Verify the key and reference counts against tracker + // record. + + if (RC_BAD( rc = chkVerifyTrackerCounts( pStateInfo, pIxChkInfo, + pPrevRSKey->uiRSIxNum, pIxChkInfo->uiRSIxKeyCount, + pIxChkInfo->uiRSIxRefCount))) + { + goto Exit; + } + } + + // Determine if the new index is one that supports counts. + + if (RC_BAD( rc = chkIsCountIndex( pStateInfo, pCurrRSKey->uiRSIxNum, + &pIxChkInfo->bCheckCounts))) + { + goto Exit; + } + + if (pIxChkInfo->bCheckCounts) + { + + // Set the counts to one. + + pIxChkInfo->uiRSIxKeyCount = 1; + pIxChkInfo->uiRSIxRefCount = 1; + } + } + else + { + if (pIxChkInfo->bCheckCounts) + { + + // Always increment the reference count. + + pIxChkInfo->uiRSIxRefCount++; + + // See if the key changed. + + if (pCurrRSKey->uiRSKeyLen != pPrevRSKey->uiRSKeyLen || + (pCurrRSKey->uiRSKeyLen > RS_KEY_OFFSET && + f_memcmp( &pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET], + &pPrevRSKey->pucRSKeyBuf[RS_KEY_OFFSET], + pCurrRSKey->uiRSKeyLen - RS_KEY_OFFSET) != 0)) + { + pIxChkInfo->uiRSIxKeyCount++; + } + else + { + + // If the keys are the same, at least the DRNs better + // be different. + + flmAssert( pCurrRSKey->uiRSRefDrn != pPrevRSKey->uiRSRefDrn); + } + } + } + break; + } + + // Call the yield function periodically + + uiIteration++; + if (!(uiIteration & 0x1F)) + { + f_yieldCPU(); + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Retrieves the next key from the sorted result set +****************************************************************************/ +RCODE chkGetNextRSKey( + IX_CHK_INFO * pIxChkInfo) +{ + RCODE rc = FERR_OK; + RS_IX_KEY * pCurrRSKey; + + // Swap current and last key pointers - this allows us to always keep + // the last key without having to memcpy the keys. + + pCurrRSKey = pIxChkInfo->pCurrRSKey; + pIxChkInfo->pCurrRSKey = pIxChkInfo->pPrevRSKey; + pIxChkInfo->pPrevRSKey = pCurrRSKey; + pCurrRSKey = pIxChkInfo->pCurrRSKey; + + // Get the next key + + if (RC_BAD( rc = chkRSGetNext( pIxChkInfo->pRSet, pCurrRSKey->pucRSKeyBuf, + MAX_KEY_SIZ + RS_KEY_OVERHEAD, &(pCurrRSKey->uiRSKeyLen)))) + { + goto Exit; + } + + // Verify that the key meets the minimum length requirements + + flmAssert( pCurrRSKey->uiRSKeyLen >= RS_KEY_OVERHEAD); + + // Extract the index number and reference DRN + + pCurrRSKey->uiRSIxNum = + (FLMUINT) FB2UW( &(pCurrRSKey->pucRSKeyBuf[RS_IX_OFFSET])); + + pCurrRSKey->uiRSRefDrn = + (FLMUINT) FB2UD( &(pCurrRSKey->pucRSKeyBuf[RS_REF_OFFSET])); + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Resolves the case of a key found in the result set but not in the + current index. +****************************************************************************/ +RCODE chkResolveIXMissingKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo) +{ + RCODE rc = FERR_OK; + FLMBOOL bKeyInRec; + FLMBOOL bKeyInIndex; + FLMBOOL bFixCorruption = FALSE; + RS_IX_KEY * pCurrRSKey = pIxChkInfo->pCurrRSKey; + + // Determine if the record generates the key and if the key is found in + // the index. + + if (RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, + pCurrRSKey->uiRSIxNum, &(pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET]), + (FLMUINT) (pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), + pCurrRSKey->uiRSRefDrn, NULL, &bKeyInRec, &bKeyInIndex))) + { + if (rc == FERR_INDEX_OFFLINE) + { + rc = FERR_OK; + } + + goto Exit; + } + + // If the record does not generate the key or the key+ref is in the + // index, the index is not corrupt. + + if (!bKeyInRec || bKeyInIndex) + { + pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; + goto Exit; + } + + // Otherwise, the index is corrupt; Update statistics + + pIxChkInfo->pDbInfo->pProgress->ui64NumRecKeysNotFound++; + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; + + // Report the error + + if (RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, + FLM_DRN_NOT_IN_KEY_REFSET, pCurrRSKey->uiRSIxNum, + pCurrRSKey->uiRSRefDrn, &(pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET]), + (FLMUINT) (pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), + &bFixCorruption))) + { + goto Exit; + } + + // Exit if the application does not want to repair the corruption. + + if (!bFixCorruption) + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + goto Exit; + } + + // Fix the corruption; Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; + + // Add the key + + if (RC_OK( rc = chkAddDelKeyRef( pStateInfo, pIxChkInfo, + pCurrRSKey->uiRSIxNum, &(pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET]), + (FLMUINT) (pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), + pCurrRSKey->uiRSRefDrn, 0))) + { + pIxChkInfo->pDbInfo->bReposition = TRUE; + goto Exit; + } + else + { + if (rc == FERR_NOT_UNIQUE) + { + + // A subsequent record probably also generates this key, but the + // index is a unique index so we were not allowed to add the + // missing key + ref to the index. This record should probably be + // deleted. + + if (RC_OK( rc = chkResolveNonUniqueKey( pStateInfo, pIxChkInfo, + pCurrRSKey->uiRSIxNum, + &(pCurrRSKey->pucRSKeyBuf[RS_KEY_OFFSET]), + (FLMUINT) (pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), + pCurrRSKey->uiRSRefDrn))) + { + pIxChkInfo->pDbInfo->bReposition = TRUE; + goto Exit; + } + } + else + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Resolves the case of a key found in the current index but not in + the result set. +****************************************************************************/ +FSTATIC RCODE chkResolveRSetMissingKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIxRefDrn) +{ + RCODE rc = FERR_OK; + FLMBOOL bKeyInRec; + FLMBOOL bKeyInIndex; + FLMBOOL bFixCorruption = FALSE; + + // See if the key is found in the index and/or generated by the record. + + if (RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, + pStateInfo->pLogicalFile->pLFile->uiLfNum, pStateInfo->pCurKey, + pStateInfo->uiCurKeyLen, uiIxRefDrn, NULL, &bKeyInRec, + &bKeyInIndex))) + { + if (rc == FERR_INDEX_OFFLINE) + { + rc = FERR_OK; + } + + goto Exit; + } + + // If the key is generated by the record or the key is not found in the + // index, the index is not corrupt. + + if (bKeyInRec || !bKeyInIndex) + { + pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; + goto Exit; + } + + // Otherwise, the index is corrupt; Update statistics + + pIxChkInfo->pDbInfo->pProgress->ui64NumKeysNotFound++; + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; + + // Report the error + + if (RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, + FLM_IX_KEY_NOT_FOUND_IN_REC, + pStateInfo->pLogicalFile->pLFile->uiLfNum, uiIxRefDrn, + pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, &bFixCorruption))) + { + goto Exit; + } + + // Exit if the application does not want to repair the corruption. + + if (!bFixCorruption) + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + goto Exit; + } + + // Fix the corruption; Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; + + // Delete the reference from the index + + if (RC_OK( rc = chkAddDelKeyRef( pStateInfo, pIxChkInfo, + pStateInfo->pLogicalFile->pLFile->uiLfNum, pStateInfo->pCurKey, + pStateInfo->uiCurKeyLen, uiIxRefDrn, KREF_DELETE_FLAG))) + { + pIxChkInfo->pDbInfo->bReposition = TRUE; + } + else + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Resolves the case of multiple references associated with a key in a + unique index. +****************************************************************************/ +RCODE chkResolveNonUniqueKey( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn) +{ + RCODE rc = FERR_OK; + FDB * pDb = pStateInfo->pDb; + LFILE * pRecLFile = NULL; + FLMBOOL bDeleteRec = FALSE; + FLMUINT uiRecContainer; + RCODE rc2 = FERR_OK; + FLMBOOL bFixCorruption = FALSE; + FlmRecord * pOldRecord = NULL; + + // Verify that the record violates the constraints of the unique index + // and should be deleted. + + if (RC_BAD( rc = chkVerifyDelNonUniqueRec( pStateInfo, pIxChkInfo, uiIndex, + pucKey, uiKeyLen, uiDrn, &uiRecContainer, &bDeleteRec))) + { + goto Exit; + } + + if (bDeleteRec) + { + + // Update statistics + + pIxChkInfo->pDbInfo->pProgress->ui64NumNonUniqueKeys++; + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; + + // Report the error + + if (RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, + FLM_NON_UNIQUE_ELM_KEY_REF, uiIndex, uiDrn, pucKey, uiKeyLen, + &bFixCorruption))) + { + goto Exit; + } + + if (!bFixCorruption) + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + goto Exit; + } + + // Delete the record that generated the non-unique reference. ; + // Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; + + // Start an update transaction, if necessary. + + if (RC_BAD( rc = chkStartUpdate( pStateInfo, pIxChkInfo))) + { + goto Exit; + } + + // Re-verify that the record should be deleted. + + if (RC_BAD( rc = chkVerifyDelNonUniqueRec( pStateInfo, pIxChkInfo, + uiIndex, pucKey, uiKeyLen, uiDrn, &uiRecContainer, + &bDeleteRec))) + { + goto Exit; + } + + if (bDeleteRec == TRUE) + { + void * pvMark; + + // Mark the temporary pool. + + pvMark = GedPoolMark( &(pDb->TempPool)); + + // Call the internal delete function, passing boolean flags + // indicating that missing keys should not prevent the record + // deletion and that the record validator callback should not be + // called. + + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, uiRecContainer, + &pRecLFile))) + { + goto Exit; + } + + rc = flmDeleteRecord( pDb, pRecLFile, uiDrn, &pOldRecord, TRUE); + + if (gv_FlmSysData.UpdateEvents.pEventCBList) + { + flmUpdEventCallback( pDb, F_EVENT_DELETE_RECORD, (HFDB) pDb, rc, + uiDrn, uiRecContainer, NULL, pOldRecord); + } + + // Reset the temporary pool. The flmDeleteRecord call + // allocates space for the record that is being deleted. + + GedPoolReset( &(pDb->TempPool), pvMark); + + if (RC_BAD( rc)) + { + + // If the record had already been deleted, continue the check + // without reporting the error. + + if (rc == FERR_NOT_FOUND) + { + rc = FERR_OK; + + // Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; + } + else + { + + // Set the logical corruption flag + + pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; + } + + goto Exit; + } + + // Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; + } + } + else + { + + // Increment the conflict counter + + pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; + } + +Exit: + + // End the update. chkEndUpdate will be a no-op if an update + // transaction was not started. + + rc2 = chkEndUpdate( pStateInfo, pIxChkInfo); + + if (pOldRecord) + { + pOldRecord->Release(); + } + + return ((RCODE) ((rc != FERR_OK) ? (RCODE) rc : (RCODE) rc2)); +} + +/**************************************************************************** +Desc: Verifies that the specified record should be deleted because it + generates key(s) which violate the constraints of a unique index. +****************************************************************************/ +FSTATIC RCODE chkVerifyDelNonUniqueRec( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiRecDrn, + FLMUINT * puiRecContainerRV, + FLMBOOL * pbDelRecRV) +{ + RCODE rc = FERR_OK; + FLMBOOL bKeyInRec; + FLMBOOL bRecRefdByKey; + FLMUINT uiRefCount; + FLMUINT uiRecContainer; + + *pbDelRecRV = FALSE; + *puiRecContainerRV = 0; + + // See if the key is found in the index and/or generated by the record. + + if (RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, uiIndex, pucKey, + uiKeyLen, uiRecDrn, &uiRecContainer, &bKeyInRec, &bRecRefdByKey))) + { + if (rc == FERR_INDEX_OFFLINE) + { + rc = FERR_OK; + } + + goto Exit; + } + + *puiRecContainerRV = uiRecContainer; + + if (bKeyInRec == TRUE) + { + + // Verify that the key is not unique + + if (RC_BAD( rc = chkVerifyKeyNotUnique( pStateInfo, uiIndex, pucKey, + uiKeyLen, &uiRefCount))) + { + goto Exit; + } + + if (uiRefCount > 1) + { + + // The unique index has multiple references for the specified + // key. Since the current record generates a non-unique key, it + // should be deleted even if it is not one of the records + // referenced by the key. Of course, if it is already referenced + // by the key, deleting the record will reduce the number of + // references associated with the key by one. + + *pbDelRecRV = TRUE; + } + else if (uiRefCount == 1 && bRecRefdByKey == FALSE) + { + + // The unique index already has a key corresponding to the key + // being generated by the current record. However, the record is + // not referenced from the unique index. The record should still + // be deleted since it generates a non-unique key. + + *pbDelRecRV = TRUE; + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Determines if a key is generated by the current record and/or if + the key is found in the current index +****************************************************************************/ +FSTATIC RCODE chkGetKeySource( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn, + FLMUINT * puiRecordContainerRV, + FLMBOOL * pbKeyInRecRV, + FLMBOOL * pbKeyInIndexRV) +{ + RCODE rc = FERR_OK; + FlmRecord * pRecord = NULL; + FDB * pDb = pStateInfo->pDb; + LFILE * pLFile; + LFILE * pIxLFile; + REC_KEY * pKeys = NULL; + REC_KEY * pTempKey = NULL; + IXD * pIxd; + FLMBYTE ucRecKeyBuf[MAX_KEY_SIZ]; + FLMUINT uiRecKeyLen; + FLMUINT uiKeyCount; + FLMBOOL bResetKRef = FALSE; + void * pIxPoolMark; + void * pDbPoolMark; + FLMUINT uiContainerNum; + + // Initialize return values. + + *pbKeyInRecRV = FALSE; + *pbKeyInIndexRV = FALSE; + + if (puiRecordContainerRV) + { + *puiRecordContainerRV = 0; + } + + // Initialize variables + + pIxPoolMark = GedPoolMark( &(pIxChkInfo->pool)); + + // Need to mark the DB's temporary pool. The index code allocates + // memory for new CDL entries from the DB pool. If the pool is not + // reset, it grows during the check and becomes VERY large. + + pDbPoolMark = GedPoolMark( &(pDb->TempPool)); + + // Set up the KRef so that flmGetRecKeys will work + + if (RC_BAD( rc = KrefCntrlCheck( pDb))) + { + goto Exit; + } + + bResetKRef = TRUE; + + // Get the LFile and IXD of the index + + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, + uiIndex, &pIxLFile, &pIxd))) + { + + // Return FERR_INDEX_OFFLINE error. + + goto Exit; + } + + if ((uiContainerNum = pIxd->uiContainerNum) == 0) + { + + // Container number is always the last two bytes of the key. + + flmAssert( uiKeyLen > getIxContainerPartLen( pIxd)); + uiContainerNum = getContainerFromKey( pucKey, uiKeyLen); + } + + // Get the LFile of the record that caused the error + + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainerNum, &pLFile))) + { + goto Exit; + } + + // Set the record container return value + + if (puiRecordContainerRV) + { + *puiRecordContainerRV = uiContainerNum; + } + + // See if the key is in the index. + + if (RC_BAD( rc = chkVerifyKeyExists( pDb, pIxLFile, pucKey, uiKeyLen, uiDrn, + pbKeyInIndexRV))) + { + goto Exit; + } + + // Read the record + + if (RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, pLFile->uiLfNum, uiDrn, FALSE, + NULL, NULL, &pRecord))) + { + if (rc != FERR_NOT_FOUND) + { + goto Exit; + } + + // NOTE: Deliberately not bringing in to cache if not found there. + + if (RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, &pRecord, NULL, NULL))) + { + if (rc == FERR_NOT_FOUND) + { + *pbKeyInRecRV = FALSE; + rc = FERR_OK; + } + else + { + goto Exit; + } + } + } + + if (pRecord) + { + + // Generate record keys + + if (RC_BAD( rc = flmGetRecKeys( pDb, pIxd, pRecord, + pRecord->getContainerID(), TRUE, &(pIxChkInfo->pool), &pKeys))) + { + goto Exit; + } + + uiKeyCount = 0; + pTempKey = pKeys; + while (pTempKey != NULL) + { + + // Build the collated keys for each key tree. + + if (RC_BAD( rc = KYTreeToKey( pDb, pIxd, pTempKey->pKey, + pTempKey->pKey->getContainerID(), ucRecKeyBuf, &uiRecKeyLen, + 0))) + { + goto Exit; + } + + if (KYKeyCompare( pucKey, uiKeyLen, ucRecKeyBuf, + uiRecKeyLen) == BT_EQ_KEY) + { + *pbKeyInRecRV = TRUE; + break; + } + + pTempKey = pTempKey->pNextKey; + uiKeyCount++; + + // Release the CPU periodically to prevent CPU hog problems. + + f_yieldCPU(); + } + } + +Exit: + + if (pKeys) + { + pTempKey = pKeys; + while (pTempKey) + { + pTempKey->pKey->Release(); + pTempKey = pTempKey->pNextKey; + } + } + + if (pRecord) + { + pRecord->Release(); + } + + // Remove any keys added to the KRef + + if (bResetKRef) + { + KYAbortCurrentRecord( pDb); + } + + // Reset the DB's temporary pool + + GedPoolReset( &(pDb->TempPool), pDbPoolMark); + + // Reset the index check pool + + GedPoolReset( &(pIxChkInfo->pool), pIxPoolMark); + + return (rc); +} + +/**************************************************************************** +Desc: Verify that a key is (or is not) found in an index. +****************************************************************************/ +FSTATIC RCODE chkVerifyKeyExists( + FDB * pDb, + LFILE * pLFile, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiRefDrn, + FLMBOOL * pbFoundRV) +{ + RCODE rc = FERR_OK; + BTSK stackBuf[BH_MAX_LEVELS]; + BTSK * stack = stackBuf; + FLMUINT uiDinDomain = DIN_DOMAIN( uiRefDrn) + 1; + FLMBYTE ucBtKeyBuf[MAX_KEY_SIZ]; + DIN_STATE dinState; + FLMUINT uiTmpDrn; + + *pbFoundRV = FALSE; + f_memset( &dinState, 0, sizeof(DIN_STATE)); + + // Initialize stack cache. + + FSInitStackCache( &(stackBuf[0]), BH_MAX_LEVELS); + stack = stackBuf; + stack->pKeyBuf = ucBtKeyBuf; + + // Search for the key. + + if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &stack, pucKey, uiKeyLen, + uiDinDomain))) + { + goto Exit; + } + + if (stack->uiCmpStatus == BT_EQ_KEY) + { + uiTmpDrn = uiRefDrn; + + // Reading the current element, position to or after uiTmpDrn + + rc = FSRefSearch( stack, &dinState, &uiTmpDrn); + + // If the entry was not found, returns FERR_FAILURE + + if (rc == FERR_OK) + { + *pbFoundRV = TRUE; + } + else if (rc != FERR_FAILURE) + { + goto Exit; + } + else + { + rc = FERR_OK; + } + } + +Exit: + + // Free the stack cache + + FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); + return (rc); +} + +/**************************************************************************** +Desc: Compares a composite key (index, ref, key) for equality. +Note: Since index references are sorted in decending order, a composite key + with a lower ref DRN will sort after a key with a higher ref DRN. +****************************************************************************/ +FLMINT chkCompareKeySet( + FLMUINT uiIxNum1, + FLMBYTE * pData1, + FLMUINT uiLength1, + FLMUINT uiDrn1, + FLMUINT uiIxNum2, + FLMBYTE * pData2, + FLMUINT uiLength2, + FLMUINT uiDrn2) +{ + FLMINT iCmpVal = RS_EQUALS; + FLMUINT uiMinLen; + + // Compare index numbers + + if (uiIxNum1 > uiIxNum2) + { + iCmpVal = RS_GREATER_THAN; + goto Exit; + } + else if (uiIxNum1 < uiIxNum2) + { + iCmpVal = RS_LESS_THAN; + goto Exit; + } + + // Compare keys + + uiMinLen = (FLMUINT) (uiLength1 < uiLength2) ? uiLength1 : uiLength2; + iCmpVal = f_memcmp( pData1, pData2, uiMinLen); + if (iCmpVal == 0) + { + + // Compare references + + if (uiLength1 == uiLength2) + { + + // A key with a lower ref DRN will sort after a key with a higher + // ref DRN. + + if (uiDrn1 > uiDrn2) + { + iCmpVal = RS_LESS_THAN; + } + else if (uiDrn1 < uiDrn2) + { + iCmpVal = RS_GREATER_THAN; + } + else + { + iCmpVal = RS_EQUALS; + goto Exit; + } + } + else if (uiLength1 > uiLength2) + { + iCmpVal = RS_GREATER_THAN; + } + else + { + iCmpVal = RS_LESS_THAN; + } + } + else + { + iCmpVal = (FLMINT) ((iCmpVal > 0) + ? (FLMINT) RS_GREATER_THAN + : (FLMINT) RS_LESS_THAN); + } + +Exit: + + return (iCmpVal); +} + +/**************************************************************************** +Desc: This routine adds or deletes an index key and/or reference. +****************************************************************************/ +FSTATIC RCODE chkAddDelKeyRef( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + FLMUINT uiIndexNum, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT uiDrn, + FLMUINT uiFlags) +{ + RCODE rc = FERR_OK; + RCODE rc2 = FERR_OK; + FLMBYTE ucKeyBuf[sizeof(KREF_ENTRY) + MAX_KEY_SIZ]; + KREF_ENTRY * pKrefEntry = (KREF_ENTRY *) (&ucKeyBuf[0]); + IXD * pIxd; + LFILE * pLFile; + FLMBOOL bStartedUpdate = FALSE; + FLMBOOL bKeyInRec; + FLMBOOL bKeyInIndex; + + // Start an update transaction, if necessary + + if (RC_BAD( rc = chkStartUpdate( pStateInfo, pIxChkInfo))) + { + goto Exit; + } + + bStartedUpdate = TRUE; + + // Look up the LFILE and IXD for the index. + + if (RC_BAD( rc = fdictGetIndex( pStateInfo->pDb->pDict, + pStateInfo->pDb->pFile->bInLimitedMode, uiIndexNum, &pLFile, &pIxd))) + { + + // Shouldn't get FERR_INDEX_OFFLINE in here. + + goto Exit; + } + + // Verify that the state has not changed + + if (RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, uiIndexNum, pucKey, + uiKeyLen, uiDrn, NULL, &bKeyInRec, &bKeyInIndex))) + { + goto Exit; + } + + if ((bKeyInIndex == TRUE && ((uiFlags & KREF_DELETE_FLAG) != 0)) || + (bKeyInIndex == FALSE && uiFlags == 0)) + { + + // Setup the KrefEntry structure + + flmAssert( uiIndexNum > 0 && uiIndexNum < FLM_UNREGISTERED_TAGS); + f_memcpy( &(ucKeyBuf[sizeof(KREF_ENTRY)]), pucKey, uiKeyLen); + pKrefEntry->ui16KeyLen = (FLMUINT16) uiKeyLen; + pKrefEntry->ui16IxNum = (FLMUINT16) uiIndexNum; + pKrefEntry->uiDrn = uiDrn; + pKrefEntry->uiTrnsSeq = 1; + pKrefEntry->uiFlags = uiFlags; + + if ((pIxd->uiFlags & IXD_UNIQUE) != 0) + { + + // Do not allow duplicate keys to be added to a unique index. + + pKrefEntry->uiFlags |= KREF_UNIQUE_KEY; + } + + // Add or delete the key/reference. + + if (RC_BAD( rc = FSRefUpdate( pStateInfo->pDb, pLFile, pKrefEntry))) + { + goto Exit; + } + + // Update statistics + + pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; + } + +Exit: + + // End the update. + + if (bStartedUpdate == TRUE) + { + if (RC_BAD( rc2 = chkEndUpdate( pStateInfo, pIxChkInfo))) + { + goto Exit; + } + } + + rc = (RCODE) ((rc != FERR_OK) ? (RCODE) rc : (RCODE) rc2); + + return (rc); +} + +/**************************************************************************** +Desc: Populates the CORRUPT_INFO structure and calls the user's callback + routine. +****************************************************************************/ +FSTATIC RCODE chkReportIxError( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + eCorruptionType eCorruption, + FLMUINT uiErrIx, + FLMUINT uiErrDrn, + FLMBYTE * pucErrKey, + FLMUINT uiErrKeyLen, + FLMBOOL * pbFixErrRV) +{ + RCODE rc = FERR_OK; + FDB * pDb = pStateInfo->pDb; + POOL * pTmpPool; + IXD * pIxd; + LFILE * pLFile; + void * pIxPoolMark; + void * pDbPoolMark = NULL; + FLMBOOL bResetKRef = FALSE; + CORRUPT_INFO CorruptInfo; + FLMUINT uiContainerNum; + + f_memset( &CorruptInfo, 0, sizeof(CORRUPT_INFO)); + + // Mark the index check pool + + pIxPoolMark = GedPoolMark( &(pIxChkInfo->pool)); + pTmpPool = &(pIxChkInfo->pool); + + // Need to mark the DB's temporary pool. The index code allocates + // memory for new CDL entries from the DB pool. If the pool is not + // reset, it grows during the check and becomes VERY large. + + pDbPoolMark = GedPoolMark( &(pDb->TempPool)); + + // Set up the KRef so that flmGetRecKeys will work + + if (RC_BAD( rc = KrefCntrlCheck( pDb))) + { + goto Exit; + } + + bResetKRef = TRUE; + + // Report the error + + CorruptInfo.eErrLocale = LOCALE_INDEX; + CorruptInfo.eCorruption = eCorruption; + CorruptInfo.uiErrLfNumber = uiErrIx; + CorruptInfo.uiErrDrn = uiErrDrn; + CorruptInfo.uiErrElmOffset = pStateInfo->uiElmOffset; + + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, + uiErrIx, NULL, &pIxd, TRUE))) + { + goto Exit; + } + + // Generate the key tree using the key that caused the error + + if (RC_BAD( rc = chkKeyToTree( pIxd, pucErrKey, uiErrKeyLen, + &(CorruptInfo.pErrIxKey)))) + { + goto Exit; + } + + // Get the LFile + + if ((uiContainerNum = pIxd->uiContainerNum) == 0) + { + + // Container number is always the last two bytes of the key. + + flmAssert( uiErrKeyLen > getIxContainerPartLen( pIxd)); + uiContainerNum = getContainerFromKey( pucErrKey, uiErrKeyLen); + } + + // Get the LFile + + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainerNum, &pLFile))) + { + goto Exit; + } + + // Read the record + + if (RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, pLFile->uiLfNum, uiErrDrn, + FALSE, NULL, NULL, &(CorruptInfo.pErrRecord)))) + { + if (rc != FERR_NOT_FOUND) + { + goto Check_Error; + } + + // NOTE: Deliberately not bringing in to cache if not found there. + + if (RC_BAD( rc = FSReadRecord( pDb, pLFile, uiErrDrn, + &(CorruptInfo.pErrRecord), NULL, NULL))) + { +Check_Error: + + // Record may have been deleted or cannot be returned because of + // an old view error. + + if (rc == FERR_NOT_FOUND) + { + rc = FERR_OK; + } + else if (FlmErrorIsFileCorrupt( rc)) + { + pIxChkInfo->pDbInfo->pProgress->bPhysicalCorrupt = TRUE; + rc = FERR_OK; + goto Exit; + } + else + { + goto Exit; + } + } + } + + // Generate index keys for the current index and record + + if (CorruptInfo.pErrRecord != NULL) + { + if (RC_BAD( rc = flmGetRecKeys( pDb, pIxd, CorruptInfo.pErrRecord, + CorruptInfo.pErrRecord->getContainerID(), TRUE, pTmpPool, + &(CorruptInfo.pErrRecordKeyList)))) + { + goto Exit; + } + } + + *pbFixErrRV = FALSE; + if ((pIxChkInfo->pDbInfo->fnStatusFunc) && + (RC_OK( pIxChkInfo->pDbInfo->LastStatusRc))) + { + pIxChkInfo->pDbInfo->LastStatusRc = + (*pIxChkInfo->pDbInfo->fnStatusFunc) ( FLM_PROBLEM_STATUS, + (void *) &CorruptInfo, (void *) pbFixErrRV, + pIxChkInfo->pDbInfo->pProgress->AppArg); + } + +Exit: + + if (CorruptInfo.pErrRecord) + { + CorruptInfo.pErrRecord->Release(); + } + + if (CorruptInfo.pErrIxKey) + { + CorruptInfo.pErrIxKey->Release(); + } + + if (CorruptInfo.pErrRecordKeyList) + { + REC_KEY * pTempKey = CorruptInfo.pErrRecordKeyList; + + while (pTempKey) + { + pTempKey->pKey->Release(); + pTempKey = pTempKey->pNextKey; + } + } + + // Remove any keys added to the KRef + + if (bResetKRef) + { + KYAbortCurrentRecord( pDb); + } + + // Reset the DB's temporary pool + + GedPoolReset( &(pDb->TempPool), pDbPoolMark); + + // Reset the index check pool + + GedPoolReset( &(pIxChkInfo->pool), pIxPoolMark); + return (rc); +} + +/**************************************************************************** +Desc: This routine verifies that a key is not unique +****************************************************************************/ +FSTATIC RCODE chkVerifyKeyNotUnique( + STATE_INFO * pStateInfo, + FLMUINT uiIndex, + FLMBYTE * pucKey, + FLMUINT uiKeyLen, + FLMUINT * puiRefCountRV) +{ + RCODE rc = FERR_OK; + FDB * pDb = pStateInfo->pDb; + FlmRecord * pKeyTree = NULL; + IXD * pIxd; + FLMUINT uiRefDrn; + + *puiRefCountRV = 0; + + // Get the IXD + + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, + uiIndex, NULL, &pIxd))) + { + goto Exit; + } + + // This routine should not be called unless the index is a unique + // index. + + flmAssert( ((pIxd->uiFlags & IXD_UNIQUE) != 0)); + + // Generate the key tree from the collation key. + + if (RC_BAD( rc = chkKeyToTree( pIxd, pucKey, uiKeyLen, &pKeyTree))) + { + goto Exit; + } + + // Count up to the first two references for the key. + + if (RC_BAD( rc = FlmKeyRetrieve( (HFDB) pDb, uiIndex, + pKeyTree->getContainerID(), pKeyTree, 0, FO_EXACT, NULL, &uiRefDrn + ))) + { + + // If the key is NOT found, the problem no longer exists. + + if ((rc == FERR_NOT_FOUND) || + (rc == FERR_BOF_HIT) || + (rc == FERR_EOF_HIT)) + { + rc = FERR_OK; + } + + goto Exit; + } + + // Found at least one reference. + + *puiRefCountRV = 1; + + // Go exclusive of the last key/reference found to see if there are + // more references for the key. + + if (RC_BAD( rc = FlmKeyRetrieve( (HFDB) pDb, uiIndex, + pKeyTree->getContainerID(), pKeyTree, uiRefDrn, + FO_KEY_EXACT | FO_EXCL, NULL, &uiRefDrn))) + { + if ((rc == FERR_NOT_FOUND) || + (rc == FERR_BOF_HIT) || + (rc == FERR_EOF_HIT)) + { + rc = FERR_OK; + } + + goto Exit; + } + + // May be more references, but it is sufficient to know that there are + // at least two. + + *puiRefCountRV = 2; + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE chkStartUpdate( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo) +{ + RCODE rc = FERR_OK; + RCODE rc2 = FERR_OK; + FDB * pDb = pStateInfo->pDb; + FLMBOOL bAbortedReadTrans = FALSE; + + if (flmGetDbTransType( pDb) == FLM_READ_TRANS) + { + + // Free the KrefCntrl + + KrefCntrlFree( pDb); + + // Abort the read transaction + + if (RC_BAD( rc = flmAbortDbTrans( pDb))) + { + goto Exit; + } + + bAbortedReadTrans = TRUE; + + // Try to start an update transaction + + if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, + pIxChkInfo->pDbInfo->uiMaxLockWait, FLM_DONT_POISON_CACHE))) + { + goto Exit; + } + + pIxChkInfo->pDbInfo->bStartedUpdateTrans = TRUE; + } + + if (RC_BAD( pIxChkInfo->pDbInfo->LastStatusRc)) + { + rc = pIxChkInfo->pDbInfo->LastStatusRc; + goto Exit; + } + +Exit: + + // If something went wrong after the update transaction was started, + // abort the transaction. + + if (RC_BAD( rc)) + { + if (pIxChkInfo->pDbInfo->bStartedUpdateTrans == TRUE) + { + (void) flmAbortDbTrans( pDb); + pIxChkInfo->pDbInfo->bStartedUpdateTrans = FALSE; + } + } + + // Re-start the read transaction. + + if (bAbortedReadTrans == TRUE && + pIxChkInfo->pDbInfo->bStartedUpdateTrans == FALSE) + { + rc2 = flmBeginDbTrans( pDb, FLM_READ_TRANS, 0, FLM_DONT_POISON_CACHE); + } + + rc = (RCODE) ((rc != FERR_OK) ? (RCODE) rc : (RCODE) rc2); + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE chkEndUpdate( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo) +{ + RCODE rc = FERR_OK; + RCODE rc2 = FERR_OK; + + if (pIxChkInfo->pDbInfo->bStartedUpdateTrans == TRUE) + { + + // Commit the update transaction that was started. If the + // transaction started by the application, do not commit it. + + if (RC_BAD( rc = flmCommitDbTrans( pStateInfo->pDb, 0, FALSE))) + { + goto Exit; + } + + pIxChkInfo->pDbInfo->bStartedUpdateTrans = FALSE; + } + +Exit: + + // Re-start read transaction + + if (flmGetDbTransType( pStateInfo->pDb) == FLM_NO_TRANS) + { + rc2 = flmBeginDbTrans( pStateInfo->pDb, FLM_READ_TRANS, 0, + FLM_DONT_POISON_CACHE); + } + + rc = (RCODE) ((rc != FERR_OK) ? (RCODE) rc : (RCODE) rc2); + return (rc); +} + +/**************************************************************************** +Desc: Initializes a result set for use by the logical check code +****************************************************************************/ +RCODE chkRSInit( + const char * pIoPath, + void ** ppvRSetRV) +{ + RCODE rc = FERR_OK; + FResultSet * pRSet; + + if ((pRSet = f_new FResultSet) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( rc = pRSet->Setup( pIoPath, chkCompareIxRSEntries, 0, 0, TRUE, + FALSE))) + { + goto Exit; + } + + *ppvRSetRV = (void *) pRSet; + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Sorts a result set. +****************************************************************************/ +RCODE chkRSFinalize( + IX_CHK_INFO * pIxChkInfo, + FLMUINT64 * pui64TotalEntries) +{ + RCODE rc = FERR_OK; + FResultSet * pRSet = (FResultSet *) (pIxChkInfo->pRSet); + DB_CHECK_PROGRESS * pProgress = pIxChkInfo->pDbInfo->pProgress; + DB_CHECK_PROGRESS saveInfo; + + // Save the current check phase information. + + f_memcpy( &saveInfo, pProgress, sizeof(DB_CHECK_PROGRESS)); + + // Set information for the result set sort phase. + + pProgress->iCheckPhase = CHECK_RS_SORT; + pProgress->bStartFlag = TRUE; + pProgress->ui64NumRSUnits = 0; + pProgress->ui64NumRSUnitsDone = 0; + + pRSet->SetCallback( chkRSCallbackFunc, (void *) pIxChkInfo); + + if (RC_BAD( rc = pRSet->Finalize( pui64TotalEntries))) + { + goto Exit; + } + +Exit: + + (void) pRSet->SetCallback( NULL, 0); + + // Reset the pProgress information. + + f_memcpy( pProgress, &saveInfo, sizeof(DB_CHECK_PROGRESS)); + pProgress->bStartFlag = TRUE; + + return (rc); +} + +/**************************************************************************** +Desc: Compares result set entries during the finalization stage to allow + the result set to be sorted and to remove duplicates. +****************************************************************************/ +RCODE chkCompareIxRSEntries( + void * vpData1, + FLMUINT uiLength1, + void * vpData2, + FLMUINT uiLength2, + void * UserValue, + FLMINT * piCompare) +{ + FLMBYTE * pucData1 = (FLMBYTE *) vpData1; + FLMBYTE * pucData2 = (FLMBYTE *) vpData2; + FLMUINT uiIxNum1; + FLMUINT uiIxNum2; + FLMUINT uiDrn1; + FLMUINT uiDrn2; + + F_UNREFERENCED_PARM( UserValue); + + uiIxNum1 = (FLMUINT) FB2UW( &(pucData1[RS_IX_OFFSET])); + uiIxNum2 = (FLMUINT) FB2UW( &(pucData2[RS_IX_OFFSET])); + uiDrn1 = (FLMUINT) FB2UD( &(pucData1[RS_REF_OFFSET])); + uiDrn2 = (FLMUINT) FB2UD( &(pucData2[RS_REF_OFFSET])); + + *piCompare = chkCompareKeySet( uiIxNum1, &(pucData1[RS_KEY_OFFSET]), + uiLength1 - RS_KEY_OVERHEAD, uiDrn1, uiIxNum2, + &(pucData2[RS_KEY_OFFSET]), + uiLength2 - RS_KEY_OVERHEAD, uiDrn2); + + return (FERR_OK); +} + +/**************************************************************************** +Desc: Callback for result set sort progress. +****************************************************************************/ +FLMINT chkRSCallbackFunc( + RSET_CB_INFO * pCBInfo) +{ + IX_CHK_INFO * pIxChkInfo = (IX_CHK_INFO *) pCBInfo->UserValue; + DB_CHECK_PROGRESS * pProgress = pIxChkInfo->pDbInfo->pProgress; + FLMINT iRetVal = 0; + + // Set the status values. + + pProgress->ui64NumRSUnits = pCBInfo->ui64EstTotalUnits; + pProgress->ui64NumRSUnitsDone = pCBInfo->ui64UnitsDone; + + // Call the progress callback. + + if (RC_BAD( chkCallProgFunc( pIxChkInfo->pDbInfo))) + { + iRetVal = -1; + goto Exit; + } + +Exit: + + pProgress->bStartFlag = FALSE; + return (iRetVal); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE chkBlkRead( + DB_INFO * pDbInfo, + FLMUINT uiBlkAddress, + LFILE * pLFile, + FLMBYTE ** ppBlk, + SCACHE ** ppSCache, + eCorruptionType * peCorruption) +{ + RCODE rc = FERR_OK; + FDB * pDb = pDbInfo->pDb; + FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; + + if (*ppSCache) + { + ScaReleaseCache( *ppSCache, FALSE); + *ppSCache = NULL; + *ppBlk = NULL; + } + else if (*ppBlk) + { + f_free( ppBlk); + *ppBlk = NULL; + } + + if (pDb->uiKilledTime) + { + rc = RC_SET( FERR_OLD_VIEW); + goto Exit; + } + + // Get the block from cache. + + if (RC_OK( rc = ScaGetBlock( pDb, pLFile, 0, uiBlkAddress, NULL, ppSCache))) + { + *ppBlk = (*ppSCache)->pucBlk; + } + else + { + + // Try to read the block directly from disk. + + FLMUINT uiBlkLen = pFileHdr->uiBlockSize; + FLMUINT uiTransID; + FLMBYTE * pucBlk; + FLMUINT uiLastReadTransID; + FLMUINT uiPrevBlkAddr; + FLMUINT uiFilePos; + + // If we didn't get a corruption error, jump to exit. + + if (!FlmErrorIsFileCorrupt( rc)) + { + goto Exit; + } + + // Allocate memory for the block. + + if (RC_BAD( rc = f_calloc( uiBlkLen, ppBlk))) + { + goto Exit; + } + + pucBlk = *ppBlk; + + uiFilePos = uiBlkAddress; + uiTransID = pDb->LogHdr.uiCurrTransID; + uiLastReadTransID = 0xFFFFFFFF; + + // Follow version chain until we find version we need. + + for (;;) + { + if (RC_BAD( rc = chkReadBlkFromDisk( pFileHdr, pDbInfo->pSFileHdl, + uiFilePos, uiBlkAddress, pLFile, pDb->pFile, pucBlk))) + { + goto Exit; + } + + // See if we can use the current version of the block, or if we + // must go get a previous version. + + if ((FLMUINT) FB2UD( &pucBlk[BH_TRANS_ID]) <= uiTransID) + { + break; + } + + // If the transaction ID is greater than or equal to the last + // one we read, we have a corruption. This test will keep us from + // looping around forever. + + if ((FLMUINT) FB2UD( &pucBlk[BH_TRANS_ID]) >= uiLastReadTransID) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + uiLastReadTransID = (FLMUINT) FB2UD( &pucBlk[BH_TRANS_ID]); + + // Block is too new, go for next older version. If previous + // block address is same as current file position or zero, we + // have a problem. + + uiPrevBlkAddr = (FLMUINT) FB2UD( &pucBlk[BH_PREV_BLK_ADDR]); + if ((uiPrevBlkAddr == uiFilePos) || (!uiPrevBlkAddr)) + { + rc = (pDb->uiKilledTime) + ? RC_SET( FERR_OLD_VIEW) + : RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + uiFilePos = uiPrevBlkAddr; + } + + // See if we even got the block we thought we wanted. + + if (GET_BH_ADDR( pucBlk) != uiBlkAddress) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + } + +Exit: + + *peCorruption = FLM_NO_CORRUPTION; + if (RC_BAD( rc)) + { + switch (rc) + { + case FERR_DATA_ERROR: + *peCorruption = FLM_COULD_NOT_SYNC_BLK; + break; + case FERR_BLOCK_CHECKSUM: + *peCorruption = FLM_BAD_BLK_CHECKSUM; + break; + default: + break; + } + } + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE chkReadBlkFromDisk( + FILE_HDR * pFileHdr, + F_SuperFileHdl * pSFileHdl, + FLMUINT uiFilePos, + FLMUINT uiBlkAddress, + LFILE * pLFile, + FFILE * pFile, + FLMBYTE * pBlk) +{ + RCODE rc = FERR_OK; + FLMUINT uiBytesRead; + FLMUINT uiBlkLen = pFileHdr->uiBlockSize; + + if (RC_BAD( rc = pSFileHdl->ReadBlock( uiFilePos, uiBlkLen, pBlk, + &uiBytesRead))) + { + if (rc == FERR_IO_END_OF_FILE) + { + rc = RC_SET( FERR_DATA_ERROR); + } + + goto Exit; + } + + if (uiBytesRead < uiBlkLen) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + // Verify the block checksum BEFORE decrypting or using any data. + + if (RC_BAD( rc = BlkCheckSum( pBlk, CHECKSUM_CHECK, uiBlkAddress, uiBlkLen))) + { + goto Exit; + } + + // If this is an index block it may be encrypted, we need to decrypt + // it before we can use it. The function ScaDecryptBlock will check if + // the index is encrypted first. If not, it will return. + + if (pLFile && pLFile->uiLfType == LF_INDEX) + { + if (RC_BAD( rc = ScaDecryptBlock( pFile, pBlk))) + { + goto Exit; + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE chkVerifyElmFields( + STATE_INFO * pStateInfo, + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxChkInfo, + POOL * pTmpPool, + FLMUINT * puiErrElmRecOffsetRV, + eCorruptionType * peElmCorruptCode) +{ + FLMBYTE * pValue = pStateInfo->pValue; + FLMBYTE * pData = pStateInfo->pData; + FLMBYTE * pTempValue; + FlmRecord * pRecord = pStateInfo->pRecord; + FLMBOOL bKRefAbortRec = FALSE; + FLMUINT uiSaveElmRecOffset = 0; + void * pDbPoolMark = NULL; + void * pKeyMark = NULL; + FLMBOOL bResetDbPool = FALSE; + RCODE rc = FERR_OK; + void * pvField = pStateInfo->pvField; + REC_KEY * pKeyList = NULL; + REC_KEY * pTmpKey; + + *peElmCorruptCode = FLM_NO_CORRUPTION; + + pTempValue = pValue + ? (FLMBYTE *) &pValue[pStateInfo->uiFieldProcessedLen] + : NULL; + + while( (*peElmCorruptCode == FLM_NO_CORRUPTION) && + (pStateInfo->uiElmRecOffset < pStateInfo->uiElmRecLen)) + { + uiSaveElmRecOffset = pStateInfo->uiElmRecOffset; + if ((*peElmCorruptCode = flmVerifyElmFOP( pStateInfo)) != FLM_NO_CORRUPTION) + { + break; + } + + if (!pStateInfo->bElmRecOK) + { + pValue = pTempValue = NULL; + if (pRecord) + { + pRecord->clear(); + } + + continue; + } + + switch (pStateInfo->uiFOPType) + { + case FLM_FOP_CONT_DATA: + { + if ((pTempValue != NULL) && (pStateInfo->uiFOPDataLen)) + { + f_memcpy( pTempValue, pStateInfo->pFOPData, pStateInfo->uiFOPDataLen); + pTempValue += pStateInfo->uiFOPDataLen; + } + break; + } + + case FLM_FOP_STANDARD: + case FLM_FOP_OPEN: + case FLM_FOP_TAGGED: + case FLM_FOP_NO_VALUE: + case FLM_FOP_LARGE: + { + if (pValue) + { + pValue = pTempValue = NULL; + } + + if (pvField) + { + pvField = NULL; + } + + if (!pRecord) + { + if ((pRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + } + + if (RC_BAD( rc = pRecord->insertLast( pStateInfo->uiFieldLevel, + pStateInfo->uiFieldNum, pStateInfo->uiFieldType, &pvField))) + { + goto Exit; + } + + if (pStateInfo->uiFieldLen) + { + if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, + pStateInfo->uiFieldType, pStateInfo->uiFieldLen, 0, 0, 0, + &pValue, NULL))) + { + goto Exit; + } + + pTempValue = pValue; + } + + if ((pTempValue) && (pStateInfo->uiFOPDataLen)) + { + f_memcpy( pTempValue, pStateInfo->pFOPData, pStateInfo->uiFOPDataLen); + pTempValue += pStateInfo->uiFOPDataLen; + } + break; + } + + case FLM_FOP_ENCRYPTED: + { + if (pValue) + { + pValue = pTempValue = NULL; + } + + if (pData) + { + pData = NULL; + } + + if (pvField) + { + pvField = NULL; + } + + if (!pRecord) + { + if ((pRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + } + + if (RC_BAD( rc = pRecord->insertLast( pStateInfo->uiFieldLevel, + pStateInfo->uiFieldNum, pStateInfo->uiFieldType, &pvField + ))) + { + goto Exit; + } + + if (pStateInfo->uiFieldLen) + { + if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, + pStateInfo->uiFieldType, pStateInfo->uiFieldLen, + pStateInfo->uiEncFieldLen, pStateInfo->uiEncId, + FLD_HAVE_ENCRYPTED_DATA, &pData, &pValue))) + { + goto Exit; + } + + pTempValue = pValue; + } + + if ((pTempValue) && (pStateInfo->uiFOPDataLen)) + { + f_memcpy( pTempValue, pStateInfo->pFOPData, + pStateInfo->uiFOPDataLen); + pTempValue += pStateInfo->uiFOPDataLen; + } + break; + } + + case FLM_FOP_JUMP_LEVEL: + { + break; + } + + default: + { + *peElmCorruptCode = FLM_BAD_FOP; + } + } + + if ((!pStateInfo->uiEncId && + pStateInfo->uiFieldProcessedLen == pStateInfo->uiFieldLen) || + (pStateInfo->uiEncId && + pStateInfo->uiFieldProcessedLen == pStateInfo->uiEncFieldLen)) + { + + // The whole field has been retrieved. Verify the field and graft + // it into the record being built. + + if (pValue && (pDbInfo->uiFlags & FLM_CHK_FIELDS)) + { + if (pStateInfo->uiFieldType == 0xFF) + { + + // Hit Rec Info object - don't care what's in it - must + // not assert, because this would kill our ability to check + // older versions of the database which have REC_INFO data + // in them. + + *peElmCorruptCode = FLM_NO_CORRUPTION; + } + else + { + if (!pStateInfo->uiEncId) + { + *peElmCorruptCode = flmVerifyField( pValue, + pStateInfo->uiFieldLen, + pStateInfo->uiFieldType); + } + else + { + + // Decrypt the field and store the decrypted data. + + if (!pStateInfo->pDb->pFile->bInLimitedMode) + { + if (RC_BAD( rc = flmDecryptField( pStateInfo->pDb->pDict, + pRecord, pvField, pStateInfo->uiEncId, pTmpPool + ))) + { + goto Exit; + } + + *peElmCorruptCode = flmVerifyField( pData, + pStateInfo->uiFieldLen, + pStateInfo->uiFieldType); + } + else + { + + // If we can't decrypt the field, then just pass it + // for now. + + *peElmCorruptCode = FLM_NO_CORRUPTION; + } + } + } + } + else + { + *peElmCorruptCode = FLM_NO_CORRUPTION; + } + + pValue = pTempValue = NULL; + } + + // If this is the last element of the record, verify the record's + // keys. + + if (BBE_IS_LAST( pStateInfo->pElm) && + (pStateInfo->uiElmRecOffset == pStateInfo->uiElmRecLen)) + { + pValue = pTempValue = NULL; + + if (!pDbInfo->pProgress->bPhysicalCorrupt && + (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING)) + { + FLMUINT uiLoop; + IXD * pIxd; + + if (pStateInfo->pLogicalFile->pLFile->uiLfType == LF_CONTAINER) + { + + // Need to mark the DB's temporary pool. The index code + // allocates memory for new CDL entries from the DB pool. + // If the pool is not reset, it grows during the check and + // becomes VERY large. + + pDbPoolMark = GedPoolMark( &(pDbInfo->pDb->TempPool)); + bResetDbPool = TRUE; + + // Set up the KRef table so that flmGetRecKeys will work + // correctly. + + if (RC_BAD( rc = KrefCntrlCheck( pStateInfo->pDb))) + { + goto Exit; + } + + bKRefAbortRec = TRUE; + + for (uiLoop = 0; uiLoop < pIxChkInfo->uiIxCount; uiLoop++) + { + if (RC_BAD( rc = fdictGetIndex( pStateInfo->pDb->pDict, + pStateInfo->pDb->pFile->bInLimitedMode, + pIxChkInfo->puiIxArray[uiLoop], NULL, &pIxd, TRUE))) + { + goto Exit; + } + + if (pIxd->uiFlags & IXD_OFFLINE) + { + continue; + } + + if (pIxd->uiContainerNum == pStateInfo->pLogicalFile->pLFile->uiLfNum || + !pIxd->uiContainerNum) + { + + // Mark the field pool so that it can be reset after + // the record keys have been generated and output. + + pKeyMark = GedPoolMark( pTmpPool); + + // Build the record keys for the current index. Do + // not remove duplicate keys. The result set will + // remove any duplicates. + + if (RC_BAD( rc = flmGetRecKeys( pStateInfo->pDb, pIxd, + pRecord, pStateInfo->pLogicalFile->pLFile->uiLfNum, + FALSE, pTmpPool, &pKeyList))) + { + goto Exit; + } + + // If the record generated keys for the current + // index, output the keys to the result set. + + if (pKeyList) + { + if (RC_BAD( rc = chkOutputIndexKeys( pStateInfo, + pIxChkInfo, pIxd, pKeyList))) + { + goto Exit; + } + + pTmpKey = pKeyList; + while (pTmpKey) + { + pTmpKey->pKey->Release(); + pTmpKey->pKey = NULL; + pTmpKey = pTmpKey->pNextKey; + } + + pKeyList = NULL; + } + + // Reset the field pool + + GedPoolReset( pTmpPool, pKeyMark); + } + } + + // Clean up any keys that may have been added to the KRef + // table. + + KYAbortCurrentRecord( pStateInfo->pDb); + bKRefAbortRec = FALSE; + + // Reset the DB's temporary pool + + (void) GedPoolReset( &(pDbInfo->pDb->TempPool), pDbPoolMark); + bResetDbPool = FALSE; + } + } + + if (pRecord) + { + pRecord->clear(); + } + + pValue = pTempValue = NULL; + GedPoolReset( pTmpPool, NULL); + } + + if (*peElmCorruptCode != FLM_NO_CORRUPTION) + { + pStateInfo->bElmRecOK = FALSE; + } + } + +Exit: + + // Clean up any keys that may have been added to the KRef table. This + // is a fail-safe case to clean up the KRef in case KYKeysCommit didn't + // get called above. + + if (bKRefAbortRec) + { + KYAbortCurrentRecord( pStateInfo->pDb); + } + + // Free any keys in the key list + + if (pKeyList) + { + pTmpKey = pKeyList; + while (pTmpKey) + { + pTmpKey->pKey->Release(); + pTmpKey->pKey = NULL; + pTmpKey = pTmpKey->pNextKey; + } + } + + // Reset the DB's temporary pool + + if (bResetDbPool) + { + (void) GedPoolReset( &(pDbInfo->pDb->TempPool), pDbPoolMark); + } + + if (*peElmCorruptCode != FLM_NO_CORRUPTION || RC_BAD( rc)) + { + pValue = pTempValue = NULL; + GedPoolReset( pTmpPool, NULL); + if (pRecord) + { + pRecord->clear(); + } + } + + pStateInfo->pValue = pValue; + pStateInfo->pData = pData; + pStateInfo->pvField = pvField; + pStateInfo->pRecord = pRecord; + + if (*peElmCorruptCode != FLM_NO_CORRUPTION) + { + *puiErrElmRecOffsetRV = uiSaveElmRecOffset; + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine checks all of the blocks/links in a sub-tree of a + B-TREE. It calls itself recursively whenever it descends a level in the + tree. +****************************************************************************/ +FSTATIC RCODE chkVerifySubTree( + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxChkInfo, + STATE_INFO * pParentState, + STATE_INFO * pStateInfo, + FLMUINT uiBlkAddress, + POOL * pTmpPool, + FLMBYTE * pucResetKey, + FLMUINT uiResetKeyLen, + FLMUINT uiResetDrn) +{ + RCODE rc = FERR_OK; + SCACHE * pSCache = NULL; + FLMBYTE * pBlk = NULL; + FLMUINT uiLevel = pStateInfo->uiLevel; + FLMUINT uiBlkType = pStateInfo->uiBlkType; + FLMUINT uiLfType = pStateInfo->pLogicalFile->pLFile->uiLfType; + FLMUINT uiBlockSize = pDbInfo->pDb->pFile->FileHdr.uiBlockSize; + FLMUINT uiParentBlkAddress; + FLMBYTE * pChildBlkAddr; + FLMUINT uiChildBlkAddress; + FLMUINT uiPrevNextBlkAddress; + eCorruptionType eElmCorruptCode; + eCorruptionType eBlkCorruptionCode = FLM_NO_CORRUPTION; + eCorruptionType eLastCorruptCode = FLM_NO_CORRUPTION; + FLMUINT uiNumErrors = 0; + FLMUINT uiErrElmRecOffset = 0; + FLMUINT64 ui64SaveKeyCount = 0; + FLMUINT64 ui64SaveKeyRefs = 0; + BLOCK_INFO SaveBlkInfo; + BLOCK_INFO * pBlkInfo; + FLMBOOL bProcessElm; + FLMBOOL bCountElm; + FLMBOOL bDescendToChildBlocks; + FLMINT iCompareStatus; + eCorruptionType eHdrCorruptCode; + + // Setup the state information. + + pStateInfo->pBlk = NULL; + pStateInfo->uiBlkAddress = uiBlkAddress; + uiPrevNextBlkAddress = pStateInfo->uiNextBlkAddr; + uiParentBlkAddress = (pParentState) ? pParentState->uiBlkAddress : BT_END; + + f_yieldCPU(); + + // Read the sub-tree root block into memory. + + bDescendToChildBlocks = TRUE; + if (RC_BAD( rc = chkBlkRead( pDbInfo, uiBlkAddress, + pStateInfo->pLogicalFile ? pStateInfo->pLogicalFile->pLFile : NULL, + &pBlk, &pSCache, &eBlkCorruptionCode))) + { + if (eBlkCorruptionCode != FLM_NO_CORRUPTION) + { + uiNumErrors++; + eLastCorruptCode = eBlkCorruptionCode; + chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, uiBlkAddress, + uiParentBlkAddress, 0, 0, 0xFFFF, 0, pBlk); + if (eBlkCorruptionCode == FLM_BAD_BLK_CHECKSUM) + { + bDescendToChildBlocks = FALSE; + + // Allow to continue the check, but if this is a non-leaf + // block a non-zero eBlkCorruptionCode will prevent us from + // descending to child blocks. Set rc to SUCCESS so we won't + // goto Exit below. + + rc = FERR_OK; + } + else if (eBlkCorruptionCode == FLM_COULD_NOT_SYNC_BLK) + { + eLastCorruptCode = eBlkCorruptionCode; + + // Need the goto here, because rc is changed to SUCCESS, and + // the goto below would get skipped. + + rc = FERR_OK; + goto fix_state; + } + } + else if (rc == FERR_OLD_VIEW) + { + pDbInfo->bReposition = TRUE; + } + + // If rc was not changed to SUCCESS above, goto Exit. + + if (RC_BAD( rc)) + { + goto Exit; + } + } + + pStateInfo->pBlk = pBlk; + + // Verify the block header; Don't re-count the block if we are resetting. + + if (!uiResetKeyLen) + { + pDbInfo->pProgress->ui64BytesExamined += (FLMUINT64) uiBlockSize; + pBlkInfo = &pStateInfo->BlkInfo; + } + else + { + pBlkInfo = NULL; + } + + chkCallProgFunc( pDbInfo); + + // Check the block header. + + if (( eHdrCorruptCode = flmVerifyBlockHeader( pStateInfo, pBlkInfo, + uiBlockSize, (pParentState == NULL) ? BT_END : 0, + (pParentState == NULL) ? BT_END : pParentState->uiLastChildAddr, + TRUE, TRUE)) == FLM_NO_CORRUPTION) + { + + // Verify the previous block's next block address -- it should equal + // the current block's address. + + if ((uiPrevNextBlkAddress) && (uiPrevNextBlkAddress != uiBlkAddress)) + { + eHdrCorruptCode = FLM_BAD_PREV_BLK_NEXT; + } + } + + if (eHdrCorruptCode != FLM_NO_CORRUPTION) + { + eLastCorruptCode = eHdrCorruptCode; + uiNumErrors++; + chkReportError( pDbInfo, eHdrCorruptCode, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, uiBlkAddress, + uiParentBlkAddress, 0, 0, 0xFFFF, 0, pBlk); + } + + // Go through the elements in the block. + + pStateInfo->uiElmOffset = BH_OVHD; + while ((pStateInfo->uiElmOffset < pStateInfo->uiEndOfBlock) && + (RC_OK( pDbInfo->LastStatusRc))) + { + + // If we are resetting, save any statistical information so we can + // back it out if we need to. + + if (uiResetKeyLen) + { + ui64SaveKeyCount = pStateInfo->ui64KeyCount; + ui64SaveKeyRefs = pStateInfo->ui64KeyRefs; + f_memcpy( &SaveBlkInfo, &pStateInfo->BlkInfo, sizeof(BLOCK_INFO)); + bCountElm = FALSE; + bProcessElm = FALSE; + } + else + { + bCountElm = TRUE; + bProcessElm = TRUE; + } + + pStateInfo->BlkInfo.ui64ElementCount++; + + if ((eElmCorruptCode = flmVerifyElement( + pStateInfo, pDbInfo->uiFlags)) != FLM_NO_CORRUPTION) + { + + // Report any errors in the element. + + eLastCorruptCode = eElmCorruptCode; + uiNumErrors++; + if (RC_BAD( rc = chkReportError( pDbInfo, eElmCorruptCode, + LOCALE_B_TREE, pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, uiBlkAddress, + uiParentBlkAddress, pStateInfo->uiElmOffset, + pStateInfo->uiElmDrn, 0xFFFF, 0, pBlk))) + { + break; + } + } + + // Keep track of the number of continuation elements. + + if ((uiBlkType == BHT_LEAF) && + (!BBE_IS_FIRST( pStateInfo->pElm)) && + (pStateInfo->uiElmLen != BBE_LEM_LEN)) + { + pStateInfo->BlkInfo.ui64ContElementCount++; + pStateInfo->BlkInfo.ui64ContElmBytes += pStateInfo->uiElmLen; + } + + // Do some further checking. + + if (eElmCorruptCode != FLM_NO_CORRUPTION) + { + pStateInfo->bElmRecOK = FALSE; + } + else + { + + // See if we are resetting + + iCompareStatus = 0; + if (uiResetKeyLen && pStateInfo->bValidKey && + ((!pStateInfo->uiCurKeyLen) || + ((iCompareStatus = flmCompareKeys( pStateInfo->pCurKey, + pStateInfo->uiCurKeyLen, pucResetKey, + uiResetKeyLen)) >= 0))) + { + if (iCompareStatus > 0) + { + if (uiBlkType == BHT_LEAF) + { + uiResetKeyLen = 0; + pucResetKey = NULL; + uiResetDrn = 0; + bCountElm = TRUE; + } + + bProcessElm = TRUE; + } + else if (uiLfType == LF_INDEX) + { + FLMBYTE * pTmpElm = pStateInfo->pElm; + FLMUINT uiLowestDrn = FSGetDomain( &pTmpElm, + pStateInfo->uiElmOvhd); + + if (uiResetDrn >= uiLowestDrn) + { + bProcessElm = TRUE; + bCountElm = TRUE; + } + } + else + { + + // Processing a container + + bProcessElm = TRUE; + } + } + + if (uiBlkType == BHT_LEAF) + { + + // No need to parse LEM element. + + if ((pStateInfo->uiCurKeyLen != 0) && (pStateInfo->bValidKey)) + { + if (uiLfType == LF_CONTAINER) + { + if (pStateInfo->uiElmDrn != DRN_LAST_MARKER) + { + if (RC_BAD( rc = chkVerifyElmFields( pStateInfo, pDbInfo, + pIxChkInfo, pTmpPool, &uiErrElmRecOffset, + &eElmCorruptCode))) + { + goto Exit; + } + } + } + else if (bProcessElm) + { + uiErrElmRecOffset = 0xFFFF; + if (!pDbInfo->pProgress->bPhysicalCorrupt && + (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING)) + { + if ((RC_BAD( rc = flmVerifyIXRefs( pStateInfo, + pIxChkInfo, uiResetDrn, &eElmCorruptCode))) || + pDbInfo->bReposition) + { + goto Exit; + } + } + else + { + if ((RC_BAD( rc = flmVerifyIXRefs( pStateInfo, NULL, + uiResetDrn, &eElmCorruptCode))) || + pDbInfo->bReposition) + { + goto Exit; + } + } + } + } + + if (bProcessElm) + { + uiResetKeyLen = 0; + pucResetKey = NULL; + uiResetDrn = 0; + + if (eElmCorruptCode != FLM_NO_CORRUPTION) + { + + // Report any errors in the element. + + eLastCorruptCode = eElmCorruptCode; + uiNumErrors++; + chkReportError( pDbInfo, eElmCorruptCode, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, + uiBlkAddress, uiParentBlkAddress, + pStateInfo->uiElmOffset, pStateInfo->uiElmDrn, + uiErrElmRecOffset, pStateInfo->uiFieldNum, pBlk); + + if (RC_BAD( pDbInfo->LastStatusRc)) + { + break; + } + } + } + } + else + { + if (uiBlkType == BHT_NON_LEAF_DATA) + { + pChildBlkAddr = &pStateInfo->pElm[BNE_DATA_CHILD_BLOCK]; + } + else + { + pChildBlkAddr = &pStateInfo->pElm[BNE_CHILD_BLOCK]; + } + + uiChildBlkAddress = (FLMUINT) FB2UD( pChildBlkAddr); + + // Check the child sub-tree -- NOTE, this is a recursive call. + // First see if we have a pucResetKey that we want to position + // to. If so, make sure we are positioned to it before + // descending to the child block. + + if (bProcessElm) + { + if (!bDescendToChildBlocks) + { + rc = FERR_OK; + } + else + { + rc = chkVerifySubTree( pDbInfo, pIxChkInfo, pStateInfo, + (pStateInfo - 1), uiChildBlkAddress, + pTmpPool, pucResetKey, uiResetKeyLen, + uiResetDrn); + } + + if ((RC_BAD( rc)) || + (RC_BAD( pDbInfo->LastStatusRc)) || + (pDbInfo->bReposition)) + { + goto Exit; + } + + // Once we reach the key, set it to an empty to key so that + // we will always descend to the child block after this + // point. + + uiResetKeyLen = 0; + pucResetKey = NULL; + uiResetDrn = 0; + } + + // Save the child block address in the level information. + + pStateInfo->uiLastChildAddr = uiChildBlkAddress; + } + } + + // If we were resetting on this element, restore the statistics to + // what they were before. + + if (!bCountElm) + { + pStateInfo->ui64KeyCount = ui64SaveKeyCount; + pStateInfo->ui64KeyRefs = ui64SaveKeyRefs; + f_memcpy( &pStateInfo->BlkInfo, &SaveBlkInfo, sizeof(BLOCK_INFO)); + } + + // Go to the next element. + + pStateInfo->uiElmOffset += pStateInfo->uiElmLen; + } + + // Verify that we ended exactly on the end of the block. + + if ((eLastCorruptCode == FLM_NO_CORRUPTION) && + (pStateInfo->uiEndOfBlock >= BH_OVHD) && + (pStateInfo->uiEndOfBlock <= uiBlockSize) && + (pStateInfo->uiElmOffset > pStateInfo->uiEndOfBlock)) + { + eLastCorruptCode = FLM_BAD_ELM_END; + uiNumErrors++; + chkReportError( pDbInfo, eLastCorruptCode, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, uiBlkAddress, + uiParentBlkAddress, pStateInfo->uiElmOffset, 0, 0xFFFF, 0, + pBlk); + } + + // Verify that the last key in the block matches the parent's key. + + if ((eLastCorruptCode == FLM_NO_CORRUPTION) && + (pParentState) && + (RC_OK( pDbInfo->LastStatusRc))) + { + if (pStateInfo->bValidKey && + pParentState->bValidKey && + (flmCompareKeys( pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, + pParentState->pCurKey, pParentState->uiCurKeyLen) != 0)) + { + eLastCorruptCode = FLM_BAD_PARENT_KEY; + uiNumErrors++; + chkReportError( pDbInfo, eLastCorruptCode, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiLevel, uiBlkAddress, + uiParentBlkAddress, 0, 0, 0xFFFF, 0, pBlk); + } + } + +fix_state: + + // If the block could not be verified, set the level's next block + // address and last child address to zero to indicate that we really + // aren't sure we're at the right place in this level in the B-TREE. + + if (eLastCorruptCode != FLM_NO_CORRUPTION) + { + pStateInfo->BlkInfo.eCorruption = eLastCorruptCode; + pStateInfo->BlkInfo.uiNumErrors += uiNumErrors; + + // Reset all child block states. + + for (;;) + { + pStateInfo->uiNextBlkAddr = 0; + pStateInfo->uiLastChildAddr = 0; + pStateInfo->bValidKey = FALSE; + pStateInfo->uiElmLastFlag = 0xFF; + + // Quit when the leaf level has been reached. + + if (pStateInfo->uiLevel == 0) + { + break; + } + + pStateInfo--; + } + } + +Exit: + + if (pSCache) + { + ScaReleaseCache( pSCache, FALSE); + } + else if (pBlk) + { + f_free( &pBlk); + } + + pStateInfo->pBlk = NULL; + return (rc); +} + +/**************************************************************************** +Desc: This routine reads the LFH areas from disk to make sure they are up + to date in memory. +****************************************************************************/ +FSTATIC RCODE chkGetLfInfo( + DB_INFO * pDbInfo, + POOL * pPool, + LF_STATS * pLfStats, + LFILE * pLFile, + LF_STATS * pCurrLfStats, + FLMBOOL * pbCurrLfLevelChangedRV) +{ + RCODE rc = FERR_OK; + SCACHE * pSCache = NULL; + FLMBYTE * pBlk = NULL; + FLMUINT uiSaveLevel; + eCorruptionType eBlkCorruptionCode; + + // Read in the block containing the logical file header. + + if (RC_BAD( rc = chkBlkRead( pDbInfo, pLFile->uiBlkAddress, pLFile, &pBlk, + &pSCache, &eBlkCorruptionCode))) + { + + // Log the error. + + if (eBlkCorruptionCode != FLM_NO_CORRUPTION) + { + chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_LFH_LIST, 0, 0, + 0xFF, pLFile->uiBlkAddress, 0, 0, 0, 0xFFFF, 0, pBlk); + } + + goto Exit; + } + + // Copy the LFH from the block to the LFILE. + + uiSaveLevel = pLfStats->uiNumLevels; + if (RC_BAD( rc = flmBufferToLFile( &pBlk[pLFile->uiOffsetInBlk], pLFile, + pLFile->uiBlkAddress, pLFile->uiOffsetInBlk))) + { + goto Exit; + } + + // Read root block to get the number of levels in the B-TREE + + if (pLFile->uiRootBlk == BT_END) + { + pLfStats->uiNumLevels = 0; + } + else + { + if (RC_BAD( rc = chkBlkRead( pDbInfo, pLFile->uiRootBlk, pLFile, &pBlk, + &pSCache, &eBlkCorruptionCode))) + { + if (eBlkCorruptionCode != FLM_NO_CORRUPTION) + { + chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_B_TREE, + pLFile->uiLfNum, pLFile->uiLfType, 0xFF, + pLFile->uiRootBlk, 0, 0, 0, 0xFFFF, 0, pBlk); + } + + goto Exit; + } + + pLfStats->uiNumLevels = (FLMUINT) (pBlk[BH_LEVEL]) + 1; + + // Make sure that the level extracted from the block is valid. + + if (pBlk[BH_LEVEL] >= BH_MAX_LEVELS) + { + chkReportError( pDbInfo, FLM_BAD_BLK_HDR_LEVEL, LOCALE_B_TREE, + pLFile->uiLfNum, pLFile->uiLfType, + (FLMUINT) (pBlk[BH_LEVEL]), pLFile->uiRootBlk, 0, 0, 0, + 0xFFFF, 0, pBlk); + + // Force pLfStats->uiNumLevels to 1 so that we don't crash + + pLfStats->uiNumLevels = 1; + } + } + + // If the number of levels changed, reset the level information on this + // logical file. + + if (uiSaveLevel != pLfStats->uiNumLevels && pLfStats->uiNumLevels) + { + if (pLfStats->uiNumLevels > uiSaveLevel) + { + if ((pLfStats->pLevelInfo = (LEVEL_INFO *) GedPoolCalloc( pPool, + (FLMUINT) (sizeof(LEVEL_INFO) * pLfStats->uiNumLevels))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + } + + if (pCurrLfStats == pLfStats) + { + *pbCurrLfLevelChangedRV = TRUE; + } + } + +Exit: + + if (pSCache) + { + ScaReleaseCache( pSCache, FALSE); + } + else if (pBlk) + { + f_free( &pBlk); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine allocates and initializes the LF table (array of + LF_HDR structures). +****************************************************************************/ +FSTATIC RCODE chkSetupLfTable( + DB_INFO * pDbInfo, + POOL * pPool) +{ + RCODE rc = FERR_OK; + FLMUINT uiCnt; + FLMUINT uiNumIndexes = 0; + FLMUINT uiIxStart; + FLMUINT uiNumDataCont = 0; + FLMUINT uiNumDictCont = 0; + FLMUINT uiIxOffset; + FLMUINT uiDataOffset; + FLMUINT uiDictOffset; + FDB * pDb = pDbInfo->pDb; + LFILE * pLFile; + LFILE * pTmpLFile; + LF_HDR * pLogicalFile; + LF_STATS * pLfStats; + + // Set up the table such that the dictionary is checked first, followed + // by data containers, and then indexes. This is necessary for the + // logical (index) check to work. The data records must be extracted + // before the indexes are checked so that the temporary result set, + // used during the logical check, can be built. + + pDbInfo->pProgress->uiNumFields = 0; + pDbInfo->pProgress->uiNumIndexes = 0; + pDbInfo->pProgress->uiNumContainers = 0; + + pDbInfo->pProgress->uiNumLogicalFiles = (FLMUINT) ((pDb->pDict) + ? (FLMUINT) pDb->pDict->uiLFileCnt + : (FLMUINT) 0); + + // Determine the number of fields. + + if (pDb->pDict) + { + chkCountFields( pDb->pDict, &pDbInfo->pProgress->uiNumFields); + + for (uiCnt = 0, pLFile = (LFILE *) pDb->pDict->pLFileTbl; + uiCnt < pDb->pDict->uiLFileCnt; + uiCnt++, pLFile++) + { + if (pLFile->uiLfType == LF_INDEX) + { + pDbInfo->pProgress->uiNumIndexes++; + uiNumIndexes++; + } + else + { + pDbInfo->pProgress->uiNumContainers++; + if (pLFile->uiLfNum == FLM_DICT_CONTAINER) + { + uiNumDictCont++; + } + else + { + uiNumDataCont++; + } + } + } + } + + // Allocate memory for each LFILE, then set up each LFILE. + + if (!pDbInfo->pProgress->uiNumLogicalFiles) + { + pDbInfo->pLogicalFiles = NULL; + pDbInfo->pProgress->pLfStats = NULL; + } + else + { + if ((pDbInfo->pLogicalFiles = (LF_HDR *) GedPoolCalloc( pPool, (FLMUINT) + (sizeof(LF_HDR) * pDbInfo->pProgress->uiNumLogicalFiles))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if ((pDbInfo->pProgress->pLfStats = (LF_STATS *) GedPoolCalloc( pPool, + (FLMUINT)(sizeof(LF_STATS) * + pDbInfo->pProgress->uiNumLogicalFiles))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + uiDictOffset = 0; + uiDataOffset = uiNumDictCont; + uiIxOffset = uiDataOffset + uiNumDataCont; + uiIxStart = uiIxOffset; + + for (uiCnt = 0, pTmpLFile = (LFILE *) pDb->pDict->pLFileTbl; + uiCnt < pDbInfo->pProgress->uiNumLogicalFiles; + uiCnt++, pTmpLFile++) + { + if (pTmpLFile->uiLfType == LF_INDEX) + { + FLMUINT uiTmpIxOffset = uiIxOffset; + + // Indexes need to be in order from lowest to highest because + // the result set is sorted that way. + + while (uiTmpIxOffset > uiIxStart) + { + if (pDbInfo->pLogicalFiles[uiTmpIxOffset - 1].pLFile->uiLfNum < + pTmpLFile->uiLfNum) + { + break; + } + + f_memcpy( &pDbInfo->pLogicalFiles[uiTmpIxOffset], + &pDbInfo->pLogicalFiles[uiTmpIxOffset - 1], + sizeof(LF_HDR)); + + f_memcpy( &pDbInfo->pProgress->pLfStats[uiTmpIxOffset], + &pDbInfo->pProgress->pLfStats[uiTmpIxOffset - 1], + sizeof(LF_STATS)); + + uiTmpIxOffset--; + } + + pLogicalFile = &(pDbInfo->pLogicalFiles[uiTmpIxOffset]); + pLfStats = &(pDbInfo->pProgress->pLfStats[uiTmpIxOffset]); + uiIxOffset++; + } + else + { + if (pTmpLFile->uiLfNum == FLM_DICT_CONTAINER) + { + pLogicalFile = &(pDbInfo->pLogicalFiles[uiDictOffset]); + pLfStats = &(pDbInfo->pProgress->pLfStats[uiDictOffset]); + uiDictOffset++; + } + else + { + pLogicalFile = &(pDbInfo->pLogicalFiles[uiDataOffset]); + pLfStats = &(pDbInfo->pProgress->pLfStats[uiDataOffset]); + uiDataOffset++; + } + } + + pLogicalFile->pLfStats = pLfStats; + + // Copy the LFILE information - so we can return the information + // even after the database has been closed. + + if ((pLogicalFile->pLFile = pLFile = (LFILE *) GedPoolAlloc( pPool, + (FLMUINT) sizeof(LFILE))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + // Copy the LFILE structure so we can get enough information to + // read them from disk, then read them from disk so we have a + // read-consistent view of them. + + f_memcpy( pLFile, pTmpLFile, sizeof(LFILE)); + if (RC_BAD( rc = flmLFileRead( pDb, pLFile))) + { + goto Exit; + } + + pLfStats->uiLfType = pLFile->uiLfType; + if (pLFile->uiLfType == LF_INDEX) + { + pLfStats->uiIndexNum = pLFile->uiLfNum; + pLfStats->uiContainerNum = 0; + } + else + { + pLfStats->uiIndexNum = 0; + pLfStats->uiContainerNum = pLFile->uiLfNum; + } + + // If the logical file is an index, get pointers to the index + // definition and its field definitions. + + if (pLFile->uiLfType == LF_INDEX) + { + IXD * pTmpIxd; + IFD * pTmpIfd; + + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, + pDb->pFile->bInLimitedMode, pLFile->uiLfNum, NULL, + &pTmpIxd, TRUE))) + { + if (rc == FERR_BAD_IX) + { + chkReportError( pDbInfo, FLM_BAD_PCODE_IXD_TBL, + LOCALE_IXD_TBL, pLFile->uiLfNum, + pLFile->uiLfType, 0xFF, 0, 0, 0, 0, 0xFFFF, 0, + NULL); + rc = RC_SET( FERR_PCODE_ERROR); + } + + goto Exit; + } + + pTmpIfd = pTmpIxd->pFirstIfd; + + // Copy the IXD and IFD information - so we can return the + // information even after the database has been closed. + + if ((pLogicalFile->pIxd = (IXD *) GedPoolAlloc( pPool, (FLMUINT) + (sizeof(IXD) + sizeof(IFD) * pTmpIxd->uiNumFlds))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pLogicalFile->pIfd = (IFD *) (&pLogicalFile->pIxd[1]); + f_memcpy( pLogicalFile->pIxd, pTmpIxd, sizeof(IXD)); + f_memcpy( pLogicalFile->pIfd, pTmpIfd, + sizeof(IFD) * pTmpIxd->uiNumFlds); + pLfStats->uiContainerNum = pLogicalFile->pIxd->uiContainerNum; + } + + // Get the current number of levels in the logical file and + // allocate an array of LEVEL_INFO structures for the levels. + + pLfStats->uiNumLevels = 0; + if (RC_BAD( rc = chkGetLfInfo( pDbInfo, pPool, pLfStats, pLFile, NULL, + NULL))) + { + goto Exit; + } + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: This routine checks all of the B-TREES in the database -- all + indexes and containers. +****************************************************************************/ +RCODE chkVerifyBTrees( + DB_INFO * pDbInfo, + POOL * pPool, + FLMBOOL * pbStartOverRV) +{ + RCODE rc = FERR_OK; + FDB * pDb = pDbInfo->pDb; + FLMUINT uiCurrLf; + FLMUINT uiCurrLevel; + FLMBYTE * pKeyBuffer = NULL; + FLMUINT uiKeysAllocated = 0; + STATE_INFO State[BH_MAX_LEVELS]; + FLMBOOL bStateInitialized[BH_MAX_LEVELS]; + FLMBYTE ucResetKeyBuff[MAX_KEY_SIZ]; + FLMBYTE * pucResetKey = NULL; + FLMUINT uiResetKeyLen = 0; + FLMUINT uiResetDrn = 0; + LF_HDR * pLogicalFile; + LF_STATS * pLfStats; + LFILE * pLFile; + FLMUINT uiSaveDictSeq; + FLMUINT uiTmpLf; + LF_STATS * pTmpLfStats; + POOL tmpPool; + FLMBOOL bRSFinalized = FALSE; + DB_CHECK_PROGRESS * pProgress = pDbInfo->pProgress; + IX_CHK_INFO IxChkInfo; + IX_CHK_INFO * pIxChkInfo = NULL; + void * pvPoolMark; + FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; + + for (uiCurrLevel = 0; uiCurrLevel < BH_MAX_LEVELS; uiCurrLevel++) + { + bStateInitialized[uiCurrLevel] = FALSE; + } + + if (*pbStartOverRV) + { + goto Exit; + } + + pvPoolMark = GedPoolMark( pPool); + uiSaveDictSeq = pDb->pDict->uiDictSeq; + + if (RC_BAD( rc = chkSetupLfTable( pDbInfo, pPool))) + { + goto Exit; + } + + if (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) + { + if (RC_BAD( rc = chkSetupIxInfo( pDbInfo, &IxChkInfo))) + { + goto Exit; + } + + pIxChkInfo = &IxChkInfo; + } + + // Loop through all of the logical files in the database and perform a + // structural and logical check. + + uiCurrLf = 0; + while (uiCurrLf < pDbInfo->pProgress->uiNumLogicalFiles) + { + pProgress->uiCurrLF = uiCurrLf + 1; + pLogicalFile = &pDbInfo->pLogicalFiles[uiCurrLf]; + pLfStats = &pDbInfo->pProgress->pLfStats[uiCurrLf]; + pLFile = pLogicalFile->pLFile; + if (pLFile->uiRootBlk == BT_END) + { + rc = FERR_OK; + uiCurrLf++; + uiResetKeyLen = 0; + pucResetKey = NULL; + uiResetDrn = 0; + continue; + } + + // Allocate space to hold the keys, if not already allocated. + + if (uiKeysAllocated < pLfStats->uiNumLevels) + { + + // If there is already a key allocated, deallocate it + + if (pKeyBuffer) + { + f_free( &pKeyBuffer); + uiKeysAllocated = 0; + } + + if (RC_BAD( rc = f_alloc( pLfStats->uiNumLevels * MAX_KEY_SIZ, + &pKeyBuffer))) + { + goto Exit; + } + + uiKeysAllocated = pLfStats->uiNumLevels; + } + + // Setup PROGRESS_CHECK_INFO structure + + pProgress->iCheckPhase = CHECK_B_TREE; + pProgress->bStartFlag = TRUE; + pProgress->uiLfNumber = pLFile->uiLfNum; + pProgress->uiLfType = pLFile->uiLfType; + + if (pLFile->uiLfType == LF_INDEX) + { + pProgress->bUniqueIndex = (pLogicalFile->pIxd->uiFlags & IXD_UNIQUE) + ? TRUE + : FALSE; + } + + if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) + { + break; + } + + pProgress->bStartFlag = FALSE; + + // Initialize the state information for each level of the B-TREE. + + for (uiCurrLevel = 0; uiCurrLevel < pLfStats->uiNumLevels; uiCurrLevel++) + { + + // If we are resetting to a particular key, save the statistics + // which were gathered so far. + + if (uiResetKeyLen) + { + + // Save the statistics which were gathered. + + pLfStats->pLevelInfo[uiCurrLevel].ui64KeyCount = + State[uiCurrLevel].ui64KeyCount; + + f_memcpy( &pLfStats->pLevelInfo[uiCurrLevel].BlockInfo, + &State[uiCurrLevel].BlkInfo, sizeof(BLOCK_INFO)); + } + + flmInitReadState( &State[uiCurrLevel], &bStateInitialized[uiCurrLevel], + pFileHdr->uiVersionNum, pDb, pLogicalFile, + uiCurrLevel, (FLMUINT) ((!uiCurrLevel) + ? (FLMUINT) BHT_LEAF + : (FLMUINT) BHT_NON_LEAF), + &pKeyBuffer[uiCurrLevel * MAX_KEY_SIZ]); + + if (!uiResetKeyLen) + { + State[uiCurrLevel].uiLastChildAddr = BT_END; + State[uiCurrLevel].uiElmLastFlag = TRUE; + } + else + { + + // Restore the statistics which were gathered so far. + + State[uiCurrLevel].ui64KeyCount = + pLfStats->pLevelInfo[uiCurrLevel].ui64KeyCount; + + f_memcpy( &State[uiCurrLevel].BlkInfo, + &pLfStats->pLevelInfo[uiCurrLevel].BlockInfo, + sizeof(BLOCK_INFO)); + } + } + + // Need to finalize the result set used by the logical check. If the + // current logical file is an index and the result set has not been + // finalized, call chkRSFinalize. + + if (!pDbInfo->pProgress->bPhysicalCorrupt && + (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) && + bRSFinalized == FALSE && + pLFile->uiLfType == LF_INDEX) + { + FLMUINT64 ui64NumRSKeys = 0; + + // Finalize the result set. + + if (RC_BAD( rc = chkRSFinalize( pIxChkInfo, &ui64NumRSKeys))) + { + goto Exit; + } + + // Reset uiNumKeys to reflect the number of keys in the result + // set now that all duplicates have been eliminated. + + if (pDbInfo->pProgress->ui64NumKeys > ui64NumRSKeys) + { + pDbInfo->pProgress->ui64NumDuplicateKeys = + pDbInfo->pProgress->ui64NumKeys - ui64NumRSKeys; + } + + pDbInfo->pProgress->ui64NumKeys = ui64NumRSKeys; + + // Set bRSFinalized to TRUE so that subsequent passes will not + // attempt to finalize the result set again. + + bRSFinalized = TRUE; + } + + // Call chkVerifySubTree to check the B-TREE starting at the root + // block. + + GedPoolInit( &tmpPool, 512); + pDbInfo->bReposition = FALSE; + + rc = chkVerifySubTree( pDbInfo, pIxChkInfo, NULL, + &State[pLfStats->uiNumLevels - 1], + pLFile->uiRootBlk, &tmpPool, pucResetKey, + uiResetKeyLen, uiResetDrn); + GedPoolFree( &tmpPool); + + if (rc == FERR_OLD_VIEW) + { + + // If it is a read transaction, reset. + + if (flmGetDbTransType( pDb) == FLM_READ_TRANS) + { + + // Free the KrefCntrl + + KrefCntrlFree( pDb); + + // Abort the read transaction + + if (RC_BAD( rc = flmAbortDbTrans( pDb))) + { + goto Exit; + } + + // Try to start a new read transaction + + if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_READ_TRANS, 0, + FLM_DONT_POISON_CACHE))) + { + goto Exit; + } + } + + rc = FERR_OK; + pDbInfo->bReposition = TRUE; + } + + if (RC_BAD( rc)) + { + goto Exit; + } + + // We may get told to reposition if we had to repair an index or we + // got an old view error. + + if (pDbInfo->bReposition) + { + + // If the dictionary has changed we must start all over. + + if (pDb->pDict->uiDictSeq != uiSaveDictSeq) + { + *pbStartOverRV = TRUE; + goto Exit; + } + + // Save the current key at the bottom level of the B-Tree. This + // is the point we want to try to reset to. Don't change the + // reset key if the current key length is zero - this may have + // occurred because of some error - we want to keep moving + // forward in the file if at all possible. + + if (State[0].uiCurKeyLen) + { + uiResetKeyLen = State[0].uiCurKeyLen; + pucResetKey = &ucResetKeyBuff[0]; + uiResetDrn = State[0].uiCurrIxRefDrn; + f_memcpy( pucResetKey, State[0].pCurKey, uiResetKeyLen); + } + + // Re-read each logical file's LFH information. + + pProgress->ui64DatabaseSize = FSGetSizeInBytes( + pDb->pFile->uiMaxFileSize, pDb->LogHdr.uiLogicalEOF); + + // Reread each of the LFH blocks and update the root block + // address and other pertinent information for each logical file. + + for (uiTmpLf = 0, pTmpLfStats = pDbInfo->pProgress->pLfStats; + uiTmpLf < pDbInfo->pProgress->uiNumLogicalFiles; + uiTmpLf++, pTmpLfStats++) + { + FLMBOOL bCurrLfLevelChanged = FALSE; + + if (RC_BAD( rc = chkGetLfInfo( pDbInfo, pPool, pTmpLfStats, + pDbInfo->pLogicalFiles[uiTmpLf].pLFile, pLfStats, + &bCurrLfLevelChanged))) + { + goto Exit; + } + + // If the number of levels for the current logical file + // changed, reset things so we will recheck the entire logical + // file. + + if (bCurrLfLevelChanged) + { + pucResetKey = NULL; + uiResetKeyLen = 0; + } + } + + continue; + } + + // Verify that all of the levels' next block address's are BT_END. + + if (RC_OK( pDbInfo->LastStatusRc)) + { + for (uiCurrLevel = 0; + uiCurrLevel < pLfStats->uiNumLevels; + uiCurrLevel++) + { + + // Save the statistics which were gathered. + + pLfStats->pLevelInfo[uiCurrLevel].ui64KeyCount = + State[uiCurrLevel].ui64KeyCount; + + f_memcpy( &pLfStats->pLevelInfo[uiCurrLevel].BlockInfo, + &State[uiCurrLevel].BlkInfo, sizeof(BLOCK_INFO)); + + // Make sure the last block had a NEXT block address of + // BT_END. + + if ((State[uiCurrLevel].uiNextBlkAddr) && + (State[uiCurrLevel].uiNextBlkAddr != BT_END)) + { + chkReportError( pDbInfo, FLM_BAD_LAST_BLK_NEXT, LOCALE_B_TREE, + pDbInfo->pProgress->uiLfNumber, + pDbInfo->pProgress->uiLfType, uiCurrLevel, 0, 0, + 0, 0, 0xFFFF, 0, NULL); + } + } + } + + if (RC_BAD( pDbInfo->LastStatusRc)) + { + break; + } + + uiCurrLf++; + pucResetKey = NULL; + uiResetKeyLen = 0; + uiResetDrn = 0; + } + + // If index check was requested, no structural corruptions were + // detected, and this is the last logical file, need to make sure that + // the result set is empty. + + if (RC_OK( rc) && + !pDbInfo->pProgress->bPhysicalCorrupt && + (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) && + bRSFinalized == TRUE && + uiCurrLf == pDbInfo->pProgress->uiNumLogicalFiles) + { + for (;;) + { + if (RC_BAD( rc = chkGetNextRSKey( pIxChkInfo))) + { + if (rc == FERR_EOF_HIT || rc == FERR_NOT_FOUND) + { + rc = FERR_OK; + break; + } + + goto Exit; + } + else + { + + // Updated statistics + + pIxChkInfo->pDbInfo->pProgress->ui64NumKeysExamined++; + + if (RC_BAD( rc = chkResolveIXMissingKey( &(State[0]), pIxChkInfo))) + { + goto Exit; + } + } + } + } + + // Clear the unique index flag + + pProgress->bUniqueIndex = FALSE; + +Exit: + + // Clear the pRecord for each level in the state array. + + for (uiCurrLevel = 0; uiCurrLevel < BH_MAX_LEVELS; uiCurrLevel++) + { + if (bStateInitialized[uiCurrLevel] && State[uiCurrLevel].pRecord) + { + State[uiCurrLevel].pRecord->Release(); + State[uiCurrLevel].pRecord = NULL; + } + } + + // Cleanup any temporary index check files + + if (pIxChkInfo != NULL) + { + chkFreeIxInfo( pIxChkInfo); + } + + if (pKeyBuffer) + { + f_free( &pKeyBuffer); + } + + if (RC_OK( rc) && RC_BAD( pDbInfo->LastStatusRc)) + { + rc = pDbInfo->LastStatusRc; + } + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE chkReportError( + DB_INFO * pDbInfo, + eCorruptionType eCorruption, + eCorruptionLocale eErrLocale, + FLMUINT uiErrLfNumber, + FLMUINT uiErrLfType, + FLMUINT uiErrBTreeLevel, + FLMUINT uiErrBlkAddress, + FLMUINT uiErrParentBlkAddress, + FLMUINT uiErrElmOffset, + FLMUINT uiErrDrn, + FLMUINT uiErrElmRecOffset, + FLMUINT uiErrFieldNum, + FLMBYTE * pBlk) +{ + CORRUPT_INFO CorruptInfo; + FLMBOOL bFixErr; + + CorruptInfo.eCorruption = eCorruption; + CorruptInfo.eErrLocale = eErrLocale; + CorruptInfo.uiErrLfNumber = uiErrLfNumber; + CorruptInfo.uiErrLfType = uiErrLfType; + CorruptInfo.uiErrBTreeLevel = uiErrBTreeLevel; + CorruptInfo.uiErrBlkAddress = uiErrBlkAddress; + CorruptInfo.uiErrParentBlkAddress = uiErrParentBlkAddress; + CorruptInfo.uiErrElmOffset = uiErrElmOffset; + CorruptInfo.uiErrDrn = uiErrDrn; + CorruptInfo.uiErrElmRecOffset = uiErrElmRecOffset; + CorruptInfo.uiErrFieldNum = uiErrFieldNum; + CorruptInfo.pBlk = pBlk; + CorruptInfo.pErrIxKey = NULL; + CorruptInfo.pErrRecord = NULL; + CorruptInfo.pErrRecordKeyList = NULL; + if ((pDbInfo->fnStatusFunc) && (RC_OK( pDbInfo->LastStatusRc))) + { + bFixErr = FALSE; + pDbInfo->LastStatusRc = (*pDbInfo->fnStatusFunc) + (FLM_PROBLEM_STATUS, (void *) &CorruptInfo, (void *) &bFixErr, + pDbInfo->pProgress->AppArg); + } + + if (eCorruption != FLM_OLD_VIEW) + { + pDbInfo->pProgress->bPhysicalCorrupt = TRUE; + pDbInfo->uiFlags &= ~FLM_CHK_INDEX_REFERENCING; + } + + return (pDbInfo->LastStatusRc); +} + +/**************************************************************************** +Desc: Initializes an IX_CHK_INFO structure +****************************************************************************/ +FSTATIC RCODE chkSetupIxInfo( + DB_INFO * pDbInfo, + IX_CHK_INFO * pIxInfoRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiIxCount = 0; + FLMUINT uiIxNum = 0; + IXD * pIxd; + LFILE * pLFile; + char szTmpIoPath[F_PATH_MAX_SIZE]; + char szBaseName[F_FILENAME_SIZE]; + FDB * pDb = pDbInfo->pDb; + + f_memset( pIxInfoRV, 0, sizeof(IX_CHK_INFO)); + GedPoolInit( &(pIxInfoRV->pool), 512); + pIxInfoRV->pDbInfo = pDbInfo; + + // Set up the result set path + + if (RC_BAD( rc = flmGetTmpDir( szTmpIoPath))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) + { + if (RC_BAD( rc = f_pathReduce( pDb->pFile->pszDbPath, szTmpIoPath, + szBaseName))) + { + goto Exit; + } + } + else + { + goto Exit; + } + } + + // Initialize the result set. The result set will be used to build an + // ordered list of keys for comparision to the database's indexes. + + if (RC_BAD( rc = chkRSInit( szTmpIoPath, &(pIxInfoRV->pRSet)))) + { + goto Exit; + } + + // Build list of all indexes + + uiIxCount = 0; + if (pDb->pDict) + { + uiIxCount += pDb->pDict->uiIxdCnt; + } + + // Allocate memory to save each index number and its associated + // container number. + + if (RC_BAD( rc = f_alloc( (FLMUINT) ((sizeof(FLMUINT) * uiIxCount) + + (sizeof(FLMBOOL) * uiIxCount)), &(pIxInfoRV->puiIxArray)))) + { + goto Exit; + } + + // Save the index numbers into the array. + + uiIxCount = 0; + if (pDb->pDict) + { + for (uiIxNum = 0, pIxd = (IXD *) pDb->pDict->pIxdTbl; + uiIxNum < pDb->pDict->uiIxdCnt; + uiIxNum++, pIxd++) + { + pIxInfoRV->puiIxArray[uiIxCount] = pIxd->uiIndexNum; + uiIxCount++; + } + } + + if (RC_OK( fdictGetIndex( pDb->pDict, pDb->pFile->bInLimitedMode, + FLM_DICT_INDEX, &pLFile, NULL))) + { + pIxInfoRV->puiIxArray[uiIxCount] = FLM_DICT_INDEX; + uiIxCount++; + } + + pIxInfoRV->uiIxCount = uiIxCount; + pIxInfoRV->bGetNextRSKey = TRUE; + +Exit: + + // Clean up any memory on error exit. + + if (RC_BAD( rc)) + { + GedPoolFree( &(pIxInfoRV->pool)); + if (pIxInfoRV->puiIxArray) + { + f_free( &(pIxInfoRV->puiIxArray)); + } + } + + return (rc); +} + +/**************************************************************************** +Desc: Outputs keys to the temporary result set +****************************************************************************/ +FSTATIC RCODE chkOutputIndexKeys( + STATE_INFO * pStateInfo, + IX_CHK_INFO * pIxChkInfo, + IXD * pIxd, + REC_KEY * pKeyList) +{ + RCODE rc = FERR_OK; + FLMUINT uiKeyLen; + REC_KEY * pKey; + FLMBYTE ucBuf[MAX_KEY_SIZ + RS_KEY_OVERHEAD]; + + pKey = pKeyList; + while (pKey) + { + + // Set the index and reference + + UW2FBA( (FLMUINT16) pIxd->uiIndexNum, &(ucBuf[RS_IX_OFFSET])); + UD2FBA( (FLMUINT32) pStateInfo->uiElmDrn, &(ucBuf[RS_REF_OFFSET])); + + // Convert the key tree to a collation key + + if (RC_BAD( rc = KYTreeToKey( pIxChkInfo->pDbInfo->pDb, pIxd, pKey->pKey, + pKey->pKey->getContainerID(), &(ucBuf[RS_KEY_OVERHEAD]), + &uiKeyLen, 0))) + { + goto Exit; + } + + // Add the composite key (index, ref, key) to the result set + + if (RC_BAD( rc = chkRSAddEntry( pIxChkInfo->pRSet, ucBuf, + uiKeyLen + RS_KEY_OVERHEAD))) + { + goto Exit; + } + + // Update statistics. Note that uiNumKeys will reflect the total + // number of keys generated by records, including any duplicate + // keys. This value is updated to reflect the correct number of keys + // once the result set has been finalized. + + pIxChkInfo->pDbInfo->pProgress->ui64NumKeys++; + pKey = pKey->pNextKey; + } + +Exit: + + return (rc); +} diff --git a/flaim/src/flchkix.cpp b/flaim/src/flchkix.cpp deleted file mode 100644 index 234f5d4..0000000 --- a/flaim/src/flchkix.cpp +++ /dev/null @@ -1,2061 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Check database indexes for logical corruptions. -// Tabs: 3 -// -// Copyright (c) 1992,1994-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flchkix.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE chkVerifyTrackerCounts( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndexNum, - FLMUINT uiKeyCount, - FLMUINT uiRefCount); - -FSTATIC RCODE chkIsCountIndex( - STATE_INFO * pStateInfo, - FLMUINT uiIndexNum, - FLMBOOL * pbIsCountIndex); - -FSTATIC RCODE chkResolveRSetMissingKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIxRefDrn); - -FSTATIC RCODE chkVerifyDelNonUniqueRec( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiRecDrn, - FLMUINT * puiRecContainerRV, - FLMBOOL * pbDelRecRV); - -FSTATIC RCODE chkVerifyKeyExists( - FDB * pDb, - LFILE * pLFile, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiRefDrn, - FLMBOOL * pbFoundRV); - -FSTATIC RCODE chkAddDelKeyRef( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndexNum, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn, - FLMUINT uiFlags); - -FSTATIC RCODE chkGetKeySource( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn, - FLMUINT * puiRecordContainerRV, - FLMBOOL * pbKeyInRecRV, - FLMBOOL * pbKeyInIndexRV); - -FSTATIC RCODE chkReportIxError( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - eCorruptionType eCorruption, - FLMUINT uiErrIx, - FLMUINT uiErrDrn, - FLMBYTE * pucErrKey, - FLMUINT uiErrKeyLen, - FLMBOOL * pbFixErrRV); - -RCODE chkGetNextRSKey( - IX_CHK_INFO * pIxChkInfo); - -FSTATIC RCODE chkVerifyKeyNotUnique( - STATE_INFO * pStateInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT * puiRefCountRV); - -FSTATIC RCODE chkStartUpdate( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo); - -FSTATIC RCODE chkEndUpdate( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo); - -FLMINT chkRSCallbackFunc( - RSET_CB_INFO * pCBInfo); - -RCODE chkCompareIxRSEntries( - void * vpData1, - FLMUINT uiLength1, - void * vpData2, - FLMUINT uiLength2, - void * UserValue, - FLMINT * piCompare); - - -/**************************************************************************** -Desc: -****************************************************************************/ -FINLINE RCODE chkRSGetNext( - void * pRSet, - FLMBYTE * pBuffer, - FLMUINT uiBufferLength, - FLMUINT * puiReturnLength) -{ - FLMUINT uiReturnLen; - RCODE rc; - - rc = ((FResultSet *)pRSet)->GetNext( (void *)pBuffer, - uiBufferLength, &uiReturnLen); - *puiReturnLength = (rc == FERR_OK) ? uiReturnLen : 0; - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -FINLINE RCODE chkKeyToTree( - IXD * pIxd, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FlmRecord ** ppKeyRV) -{ - return flmIxKeyOutput( pIxd, pucKey, uiKeyLen, ppKeyRV, FALSE); -} - -/******************************************************************** -Desc: Verifies the key and reference counts against the counts that - are stored in the tracker record. -*********************************************************************/ -FSTATIC RCODE chkVerifyTrackerCounts( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndexNum, - FLMUINT uiKeyCount, - FLMUINT uiRefCount - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = pStateInfo->pDb; - FlmRecord * pRecord = NULL; - eCorruptionType eCorruption; - FLMUINT uiTrackerKeyCount = 0; - FLMUINT uiTrackerRefCount = 0; - void * pvField; - - // Retrieve the tracker record from record cache. - - if (RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, FLM_TRACKER_CONTAINER, - uiIndexNum, TRUE, NULL, NULL, &pRecord))) - { - if (rc != FERR_NOT_FOUND) - { - goto Exit; - } - rc = FERR_OK; - } - else - { - if ((pvField = pRecord->find( pRecord->root(), FLM_KEY_TAG)) != NULL) - { - if (RC_BAD( rc = pRecord->getUINT( pvField, &uiTrackerKeyCount))) - { - goto Exit; - } - } - if ((pvField = pRecord->find( pRecord->root(), FLM_REFS_TAG)) != NULL) - { - if (RC_BAD( rc = pRecord->getUINT( pvField, &uiTrackerRefCount))) - { - goto Exit; - } - } - } - - // See if the counts match what we got from the tracker record. - - if (uiKeyCount != uiTrackerKeyCount || uiRefCount != uiTrackerRefCount) - { - - // Log an error. - - eCorruption = (eCorruptionType)((uiKeyCount != uiTrackerKeyCount) - ? FLM_KEY_COUNT_MISMATCH - : FLM_REF_COUNT_MISMATCH); - - if (RC_BAD( rc = chkReportError( pIxChkInfo->pDbInfo, eCorruption, - LOCALE_INDEX, uiIndexNum, LF_INDEX, - 0xFF, 0, 0, 0, 0, 0xFFFF, 0, NULL))) - { - goto Exit; - } - } -Exit: - if (pRecord) - { - pRecord->Release(); - } - return( rc); -} - -/******************************************************************** -Desc: Determine if an index is an index that keeps key and reference - counts. -*********************************************************************/ -FSTATIC RCODE chkIsCountIndex( - STATE_INFO * pStateInfo, - FLMUINT uiIndexNum, - FLMBOOL * pbIsCountIndex - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = pStateInfo->pDb; - IXD * pIxd; - - if( RC_BAD( rc = fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, uiIndexNum, - NULL, &pIxd, TRUE))) - { - goto Exit; - } - *pbIsCountIndex = (FLMBOOL)((pIxd->uiFlags & IXD_COUNT) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); -Exit: - return( rc); -} - -/******************************************************************** -Desc: Verifies the current index key against the result set. -*********************************************************************/ -RCODE chkVerifyIXRSet( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIxRefDrn - ) -{ - FLMINT iCmpVal = 0; - FLMUINT uiIteration = 0; - FLMBOOL bRSetEmpty = FALSE; - RCODE rc = FERR_OK; - RS_IX_KEY * pCurrRSKey; - RS_IX_KEY * pPrevRSKey; - - if (!pIxChkInfo->pCurrRSKey) - { - pIxChkInfo->pCurrRSKey = &pIxChkInfo->IxKey1; - pIxChkInfo->pPrevRSKey = &pIxChkInfo->IxKey2; - } - - /* Compare index and result set keys */ - - while( !bRSetEmpty) - { - if( pIxChkInfo->bGetNextRSKey) - { - /* - Get the next key from the result set. If the result set - is empty, then pIxChkInfo->uiRSKeyLen will be set to - zero, forcing the problem to be resolved below. - */ - - if( RC_BAD( rc = chkGetNextRSKey( pIxChkInfo))) - { - if( rc == FERR_EOF_HIT || rc == FERR_NOT_FOUND) - { - /* - Set bRSetEmpty to TRUE so that the loop will exit after the - current key is resolved. Otherwise, conflict resolution on - the current key will be repeated forever (infinite loop). - */ - - bRSetEmpty = TRUE; - rc = FERR_OK; - } - else - { - goto Exit; - } - } - else - { - /* Updated statistics */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumKeysExamined++; - } - } - pCurrRSKey = pIxChkInfo->pCurrRSKey; - pPrevRSKey = pIxChkInfo->pPrevRSKey; - - if( pCurrRSKey->uiRSKeyLen == 0 || bRSetEmpty) - { - /* - We don't have a key because we got an EOF when - reading the result set. Need to resolve the - fact that the result set does not have a key - that is found in the index. Set iCmpVal to - 1 to force this resolution. - */ - - iCmpVal = 1; - } - else - { - /* - Compare the index key and result set key. - */ - - iCmpVal = chkCompareKeySet( - pCurrRSKey->uiRSIxNum, - &(pCurrRSKey->pucRSKeyBuf[ RS_KEY_OFFSET]), - pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD, - pCurrRSKey->uiRSRefDrn, - pStateInfo->pLogicalFile->pLFile->uiLfNum, - pStateInfo->pCurKey, - pStateInfo->uiCurKeyLen, - uiIxRefDrn); - } - - if( iCmpVal < 0) - { - - // If a comparison is done where the keys from the result set - // don't match what we got from the index, we will forego verifying - // the tracker counts. Verifying of tracker counts can only - // occur if we have an otherwise clean check of the index keys. - - pIxChkInfo->bCheckCounts = FALSE; - - /* - The result set key is less than the index key. This could mean - that the result set key needs to be added to the index. - */ - - if(( RC_BAD( rc = chkResolveIXMissingKey( pStateInfo, - pIxChkInfo))) || - (pIxChkInfo->pDbInfo->bReposition)) - { - /* - If the key was added to the index (bReposition == TRUE) - or we got some other error, we don't want to get the next - result set key. - */ - - pIxChkInfo->bGetNextRSKey = FALSE; - goto Exit; - } - else - { - /* - False alarm. The index is missing the key because of - a concurrent update. We want to get the next RS key. - */ - - pIxChkInfo->bGetNextRSKey = TRUE; - } - } - else if( iCmpVal > 0) - { - - // If a comparison is done where the keys from the result set - // don't match what we got from the index, we will forego verifying - // the tracker counts. Verifying of tracker counts can only - // occur if we have an otherwise clean check of the index keys. - - pIxChkInfo->bCheckCounts = FALSE; - - /* - The result set key is greater than the index key. This could mean - that the index key needs to be deleted from the index. Whether we - delete the index key or not, we don't need to get the next result - set key, but we do want to reposition and get the next index key. - */ - - pIxChkInfo->bGetNextRSKey = FALSE; - if(( RC_BAD( rc = chkResolveRSetMissingKey( pStateInfo, - pIxChkInfo, uiIxRefDrn))) || - (pIxChkInfo->pDbInfo->bReposition)) - { - goto Exit; - } - break; - } - else - { - - /* - The index and result set keys are equal. We want to get - the next result set and index keys. - */ - - pIxChkInfo->bGetNextRSKey = TRUE; - - // Determine if we have switched indexes. If so, verify the key - // and reference counts against the counts in the tracker record. - - if (pCurrRSKey->uiRSIxNum != pPrevRSKey->uiRSIxNum) - { - if (pIxChkInfo->bCheckCounts) - { - - // Verify the key and reference counts against tracker record. - - if (RC_BAD( rc = chkVerifyTrackerCounts( pStateInfo, - pIxChkInfo, - pPrevRSKey->uiRSIxNum, - pIxChkInfo->uiRSIxKeyCount, - pIxChkInfo->uiRSIxRefCount))) - { - goto Exit; - } - } - - // Determine if the new index is one that supports counts. - - if (RC_BAD( rc = chkIsCountIndex( pStateInfo, - pCurrRSKey->uiRSIxNum, - &pIxChkInfo->bCheckCounts))) - { - goto Exit; - } - if (pIxChkInfo->bCheckCounts) - { - - // Set the counts to one. - - pIxChkInfo->uiRSIxKeyCount = 1; - pIxChkInfo->uiRSIxRefCount = 1; - } - } - else - { - if (pIxChkInfo->bCheckCounts) - { - - // Always increment the reference count. - - pIxChkInfo->uiRSIxRefCount++; - - // See if the key changed. - - if (pCurrRSKey->uiRSKeyLen != - pPrevRSKey->uiRSKeyLen || - (pCurrRSKey->uiRSKeyLen > RS_KEY_OFFSET && - f_memcmp( &pCurrRSKey->pucRSKeyBuf [RS_KEY_OFFSET], - &pPrevRSKey->pucRSKeyBuf [RS_KEY_OFFSET], - pCurrRSKey->uiRSKeyLen - RS_KEY_OFFSET) != 0)) - { - pIxChkInfo->uiRSIxKeyCount++; - } - else - { - - // If the keys are the same, at least the DRNs better - // be different. - - flmAssert( pCurrRSKey->uiRSRefDrn != - pPrevRSKey->uiRSRefDrn); - } - } - } - break; - } - - /* Call the yield function periodically */ - - uiIteration++; - if( !(uiIteration & 0x1F) ) - { - f_yieldCPU(); - } - } - -Exit: - - return( rc); -} - - -/******************************************************************** -Desc: Retrieves the next key from the sorted result set -*********************************************************************/ -RCODE chkGetNextRSKey( - IX_CHK_INFO * pIxChkInfo - ) -{ - RCODE rc = FERR_OK; - RS_IX_KEY * pCurrRSKey; - - // Swap current and last key pointers - this allows us to always keep - // the last key without having to memcpy the keys. - - pCurrRSKey = pIxChkInfo->pCurrRSKey; - pIxChkInfo->pCurrRSKey = pIxChkInfo->pPrevRSKey; - pIxChkInfo->pPrevRSKey = pCurrRSKey; - pCurrRSKey = pIxChkInfo->pCurrRSKey; - - /* Get the next key */ - - if( RC_BAD( rc = chkRSGetNext( pIxChkInfo->pRSet, - pCurrRSKey->pucRSKeyBuf, - MAX_KEY_SIZ + RS_KEY_OVERHEAD, - &(pCurrRSKey->uiRSKeyLen)))) - { - goto Exit; - } - - /* Verify that the key meets the minimum length requirements */ - - flmAssert( pCurrRSKey->uiRSKeyLen >= RS_KEY_OVERHEAD); - - /* Extract the index number and reference DRN */ - - pCurrRSKey->uiRSIxNum = - (FLMUINT)FB2UW( &(pCurrRSKey->pucRSKeyBuf[ RS_IX_OFFSET])); - pCurrRSKey->uiRSRefDrn = - (FLMUINT)FB2UD( &(pCurrRSKey->pucRSKeyBuf[ RS_REF_OFFSET])); - -Exit: - - return( rc); - -} - -/******************************************************************** -Desc: Resolves the case of a key found in the result set but not in - the current index. -*********************************************************************/ -RCODE - chkResolveIXMissingKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo - ) -{ - FLMBOOL bKeyInRec; - FLMBOOL bKeyInIndex; - RCODE rc = FERR_OK; - FLMBOOL bFixCorruption = FALSE; - RS_IX_KEY * pCurrRSKey = pIxChkInfo->pCurrRSKey; - - /* - Determine if the record generates the key and if the - key is found in the index. - */ - - if( RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, - pCurrRSKey->uiRSIxNum, &(pCurrRSKey->pucRSKeyBuf[ RS_KEY_OFFSET]), - (FLMUINT)(pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), - pCurrRSKey->uiRSRefDrn, NULL, - &bKeyInRec, &bKeyInIndex))) - { - if( rc == FERR_INDEX_OFFLINE) - { - rc = FERR_OK; - } - goto Exit; - } - - /* - If the record does not generate the key or the key+ref is in the index, - the index is not corrupt. - */ - - if( !bKeyInRec || bKeyInIndex) - { - pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; - goto Exit; - } - - /* - Otherwise, the index is corrupt. - */ - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumRecKeysNotFound++; - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; - - /* Report the error */ - - if( RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, - FLM_DRN_NOT_IN_KEY_REFSET, pCurrRSKey->uiRSIxNum, - pCurrRSKey->uiRSRefDrn, - &(pCurrRSKey->pucRSKeyBuf[ RS_KEY_OFFSET]), - (FLMUINT)(pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), - &bFixCorruption))) - { - goto Exit; - } - - /* - Exit if the application does not want to repair the corruption. - */ - - if( !bFixCorruption) - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - goto Exit; - } - - /* Fix the corruption */ - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; - - /* Add the key. */ - - if( RC_OK( rc = chkAddDelKeyRef( - pStateInfo, pIxChkInfo, pCurrRSKey->uiRSIxNum, - &(pCurrRSKey->pucRSKeyBuf[ RS_KEY_OFFSET]), - (FLMUINT)(pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), - pCurrRSKey->uiRSRefDrn, 0))) - { - pIxChkInfo->pDbInfo->bReposition = TRUE; - goto Exit; - } - else - { - if( rc == FERR_NOT_UNIQUE) - { - /* - A subsequent record probably also generates this key, - but the index is a unique index so we were not allowed - to add the missing key + ref to the index. This record - should probably be deleted. - */ - - if( RC_OK( rc = chkResolveNonUniqueKey( pStateInfo, - pIxChkInfo, pCurrRSKey->uiRSIxNum, - &(pCurrRSKey->pucRSKeyBuf[ RS_KEY_OFFSET]), - (FLMUINT)(pCurrRSKey->uiRSKeyLen - RS_KEY_OVERHEAD), - pCurrRSKey->uiRSRefDrn))) - { - pIxChkInfo->pDbInfo->bReposition = TRUE; - goto Exit; - } - } - else - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - } - } - -Exit: - - return( rc); -} - - -/******************************************************************** -Desc: Resolves the case of a key found in the current index but not - in the result set. -*********************************************************************/ -FSTATIC RCODE - chkResolveRSetMissingKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIxRefDrn - ) -{ - FLMBOOL bKeyInRec; - FLMBOOL bKeyInIndex; - RCODE rc = FERR_OK; - FLMBOOL bFixCorruption = FALSE; - - /* - See if the key is found in the index and/or generated - by the record. - */ - - if( RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, - pStateInfo->pLogicalFile->pLFile->uiLfNum, - pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, - uiIxRefDrn, NULL, &bKeyInRec, &bKeyInIndex))) - { - if( rc == FERR_INDEX_OFFLINE) - { - rc = FERR_OK; - } - goto Exit; - } - - /* - If the key is generated by the record or the key is not found - in the index, the index is not corrupt. - */ - - if( bKeyInRec || !bKeyInIndex) - { - pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; - goto Exit; - } - - /* - Otherwise, the index is corrupt. - */ - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumKeysNotFound++; - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; - - /* Report the error */ - - if( RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, - FLM_IX_KEY_NOT_FOUND_IN_REC, - pStateInfo->pLogicalFile->pLFile->uiLfNum, uiIxRefDrn, - pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, - &bFixCorruption))) - { - goto Exit; - } - - /* - Exit if the application does not want to repair the corruption. - */ - - if( !bFixCorruption) - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - goto Exit; - } - - /* Fix the corruption */ - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; - - /* Delete the reference from the index */ - - if( RC_OK( rc = chkAddDelKeyRef( - pStateInfo, pIxChkInfo, - pStateInfo->pLogicalFile->pLFile->uiLfNum, - pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, - uiIxRefDrn, KREF_DELETE_FLAG))) - { - pIxChkInfo->pDbInfo->bReposition = TRUE; - } - else - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - } - -Exit: - - return( rc); -} - - -/******************************************************************** -Desc: Resolves the case of multiple references associated with a - key in a unique index. -*********************************************************************/ -RCODE - chkResolveNonUniqueKey( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn - ) -{ - FDB * pDb = pStateInfo->pDb; - LFILE * pRecLFile = NULL; - FLMBOOL bDeleteRec = FALSE; - FLMUINT uiRecContainer; - RCODE rc = FERR_OK; - RCODE rc2 = FERR_OK; - FLMBOOL bFixCorruption = FALSE; - FlmRecord * pOldRecord = NULL; - - /* - Verify that the record violates the constraints of the unique - index and should be deleted. - */ - - if( RC_BAD( rc = chkVerifyDelNonUniqueRec( pStateInfo, pIxChkInfo, - uiIndex, pucKey, uiKeyLen, uiDrn, &uiRecContainer, &bDeleteRec))) - { - goto Exit; - } - - if( bDeleteRec) - { - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumNonUniqueKeys++; - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexCorruptions++; - - /* Report the error */ - - if( RC_BAD( rc = chkReportIxError( pStateInfo, pIxChkInfo, - FLM_NON_UNIQUE_ELM_KEY_REF, uiIndex, uiDrn, - pucKey, uiKeyLen, &bFixCorruption))) - { - goto Exit; - } - - if( !bFixCorruption) - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - goto Exit; - } - - /* - Delete the record that generated the non-unique - reference. - */ - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->uiLogicalIndexRepairs++; - - /* - Start an update transaction, if necessary. - */ - - if( RC_BAD( rc = chkStartUpdate( pStateInfo, pIxChkInfo))) - { - goto Exit; - } - - /* - Re-verify that the record should be deleted. - */ - - if( RC_BAD( rc = chkVerifyDelNonUniqueRec( pStateInfo, pIxChkInfo, - uiIndex, pucKey, uiKeyLen, uiDrn, &uiRecContainer, &bDeleteRec))) - { - goto Exit; - } - - if( bDeleteRec == TRUE) - { - void * pvMark; - - /* - Mark the DB's temporary pool. - */ - - pvMark = GedPoolMark( &(pDb->TempPool)); - - /* - Call the internal delete function, passing boolean flags - indicating that missing keys should not prevent the - record deletion and that the record validator callback - should not be called. - */ - - if( RC_BAD( rc = fdictGetContainer( pDb->pDict, - uiRecContainer, &pRecLFile))) - { - goto Exit; - } - - rc = flmDeleteRecord( pDb, pRecLFile, - uiDrn, &pOldRecord, TRUE); - - if (gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) - { - flmUpdEventCallback( pDb, - F_EVENT_DELETE_RECORD, (HFDB)pDb, rc, uiDrn, - uiRecContainer, NULL, pOldRecord); - } - - /* - Reset the DB's temporary pool. The flmDeleteRecord - call allocates space for the record that is being deleted. - */ - - GedPoolReset( &(pDb->TempPool), pvMark); - - if( RC_BAD( rc)) - { - /* - If the record had already been deleted, continue the - check without reporting the error. - */ - if( rc == FERR_NOT_FOUND) - { - rc = FERR_OK; - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; - } - else - { - /* Set the logical corruption flag */ - pIxChkInfo->pDbInfo->pProgress->bLogicalIndexCorrupt = TRUE; - } - goto Exit; - } - - /* Update statistics */ - - pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; - } - } - else - { - /* Increment the conflict counter */ - pIxChkInfo->pDbInfo->pProgress->ui64NumConflicts++; - } - -Exit: - - /* - End the update. chkEndUpdate will be a no-op if an update - transaction was not started. - */ - - rc2 = chkEndUpdate( pStateInfo, pIxChkInfo); - - if( pOldRecord) - { - pOldRecord->Release(); - } - - return( (RCODE)((rc != FERR_OK) ? (RCODE)rc : (RCODE)rc2)); -} - - -/******************************************************************** -Desc: Verifies that the specified record should be deleted because it - generates key(s) which violate the constraints of a unique - index. -*********************************************************************/ -FSTATIC RCODE chkVerifyDelNonUniqueRec( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiRecDrn, - FLMUINT * puiRecContainerRV, - FLMBOOL * pbDelRecRV - ) -{ - FLMBOOL bKeyInRec; - FLMBOOL bRecRefdByKey; - FLMUINT uiRefCount; - FLMUINT uiRecContainer; - RCODE rc = FERR_OK; - - *pbDelRecRV = FALSE; - *puiRecContainerRV = 0; - - /* - See if the key is found in the index and/or generated - by the record. - */ - - if( RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, - uiIndex, pucKey, uiKeyLen, uiRecDrn, - &uiRecContainer, &bKeyInRec, &bRecRefdByKey))) - { - if( rc == FERR_INDEX_OFFLINE) - { - rc = FERR_OK; - } - goto Exit; - } - - *puiRecContainerRV = uiRecContainer; - - if( bKeyInRec == TRUE) - { - /* Verify that the key is not unique */ - - if( RC_BAD( rc = chkVerifyKeyNotUnique( - pStateInfo, uiIndex, pucKey, - uiKeyLen, &uiRefCount))) - { - goto Exit; - } - - if( uiRefCount > 1) - { - /* - The unique index has multiple references for the - specified key. Since the current record generates - a non-unique key, it should be deleted even if - it is not one of the records referenced by the - key. Of course, if it is already referenced by - the key, deleting the record will reduce the - number of references associated with the key - by one. - */ - - *pbDelRecRV = TRUE; - } - else if( uiRefCount == 1 && bRecRefdByKey == FALSE) - { - /* - The unique index already has a key corresponding - to the key being generated by the current record. - However, the record is not referenced from the - unique index. The record should still be - deleted since it generates a non-unique key. - */ - - *pbDelRecRV = TRUE; - } - } - -Exit: - - return( rc); -} - - -/******************************************************************** -Desc: Determines if a key is generated by the current record - and/or if the key is found in the current index -*********************************************************************/ -FSTATIC RCODE chkGetKeySource( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn, - FLMUINT * puiRecordContainerRV, - FLMBOOL * pbKeyInRecRV, - FLMBOOL * pbKeyInIndexRV - ) -{ - FlmRecord * pRecord = NULL; - FDB * pDb = pStateInfo->pDb; - LFILE * pLFile; - LFILE * pIxLFile; - REC_KEY * pKeys = NULL; - REC_KEY * pTempKey = NULL; - IXD * pIxd; - FLMBYTE ucRecKeyBuf[ MAX_KEY_SIZ]; - FLMUINT uiRecKeyLen; - FLMUINT uiKeyCount; - FLMBOOL bResetKRef = FALSE; - void * pIxPoolMark; - void * pDbPoolMark; - FLMUINT uiContainerNum; - RCODE rc = FERR_OK; - - /* - Initialize return values. - */ - - *pbKeyInRecRV = FALSE; - *pbKeyInIndexRV = FALSE; - - if( puiRecordContainerRV) - { - *puiRecordContainerRV = 0; - } - - /* Initialize variables */ - - pIxPoolMark = GedPoolMark( &(pIxChkInfo->pool)); - - /* - Need to mark the DB's temporary pool. The index code allocates - memory for new CDL entries from the DB pool. If the pool is not - reset, it grows during the check and becomes VERY large. - */ - - pDbPoolMark = GedPoolMark( &(pDb->TempPool)); - - - /* Set up the KRef so that flmGetRecKeys will work */ - - if( RC_BAD( rc = KrefCntrlCheck( pDb))) - { - goto Exit; - } - bResetKRef = TRUE; - - /* Get the LFile and IXD of the index */ - - if( RC_BAD( rc = fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, uiIndex, - &pIxLFile, &pIxd))) - { - // Return FERR_INDEX_OFFLINE error. - goto Exit; - } - - if ((uiContainerNum = pIxd->uiContainerNum) == 0) - { - - // Container number is always the last two bytes of the key. - - flmAssert( uiKeyLen > getIxContainerPartLen( pIxd)); - uiContainerNum = getContainerFromKey( pucKey, uiKeyLen); - } - - // Get the LFile of the record that caused the error - - if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainerNum, &pLFile))) - { - goto Exit; - } - - // Set the record container return value - - if( puiRecordContainerRV) - { - *puiRecordContainerRV = uiContainerNum; - } - - /* See if the key is in the index. */ - - if( RC_BAD( rc = chkVerifyKeyExists( pDb, - pIxLFile, pucKey, uiKeyLen, uiDrn, pbKeyInIndexRV))) - { - goto Exit; - } - - /* Read the record */ - - if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, - pLFile->uiLfNum, uiDrn, FALSE, NULL, NULL, &pRecord))) - { - if (rc != FERR_NOT_FOUND) - goto Exit; - - // NOTE: Deliberately not bringing in to cache if not found there. - - if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiDrn, - &pRecord, NULL, NULL))) - { - if( rc == FERR_NOT_FOUND) - { - *pbKeyInRecRV = FALSE; - rc = FERR_OK; - } - else - { - goto Exit; - } - } - } - - if( pRecord) - { - /* Generate record keys */ - - if (RC_BAD( rc = flmGetRecKeys( pDb, pIxd, pRecord, - pRecord->getContainerID(), - TRUE, &(pIxChkInfo->pool), &pKeys))) - { - goto Exit; - } - - uiKeyCount = 0; - pTempKey = pKeys; - while( pTempKey != NULL) - { - /* Build the collated keys for each key tree. */ - - if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, - pTempKey->pKey, pTempKey->pKey->getContainerID(), - ucRecKeyBuf, &uiRecKeyLen, 0))) - { - goto Exit; - } - - if( KYKeyCompare( pucKey, uiKeyLen, - ucRecKeyBuf, uiRecKeyLen) == BT_EQ_KEY) - { - *pbKeyInRecRV = TRUE; - break; - } - pTempKey = pTempKey->pNextKey; - uiKeyCount++; - - /* - Release the CPU periodically to prevent CPU hog - problems. - */ - - f_yieldCPU(); - } - } - -Exit: - - if (pKeys) - { - pTempKey = pKeys; - while (pTempKey) - { - pTempKey->pKey->Release(); - pTempKey = pTempKey->pNextKey; - } - } - - if( pRecord) - { - pRecord->Release(); - } - - // Remove any keys added to the KRef - - if (bResetKRef) - { - KYAbortCurrentRecord( pDb); - } - - // Reset the DB's temporary pool - - GedPoolReset( &(pDb->TempPool), pDbPoolMark); - - // Reset the index check pool - - GedPoolReset( &(pIxChkInfo->pool), pIxPoolMark); - - return( rc); -} - - -/******************************************************************** -Desc: Verify that a key is (or is not) found in an index. -*********************************************************************/ -FSTATIC RCODE chkVerifyKeyExists( - FDB * pDb, - LFILE * pLFile, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiRefDrn, - FLMBOOL * pbFoundRV) -{ - RCODE rc = FERR_OK; /* Return code */ - BTSK stackBuf[ BH_MAX_LEVELS ]; /* Stack to hold b-tree variables */ - BTSK * stack = stackBuf; /* Points to proper stack frame */ - FLMUINT uiDinDomain = DIN_DOMAIN( uiRefDrn) + 1; /* Lower bounds */ - FLMBYTE ucBtKeyBuf[ MAX_KEY_SIZ ]; /* Key buffer pointed to by stack */ - DIN_STATE dinState; - FLMUINT uiTmpDrn; - - *pbFoundRV = FALSE; - f_memset( &dinState, 0, sizeof( DIN_STATE)); - - /* Initialize stack cache. */ - - FSInitStackCache( &(stackBuf[ 0]), BH_MAX_LEVELS); - stack = stackBuf; - stack->pKeyBuf = ucBtKeyBuf; - - /* Search for the key. */ - - if( RC_BAD( rc = FSBtSearch( pDb, - pLFile, &stack, pucKey, uiKeyLen, uiDinDomain))) - { - goto Exit; - } - - if( stack->uiCmpStatus == BT_EQ_KEY) - { - uiTmpDrn = uiRefDrn; - - /* Reading the current element, position to or after uiTmpDrn */ - rc = FSRefSearch( stack, &dinState, &uiTmpDrn); - - /* If the entry was not found, returns FERR_FAILURE */ - - if( rc == FERR_OK) - { - *pbFoundRV = TRUE; - } - else if( rc != FERR_FAILURE) - { - goto Exit; - } - else /* rc == FERR_FAILURE */ - { - rc = FERR_OK; - } - } - -Exit: - - /* Free the stack cache */ - - FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); - return( rc ); -} - - -/******************************************************************** -Desc: Compares a composite key (index, ref, key) for equality. -Note: Since index references are sorted in decending order, a - composite key with a lower ref DRN will sort after a key - with a higher ref DRN. -*********************************************************************/ -FLMINT - chkCompareKeySet( - FLMUINT uiIxNum1, - FLMBYTE * pData1, - FLMUINT uiLength1, - FLMUINT uiDrn1, - FLMUINT uiIxNum2, - FLMBYTE * pData2, - FLMUINT uiLength2, - FLMUINT uiDrn2 - ) -{ - FLMINT iCmpVal = RS_EQUALS; - FLMUINT uiMinLen; - - - /* Compare index numbers */ - - if( uiIxNum1 > uiIxNum2) - { - iCmpVal = RS_GREATER_THAN; - goto Exit; - } - else if( uiIxNum1 < uiIxNum2) - { - iCmpVal = RS_LESS_THAN; - goto Exit; - } - - /* Compare keys */ - - uiMinLen = (FLMUINT)(uiLength1 < uiLength2) ? uiLength1 : uiLength2; - iCmpVal = f_memcmp( pData1, pData2, uiMinLen); - if( iCmpVal == 0) - { - /* Compare references */ - - if( uiLength1 == uiLength2) - { - /* - A key with a lower ref DRN will sort after a key - with a higher ref DRN. - */ - - if( uiDrn1 > uiDrn2) - { - iCmpVal = RS_LESS_THAN; - } - else if( uiDrn1 < uiDrn2) - { - iCmpVal = RS_GREATER_THAN; - } - else - { - iCmpVal = RS_EQUALS; - goto Exit; - } - } - else if( uiLength1 > uiLength2) - { - iCmpVal = RS_GREATER_THAN; - } - else - { - iCmpVal = RS_LESS_THAN; - } - } - else - { - iCmpVal = (FLMINT)((iCmpVal > 0) - ? (FLMINT)RS_GREATER_THAN - : (FLMINT)RS_LESS_THAN); - } - -Exit: - - return( iCmpVal); -} - - -/*************************************************************************** -Desc: This routine adds or deletes an index key and/or reference. -*****************************************************************************/ -FSTATIC RCODE - chkAddDelKeyRef( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - FLMUINT uiIndexNum, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT uiDrn, - FLMUINT uiFlags - ) -{ - RCODE rc = FERR_OK; - RCODE rc2 = FERR_OK; - FLMBYTE ucKeyBuf[ sizeof( KREF_ENTRY) + MAX_KEY_SIZ]; - KREF_ENTRY * pKrefEntry = (KREF_ENTRY *)(&ucKeyBuf[ 0]); - IXD * pIxd; - LFILE * pLFile; - FLMBOOL bStartedUpdate = FALSE; - FLMBOOL bKeyInRec; - FLMBOOL bKeyInIndex; - - - /* Start an update transaction, if necessary */ - - if( RC_BAD( rc = chkStartUpdate( pStateInfo, pIxChkInfo))) - { - goto Exit; - } - bStartedUpdate = TRUE; - - /* Look up the LFILE and IXD for the index. */ - - if( RC_BAD( rc = fdictGetIndex( pStateInfo->pDb->pDict, - pStateInfo->pDb->pFile->bInLimitedMode, uiIndexNum, - &pLFile, &pIxd))) - { - // Shouldn't get FERR_INDEX_OFFLINE in here. - goto Exit; - } - - /* Verify that the state has not changed */ - - if( RC_BAD( rc = chkGetKeySource( pStateInfo, pIxChkInfo, - uiIndexNum, pucKey, uiKeyLen, uiDrn, NULL, - &bKeyInRec, &bKeyInIndex))) - { - goto Exit; - } - - if( (bKeyInIndex == TRUE && ((uiFlags & KREF_DELETE_FLAG) != 0)) || - (bKeyInIndex == FALSE && uiFlags == 0)) - { - - /* Setup the KrefEntry structure */ - - flmAssert( uiIndexNum > 0 && uiIndexNum < FLM_UNREGISTERED_TAGS); // Sanity check - f_memcpy( &(ucKeyBuf[ sizeof( KREF_ENTRY)]), pucKey, uiKeyLen); - pKrefEntry->ui16KeyLen = (FLMUINT16)uiKeyLen; - pKrefEntry->ui16IxNum = (FLMUINT16)uiIndexNum; - pKrefEntry->uiDrn = uiDrn; - pKrefEntry->uiTrnsSeq = 1; - pKrefEntry->uiFlags = uiFlags; - - if( (pIxd->uiFlags & IXD_UNIQUE) != 0) - { - /* - Do not allow duplicate keys to be added to a unique index. - */ - pKrefEntry->uiFlags |= KREF_UNIQUE_KEY; - } - - /* Add or delete the key/reference. */ - - if( RC_BAD( rc = FSRefUpdate( pStateInfo->pDb, pLFile, pKrefEntry))) - { - goto Exit; - } - - /* Update statistics */ - pIxChkInfo->pDbInfo->pProgress->uiNumProblemsFixed++; - } - -Exit: - - /* End the update. */ - - if( bStartedUpdate == TRUE) - { - if( RC_BAD( rc2 = chkEndUpdate( pStateInfo, pIxChkInfo))) - { - goto Exit; - } - } - - rc = (RCODE)((rc != FERR_OK) ? (RCODE)rc : (RCODE)rc2); - - return( rc); -} - -/******************************************************************** -Desc: Populates the CORRUPT_INFO structure and calls the user's - callback routine. -*********************************************************************/ -FSTATIC RCODE chkReportIxError( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - eCorruptionType eCorruption, - FLMUINT uiErrIx, - FLMUINT uiErrDrn, - FLMBYTE * pucErrKey, - FLMUINT uiErrKeyLen, - FLMBOOL * pbFixErrRV - ) -{ - FDB * pDb = pStateInfo->pDb; - POOL * pTmpPool; - IXD * pIxd; - LFILE * pLFile; - void * pIxPoolMark; - void * pDbPoolMark = NULL; - FLMBOOL bResetKRef = FALSE; - RCODE rc = FERR_OK; - CORRUPT_INFO CorruptInfo; - FLMUINT uiContainerNum; - - f_memset( &CorruptInfo, 0, sizeof( CORRUPT_INFO)); - - // Mark the index check pool - - pIxPoolMark = GedPoolMark( &(pIxChkInfo->pool)); - pTmpPool = &(pIxChkInfo->pool); - - // Need to mark the DB's temporary pool. The index code allocates - // memory for new CDL entries from the DB pool. If the pool is not - // reset, it grows during the check and becomes VERY large. - - pDbPoolMark = GedPoolMark( &(pDb->TempPool)); - - // Set up the KRef so that flmGetRecKeys will work - - if( RC_BAD( rc = KrefCntrlCheck( pDb))) - { - goto Exit; - } - bResetKRef = TRUE; - - // Report the error - - CorruptInfo.eErrLocale = LOCALE_INDEX; - CorruptInfo.eCorruption = eCorruption; - CorruptInfo.uiErrLfNumber = uiErrIx; - CorruptInfo.uiErrDrn = uiErrDrn; - CorruptInfo.uiErrElmOffset = pStateInfo->uiElmOffset; - - if (RC_BAD( rc = fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, uiErrIx, - NULL, &pIxd, TRUE))) - { - goto Exit; - } - - /* Generate the key tree using the key that caused the error */ - - if( RC_BAD( rc = chkKeyToTree( pIxd, pucErrKey, uiErrKeyLen, - &(CorruptInfo.pErrIxKey)))) - { - goto Exit; - } - - /* Get the LFile */ - - if ((uiContainerNum = pIxd->uiContainerNum) == 0) - { - - // Container number is always the last two bytes of the key. - - flmAssert( uiErrKeyLen > getIxContainerPartLen( pIxd)); - uiContainerNum = getContainerFromKey( pucErrKey, uiErrKeyLen); - } - - /* Get the LFile */ - - if( RC_BAD( rc = fdictGetContainer( pDb->pDict, uiContainerNum, &pLFile))) - { - goto Exit; - } - - /* Read the record */ - - if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, - pLFile->uiLfNum, uiErrDrn, FALSE, NULL, NULL, &(CorruptInfo.pErrRecord)))) - { - if (rc != FERR_NOT_FOUND) - goto Check_Error; - - // NOTE: Deliberately not bringing in to cache if not found there. - - if( RC_BAD( rc = FSReadRecord( pDb, pLFile, uiErrDrn, - &(CorruptInfo.pErrRecord), NULL, NULL))) - { -Check_Error: - /* - Record may have been deleted or cannot be returned - because of an old view error. - */ - - if( rc == FERR_NOT_FOUND) - { - rc = FERR_OK; - } - else if( FlmErrorIsFileCorrupt( rc)) - { - pIxChkInfo->pDbInfo->pProgress->bPhysicalCorrupt = TRUE; - rc = FERR_OK; - goto Exit; - } - else - { - goto Exit; - } - } - } - - /* Generate index keys for the current index and record */ - - if( CorruptInfo.pErrRecord != NULL) - { - if (RC_BAD( rc = flmGetRecKeys( pDb, pIxd, - CorruptInfo.pErrRecord, - CorruptInfo.pErrRecord->getContainerID(), - TRUE, pTmpPool, - &(CorruptInfo.pErrRecordKeyList)))) - { - goto Exit; - } - } - - *pbFixErrRV = FALSE; - if ((pIxChkInfo->pDbInfo->fnStatusFunc) && - (RC_OK( pIxChkInfo->pDbInfo->LastStatusRc))) - { - pIxChkInfo->pDbInfo->LastStatusRc = - (*pIxChkInfo->pDbInfo->fnStatusFunc)( FLM_PROBLEM_STATUS, - (void *)&CorruptInfo, - (void *)pbFixErrRV, - pIxChkInfo->pDbInfo->pProgress->AppArg); - } -Exit: - - if( CorruptInfo.pErrRecord) - { - CorruptInfo.pErrRecord->Release(); - } - - if( CorruptInfo.pErrIxKey) - { - CorruptInfo.pErrIxKey->Release(); - } - - if( CorruptInfo.pErrRecordKeyList) - { - REC_KEY * pTempKey = CorruptInfo.pErrRecordKeyList; - - while (pTempKey) - { - pTempKey->pKey->Release(); - pTempKey = pTempKey->pNextKey; - } - } - - // Remove any keys added to the KRef - - if (bResetKRef) - { - KYAbortCurrentRecord( pDb); - } - - // Reset the DB's temporary pool - - GedPoolReset( &(pDb->TempPool), pDbPoolMark); - - // Reset the index check pool - - GedPoolReset( &(pIxChkInfo->pool), pIxPoolMark); - return( rc); -} - - -/*************************************************************************** -Desc: This routine verifies that a key is not unique -*****************************************************************************/ -FSTATIC RCODE - chkVerifyKeyNotUnique( - STATE_INFO * pStateInfo, - FLMUINT uiIndex, - FLMBYTE * pucKey, - FLMUINT uiKeyLen, - FLMUINT * puiRefCountRV - ) -{ - FDB * pDb = pStateInfo->pDb; - RCODE rc = FERR_OK; - FlmRecord * pKeyTree = NULL; - IXD * pIxd; - FLMUINT uiRefDrn; - - *puiRefCountRV = 0; - - /* Get the IXD */ - - if (RC_BAD( rc = fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, - uiIndex, NULL, &pIxd))) - { - goto Exit; - } - - /* - This routine should not be called unless the index is - a unique index. - */ - - flmAssert( ((pIxd->uiFlags & IXD_UNIQUE) != 0)); - - /* - Generate the key tree from the collation key. - */ - - if( RC_BAD( rc = chkKeyToTree( pIxd, pucKey, uiKeyLen, &pKeyTree))) - { - goto Exit; - } - - // Count up to the first two references for the key. - - if (RC_BAD( rc = FlmKeyRetrieve( (HFDB)pDb, - uiIndex, pKeyTree->getContainerID(), - pKeyTree, 0, FO_EXACT, - NULL, &uiRefDrn))) - { - - // If the key is NOT found, the problem no longer exists. - - if ((rc == FERR_NOT_FOUND) || - (rc == FERR_BOF_HIT) || - (rc == FERR_EOF_HIT)) - { - rc = FERR_OK; - } - goto Exit; - } - - // Found at least one reference. - - *puiRefCountRV = 1; - - // Go exclusive of the last key/reference found to see if there - // are more references for the key. - - if (RC_BAD( rc = FlmKeyRetrieve( (HFDB)pDb, - uiIndex, pKeyTree->getContainerID(), - pKeyTree, uiRefDrn, FO_KEY_EXACT | FO_EXCL, - NULL, &uiRefDrn))) - { - if ((rc == FERR_NOT_FOUND) || - (rc == FERR_BOF_HIT) || - (rc == FERR_EOF_HIT)) - { - rc = FERR_OK; - } - goto Exit; - } - - // May be more references, but it is sufficient to know that there - // are at least two. - - *puiRefCountRV = 2; -Exit: - return( rc); -} - - -/*************************************************************************** -Desc: -*****************************************************************************/ -FSTATIC RCODE chkStartUpdate( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo - ) -{ - FDB * pDb = pStateInfo->pDb; - FLMBOOL bAbortedReadTrans = FALSE; - RCODE rc = FERR_OK; - RCODE rc2 = FERR_OK; - - if( flmGetDbTransType( pDb) == FLM_READ_TRANS) - { - /* Free the KrefCntrl */ - - KrefCntrlFree( pDb); - - /* Abort the read transaction */ - - if( RC_BAD( rc = flmAbortDbTrans( pDb))) - { - goto Exit; - } - bAbortedReadTrans = TRUE; - - /* Try to start an update transaction */ - - if( RC_BAD( rc = flmBeginDbTrans( pDb, - FLM_UPDATE_TRANS, pIxChkInfo->pDbInfo->uiMaxLockWait, - FLM_DONT_POISON_CACHE))) - { - goto Exit; - } - pIxChkInfo->pDbInfo->bStartedUpdateTrans = TRUE; - } - - if( RC_BAD( pIxChkInfo->pDbInfo->LastStatusRc)) - { - rc = pIxChkInfo->pDbInfo->LastStatusRc; - goto Exit; - } - -Exit: - - /* - If something went wrong after the update transaction was started, - abort the transaction. - */ - - if( RC_BAD( rc)) - { - if( pIxChkInfo->pDbInfo->bStartedUpdateTrans == TRUE) - { - (void)flmAbortDbTrans( pDb); - pIxChkInfo->pDbInfo->bStartedUpdateTrans = FALSE; - } - } - - /* - Re-start the read transaction. - */ - - if( bAbortedReadTrans == TRUE && - pIxChkInfo->pDbInfo->bStartedUpdateTrans == FALSE) - { - rc2 = flmBeginDbTrans( pDb, FLM_READ_TRANS, 0, FLM_DONT_POISON_CACHE); - } - - rc = (RCODE)((rc != FERR_OK) ? (RCODE)rc : (RCODE)rc2); - - return( rc); -} - - -/*************************************************************************** -Desc: -*****************************************************************************/ -FSTATIC RCODE - chkEndUpdate( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo - ) -{ - RCODE rc = FERR_OK; - RCODE rc2 = FERR_OK; - - if( pIxChkInfo->pDbInfo->bStartedUpdateTrans == TRUE) - { - /* - Commit the update transaction that was started. If the transaction - started by the application, do not commit it. - */ - - if( RC_BAD( rc = flmCommitDbTrans( pStateInfo->pDb, 0, FALSE))) - { - goto Exit; - } - pIxChkInfo->pDbInfo->bStartedUpdateTrans = FALSE; - } - -Exit: - - /* Re-start read transaction */ - - if( flmGetDbTransType( pStateInfo->pDb) == FLM_NO_TRANS) - { - rc2 = flmBeginDbTrans( pStateInfo->pDb, - FLM_READ_TRANS, 0, FLM_DONT_POISON_CACHE); - } - - rc = (RCODE)((rc != FERR_OK) ? (RCODE)rc : (RCODE)rc2); - - return( rc); -} - - -/*************************************************************************** -Desc: Initializes a result set for use by the logical check code -*****************************************************************************/ -RCODE chkRSInit( - const char * pIoPath, - void ** ppvRSetRV) -{ - RCODE rc = FERR_OK; - FResultSet * pRSet; - - if( (pRSet = f_new FResultSet) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = pRSet->Setup( pIoPath, - chkCompareIxRSEntries, 0, 0, TRUE, FALSE))) - { - goto Exit; - } - - *ppvRSetRV = (void *)pRSet; - -Exit: - - return( rc); -} - -/*************************************************************************** -Desc: Sorts a result set. -*****************************************************************************/ -RCODE - chkRSFinalize( - IX_CHK_INFO * pIxChkInfo, - FLMUINT64 * pui64TotalEntries - ) -{ - FResultSet * pRSet = (FResultSet *)(pIxChkInfo->pRSet); - DB_CHECK_PROGRESS * pProgress = pIxChkInfo->pDbInfo->pProgress; - DB_CHECK_PROGRESS saveInfo; - RCODE rc = FERR_OK; - - /* - Save the current check phase information. - */ - - f_memcpy( &saveInfo, pProgress, sizeof( DB_CHECK_PROGRESS)); - - /* - Set information for the result set sort phase. - */ - - pProgress->iCheckPhase = CHECK_RS_SORT; - pProgress->bStartFlag = TRUE; - pProgress->ui64NumRSUnits = 0; - pProgress->ui64NumRSUnitsDone = 0; - - pRSet->SetCallback( chkRSCallbackFunc, (void *)pIxChkInfo); - - if( RC_BAD( rc = pRSet->Finalize( pui64TotalEntries))) - { - goto Exit; - } - -Exit: - - (void)pRSet->SetCallback( NULL, 0); - - /* - Reset the pProgress information. - */ - - f_memcpy( pProgress, &saveInfo, sizeof( DB_CHECK_PROGRESS)); - pProgress->bStartFlag = TRUE; - - return( rc); -} - -/*************************************************************************** -Desc: Compares result set entries during the finalization stage to allow - the result set to be sorted and to remove duplicates. -*****************************************************************************/ -RCODE chkCompareIxRSEntries( - void * vpData1, - FLMUINT uiLength1, - void * vpData2, - FLMUINT uiLength2, - void * UserValue, - FLMINT * piCompare) -{ - FLMBYTE * pucData1 = (FLMBYTE *)vpData1; - FLMBYTE * pucData2 = (FLMBYTE *)vpData2; - FLMUINT uiIxNum1; - FLMUINT uiIxNum2; - FLMUINT uiDrn1; - FLMUINT uiDrn2; - - F_UNREFERENCED_PARM( UserValue); - - uiIxNum1 = (FLMUINT)FB2UW( &(pucData1[ RS_IX_OFFSET])); - uiIxNum2 = (FLMUINT)FB2UW( &(pucData2[ RS_IX_OFFSET])); - uiDrn1 = (FLMUINT)FB2UD( &(pucData1[ RS_REF_OFFSET])); - uiDrn2 = (FLMUINT)FB2UD( &(pucData2[ RS_REF_OFFSET])); - - *piCompare = chkCompareKeySet( - uiIxNum1, &(pucData1[ RS_KEY_OFFSET]), - uiLength1 - RS_KEY_OVERHEAD, uiDrn1, - uiIxNum2, &(pucData2[ RS_KEY_OFFSET]), - uiLength2 - RS_KEY_OVERHEAD, uiDrn2); - - return( FERR_OK); -} - - -/*************************************************************************** -Desc: Callback for result set sort progress. -*****************************************************************************/ -FLMINT chkRSCallbackFunc( - RSET_CB_INFO * pCBInfo) -{ - IX_CHK_INFO * pIxChkInfo = (IX_CHK_INFO *)pCBInfo->UserValue; - DB_CHECK_PROGRESS * pProgress = pIxChkInfo->pDbInfo->pProgress; - FLMINT iRetVal = 0; - - f_yieldCPU(); - - /* - Set the status values. - */ - - pProgress->ui64NumRSUnits = pCBInfo->ui64EstTotalUnits; - pProgress->ui64NumRSUnitsDone = pCBInfo->ui64UnitsDone; - - /* - Call the progress callback. - */ - - if (RC_BAD( chkCallProgFunc( pIxChkInfo->pDbInfo))) - { - iRetVal = -1; - goto Exit; - } - -Exit: - - pProgress->bStartFlag = FALSE; - return( iRetVal); -} diff --git a/flaim/src/flchktr.cpp b/flaim/src/flchktr.cpp deleted file mode 100644 index d3e4773..0000000 --- a/flaim/src/flchktr.cpp +++ /dev/null @@ -1,2349 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Check database b-trees for physical corruptions. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flchktr.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE chkReadBlkFromDisk( - FILE_HDR * pFileHdr, - F_SuperFileHdl * pSFileHdl, - FLMUINT uiFilePos, - FLMUINT uiBlkAddress, - LFILE * pLFile, - FFILE * pFile, - FLMBYTE * pBlk); - -FSTATIC RCODE chkVerifyElmFields( - STATE_INFO * pStateInfo, - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxChkInfo, - POOL * pTmpPool, - FLMUINT * puiErrElmRecOffsetRV, - eCorruptionType * peElmErrCorruptCode); - -FSTATIC RCODE chkVerifySubTree( - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxChkInfo, - STATE_INFO * ParentState, - STATE_INFO * pStateInfo, - FLMUINT uiBlkAddress, - POOL * pTmpPool, - FLMBYTE * pucResetKey, - FLMUINT uiResetKeyLen, - FLMUINT uiResetDrn); - -FSTATIC RCODE chkGetLfInfo( - DB_INFO * pDbInfo, - POOL * pPool, - LF_STATS * pLfStats, - LFILE * pLFile, - LF_STATS * pCurrLfStats, - FLMBOOL * pbCurrLfLevelChangedRV); - -FSTATIC RCODE chkSetupLfTable( - DB_INFO * pDbInfo, - POOL * pPool); - -FSTATIC RCODE chkSetupIxInfo( - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxInfoRV); - -FSTATIC RCODE chkOutputIndexKeys( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - IXD * pIxd, - REC_KEY * pKeyList); - -/**************************************************************************** -Desc: Frees memory allocated to a result set and deletes any temporary files - that may have been created. -****************************************************************************/ -FINLINE void chkRSFree( - void ** ppRSetRV) -{ - FResultSet * pRSet; - - pRSet = *((FResultSet **)ppRSetRV); - pRSet->Release(); - *ppRSetRV = (void *)0; -} - -/**************************************************************************** -Desc: Adds a variable-length entry to a result set. -****************************************************************************/ -FINLINE RCODE chkRSAddEntry( - void * pRSet, - FLMBYTE * pEntry, - FLMUINT uiEntryLength) -{ - return( ((FResultSet *)pRSet)->AddEntry( pEntry, uiEntryLength)); -} - -/**************************************************************************** -Desc: This routine counts the number of fields in an object table. -****************************************************************************/ -FINLINE void chkCountFields( - FDICT * pDict, - FLMUINT * puiNumFieldsRV) -{ - FLMUINT uiTblSize = pDict->uiIttCnt; - ITT * pItt = pDict->pIttTbl; - FLMUINT uiCount = 0; - FLMUINT uiCurrObj; - - for (uiCurrObj = 0; uiCurrObj < uiTblSize; uiCurrObj++, pItt++) - { - if( ITT_IS_FIELD( pItt)) - { - uiCount++; - } - } - (*puiNumFieldsRV) += uiCount; -} - -/**************************************************************************** -Desc: Frees memory allocated to an IX_CHK_INFO structure -****************************************************************************/ -FINLINE RCODE chkFreeIxInfo( - IX_CHK_INFO * pIxInfoRV) -{ - GedPoolFree( &(pIxInfoRV->pool)); - chkRSFree( &(pIxInfoRV->pRSet)); - f_free( &(pIxInfoRV->puiIxArray)); - f_memset( pIxInfoRV, 0, sizeof( IX_CHK_INFO)); - - return FERR_OK; -} - -/******************************************************************** -Desc: -*********************************************************************/ -RCODE chkBlkRead( - DB_INFO * pDbInfo, - FLMUINT uiBlkAddress, - LFILE * pLFile, - FLMBYTE ** ppBlk, - SCACHE ** ppSCache, - eCorruptionType * peCorruption - ) -{ - FDB * pDb = pDbInfo->pDb; - FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; - RCODE rc = FERR_OK; - - if( *ppSCache) - { - ScaReleaseCache( *ppSCache, FALSE); - *ppSCache = NULL; - *ppBlk = NULL; - } - else if( *ppBlk) - { - f_free( ppBlk); - *ppBlk = NULL; - } - - if( pDb->uiKilledTime) - { - rc = RC_SET( FERR_OLD_VIEW); - goto Exit; - } - - /* - Get the block from cache. - */ - - if( RC_OK( rc = ScaGetBlock( pDb, pLFile, 0, - uiBlkAddress, NULL, ppSCache))) - { - *ppBlk = (*ppSCache)->pucBlk; - } - else - { - /* - Try to read the block directly from disk. - */ - - FLMUINT uiBlkLen = pFileHdr->uiBlockSize; - FLMUINT uiTransID; - FLMBYTE * pucBlk; - FLMUINT uiLastReadTransID; - FLMUINT uiPrevBlkAddr; - FLMUINT uiFilePos; - - /* - If we didn't get a corruption error, jump to exit. - */ - - if( !FlmErrorIsFileCorrupt( rc)) - { - goto Exit; - } - - /* - Allocate memory for the block. - */ - - if( RC_BAD( rc = f_calloc( uiBlkLen, ppBlk))) - { - goto Exit; - } - pucBlk = *ppBlk; - - uiFilePos = uiBlkAddress; - uiTransID = pDb->LogHdr.uiCurrTransID; - uiLastReadTransID = 0xFFFFFFFF; - - // Follow version chain until we find version we need. - - for (;;) - { - - if( RC_BAD( rc = chkReadBlkFromDisk( pFileHdr, pDbInfo->pSFileHdl, - uiFilePos, uiBlkAddress, pLFile, pDb->pFile, pucBlk))) - { - goto Exit; - } - - /* - See if we can use the current version of the block, or if we - must go get a previous version. - */ - - if( (FLMUINT)FB2UD( &pucBlk [BH_TRANS_ID]) <= uiTransID) - { - break; - } - - // If the transaction ID is greater than or equal to the last - // one we read, we have a corruption. This test will keep us - // from looping around forever. - - if ((FLMUINT)FB2UD( &pucBlk [BH_TRANS_ID]) >= uiLastReadTransID) - { - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - uiLastReadTransID = (FLMUINT)FB2UD( &pucBlk [BH_TRANS_ID]); - - // Block is too new, go for next older version. - - // If previous block address is same as current file position or - // zero, we have a problem. - - uiPrevBlkAddr = (FLMUINT)FB2UD( &pucBlk [BH_PREV_BLK_ADDR]); - if ((uiPrevBlkAddr == uiFilePos) || (!uiPrevBlkAddr)) - { - rc = (pDb->uiKilledTime) - ? RC_SET( FERR_OLD_VIEW) - : RC_SET( FERR_DATA_ERROR); - goto Exit; - } - uiFilePos = uiPrevBlkAddr; - } - - /* See if we even got the block we thought we wanted. */ - - if (GET_BH_ADDR( pucBlk) != uiBlkAddress) - { - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - } - -Exit: - - *peCorruption = FLM_NO_CORRUPTION; - if (RC_BAD( rc)) - { - switch (rc) - { - case FERR_DATA_ERROR: - *peCorruption = FLM_COULD_NOT_SYNC_BLK; - break; - case FERR_BLOCK_CHECKSUM: - *peCorruption = FLM_BAD_BLK_CHECKSUM; - break; - default: - break; - } - } - return( rc); -} - -/************************************************************************ -Desc: -*************************************************************************/ -FSTATIC RCODE chkReadBlkFromDisk( - FILE_HDR * pFileHdr, - F_SuperFileHdl * pSFileHdl, - FLMUINT uiFilePos, - FLMUINT uiBlkAddress, - LFILE * pLFile, - FFILE * pFile, - FLMBYTE * pBlk) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesRead; - FLMUINT uiBlkLen = pFileHdr->uiBlockSize; - - if (RC_BAD( rc = pSFileHdl->ReadBlock( uiFilePos, - uiBlkLen, pBlk, &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - rc = RC_SET( FERR_DATA_ERROR); - } - goto Exit; - } - - if( uiBytesRead < uiBlkLen) - { - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - - /* Verify the block checksum BEFORE decrypting or using any data. */ - - if( RC_BAD( rc = BlkCheckSum( pBlk, CHECKSUM_CHECK, - uiBlkAddress, uiBlkLen))) - { - goto Exit; - } - - // If this is an index block it may be encrypted, we - // need to decrypt it before we can use it. - // The function ScaDecryptBlock will check if the index - // is encrypted first. If not, it will return. - if (pLFile && pLFile->uiLfType == LF_INDEX) - { - if (RC_BAD( rc = ScaDecryptBlock( pFile, pBlk))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: -*********************************************************************/ -FSTATIC RCODE chkVerifyElmFields( - STATE_INFO * pStateInfo, - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxChkInfo, - POOL * pTmpPool, - FLMUINT * puiErrElmRecOffsetRV, - eCorruptionType * peElmCorruptCode) -{ - FLMBYTE * pValue = pStateInfo->pValue; - FLMBYTE * pData = pStateInfo->pData; - FLMBYTE * pTempValue; - FlmRecord * pRecord = pStateInfo->pRecord; - FLMBOOL bKRefAbortRec = FALSE; - FLMUINT uiSaveElmRecOffset = 0; - void * pDbPoolMark = NULL; - void * pKeyMark = NULL; - FLMBOOL bResetDbPool = FALSE; - RCODE rc = FERR_OK; - void * pvField = pStateInfo->pvField; - REC_KEY * pKeyList = NULL; - REC_KEY * pTmpKey; - - *peElmCorruptCode = FLM_NO_CORRUPTION; - - pTempValue = (pValue) - ? (FLMBYTE *)&pValue [pStateInfo->uiFieldProcessedLen] - : (FLMBYTE *)NULL; - - while ((*peElmCorruptCode == FLM_NO_CORRUPTION) && - (pStateInfo->uiElmRecOffset < pStateInfo->uiElmRecLen)) - { - uiSaveElmRecOffset = pStateInfo->uiElmRecOffset; - if ((*peElmCorruptCode = flmVerifyElmFOP( pStateInfo)) != FLM_NO_CORRUPTION) - { - break; - } - - if (!pStateInfo->bElmRecOK) - { - pValue = pTempValue = NULL; - if (pRecord) - { - pRecord->clear(); - } - continue; - } - switch (pStateInfo->uiFOPType) - { - case FLM_FOP_CONT_DATA: - if ((pTempValue != NULL) && (pStateInfo->uiFOPDataLen)) - { - f_memcpy( pTempValue, - pStateInfo->pFOPData, pStateInfo->uiFOPDataLen); - pTempValue += pStateInfo->uiFOPDataLen; - } - break; - case FLM_FOP_STANDARD: - case FLM_FOP_OPEN: - case FLM_FOP_TAGGED: - case FLM_FOP_NO_VALUE: - if( pValue) - { - pValue = pTempValue = NULL; - } - - if (pvField) - { - pvField = NULL; - } - - if (!pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - if (RC_BAD( rc = pRecord->insertLast( pStateInfo->uiFieldLevel, - pStateInfo->uiFieldNum, - pStateInfo->uiFieldType, &pvField))) - { - goto Exit; - } - - - if( pStateInfo->uiFieldLen) - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - pStateInfo->uiFieldType, - pStateInfo->uiFieldLen, - 0, - 0, - 0, - &pValue, - NULL))) - { - goto Exit; - } - pTempValue = pValue; - } - - if ((pTempValue) && (pStateInfo->uiFOPDataLen)) - { - f_memcpy( pTempValue, pStateInfo->pFOPData, - pStateInfo->uiFOPDataLen); - pTempValue += pStateInfo->uiFOPDataLen; - } - break; - - case FLM_FOP_ENCRYPTED: - { - if( pValue) - { - pValue = pTempValue = NULL; - } - - if( pData) - { - pData = NULL; - } - - if (pvField) - { - pvField = NULL; - } - - if (!pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - if (RC_BAD( rc = pRecord->insertLast( pStateInfo->uiFieldLevel, - pStateInfo->uiFieldNum, - pStateInfo->uiFieldType, &pvField))) - { - goto Exit; - } - - - if( pStateInfo->uiFieldLen) - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - pStateInfo->uiFieldType, - pStateInfo->uiFieldLen, - pStateInfo->uiEncFieldLen, - pStateInfo->uiEncId, - FLD_HAVE_ENCRYPTED_DATA, - &pData, - &pValue))) - { - goto Exit; - } - pTempValue = pValue; - } - - if ((pTempValue) && (pStateInfo->uiFOPDataLen)) - { - f_memcpy( pTempValue, pStateInfo->pFOPData, - pStateInfo->uiFOPDataLen); - pTempValue += pStateInfo->uiFOPDataLen; - } - break; - } - - case FLM_FOP_JUMP_LEVEL: - break; - } - - if ((!pStateInfo->uiEncId && pStateInfo->uiFieldProcessedLen == pStateInfo->uiFieldLen) || - (pStateInfo->uiEncId && pStateInfo->uiFieldProcessedLen == pStateInfo->uiEncFieldLen)) - { - - /* - The whole field has been retrieved. Verify the field and - graft it into the record being built. - */ - - if (pValue && (pDbInfo->uiFlags & FLM_CHK_FIELDS)) - { - if (pStateInfo->uiFieldType == 0xFF) - { - // Hit Rec Info object - don't care what's in it - must not - // assert, because this would kill our ability to check - // older versions of the database which have REC_INFO - // data in them. - - *peElmCorruptCode = FLM_NO_CORRUPTION; - } - else - { - if (!pStateInfo->uiEncId) - { - *peElmCorruptCode = flmVerifyField( pValue, - pStateInfo->uiFieldLen, pStateInfo->uiFieldType); - } - else - { - // Decrypt the field and store the decrypted data. - - if (!pStateInfo->pDb->pFile->bInLimitedMode) - { - if (RC_BAD( rc = flmDecryptField( pStateInfo->pDb->pDict, - pRecord, pvField, pStateInfo->uiEncId, pTmpPool))) - { - goto Exit; - } - *peElmCorruptCode = flmVerifyField( pData, - pStateInfo->uiFieldLen, pStateInfo->uiFieldType); - } - else - { - // If we can't decrypt the field, then just pass - // it for now. - - *peElmCorruptCode = FLM_NO_CORRUPTION; - } - } - } - } - else - { - *peElmCorruptCode = FLM_NO_CORRUPTION; - } - - pValue = pTempValue = NULL; - } - - // If this is the last element of the record, verify the - // record's keys. - - if( BBE_IS_LAST( pStateInfo->pElm) && - (pStateInfo->uiElmRecOffset == pStateInfo->uiElmRecLen)) - { - pValue = pTempValue = NULL; - - if( !pDbInfo->pProgress->bPhysicalCorrupt && (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING)) - { - FLMUINT uiLoop; - IXD * pIxd; - - if( pStateInfo->pLogicalFile->pLFile->uiLfType == LF_CONTAINER) - { - // Need to mark the DB's temporary pool. The index code - // allocates memory for new CDL entries from the DB pool. If - // the pool is not reset, it grows during the check and - // becomes VERY large. - - pDbPoolMark = GedPoolMark( &(pDbInfo->pDb->TempPool)); - bResetDbPool = TRUE; - - /* - Set up the KRef table so that flmGetRecKeys - will work correctly. - */ - - if( RC_BAD( rc = KrefCntrlCheck( pStateInfo->pDb))) - { - goto Exit; - } - bKRefAbortRec = TRUE; - - for( uiLoop = 0; uiLoop < pIxChkInfo->uiIxCount; uiLoop++) - { - if( RC_BAD( rc = fdictGetIndex( - pStateInfo->pDb->pDict, - pStateInfo->pDb->pFile->bInLimitedMode, - pIxChkInfo->puiIxArray[ uiLoop], NULL, &pIxd, TRUE))) - { - goto Exit; - } - - if( pIxd->uiFlags & IXD_OFFLINE) - { - continue; - } - - if( pIxd->uiContainerNum == - pStateInfo->pLogicalFile->pLFile->uiLfNum || - !pIxd->uiContainerNum) - { - /* - Mark the field pool so that it can be reset - after the record keys have been generated - and output. - */ - - pKeyMark = GedPoolMark( pTmpPool); - - /* - Build the record keys for the current index. - Do not remove duplicate keys. The result set - will remove any duplicates. - */ - - if (RC_BAD( rc = flmGetRecKeys( - pStateInfo->pDb, pIxd, pRecord, - pStateInfo->pLogicalFile->pLFile->uiLfNum, - FALSE, pTmpPool, &pKeyList))) - { - goto Exit; - } - - /* - If the record generated keys for the current - index, output the keys to the result set. - */ - - if( pKeyList) - { - if( RC_BAD( rc = chkOutputIndexKeys( - pStateInfo, pIxChkInfo, pIxd, pKeyList))) - { - goto Exit; - } - - pTmpKey = pKeyList; - while( pTmpKey) - { - pTmpKey->pKey->Release(); - pTmpKey->pKey = NULL; - pTmpKey = pTmpKey->pNextKey; - } - pKeyList = NULL; - } - - /* Reset the field pool */ - - GedPoolReset( pTmpPool, pKeyMark); - } - } - - /* - Clean up any keys that may have been added to the - KRef table. - */ - - KYAbortCurrentRecord( pStateInfo->pDb); - bKRefAbortRec = FALSE; - - /* Reset the DB's temporary pool */ - - (void)GedPoolReset( &(pDbInfo->pDb->TempPool), pDbPoolMark); - bResetDbPool = FALSE; - } - } - - if (pRecord) - { - pRecord->clear(); - } - pValue = pTempValue = NULL; - GedPoolReset( pTmpPool, NULL); - } - - if( *peElmCorruptCode != FLM_NO_CORRUPTION) - { - pStateInfo->bElmRecOK = FALSE; - } - } - -Exit: - - /* - Clean up any keys that may have been added to the - KRef table. This is a fail-safe case to clean up the - KRef in case KYKeysCommit didn't get called above. - */ - - if (bKRefAbortRec) - { - KYAbortCurrentRecord( pStateInfo->pDb); - } - - /* - Free any keys in the key list - */ - - if( pKeyList) - { - pTmpKey = pKeyList; - while( pTmpKey) - { - pTmpKey->pKey->Release(); - pTmpKey->pKey = NULL; - pTmpKey = pTmpKey->pNextKey; - } - } - - /* Reset the DB's temporary pool */ - - if( bResetDbPool) - { - (void)GedPoolReset( &(pDbInfo->pDb->TempPool), pDbPoolMark); - } - - if( *peElmCorruptCode != FLM_NO_CORRUPTION || RC_BAD( rc)) - { - pValue = pTempValue = NULL; - GedPoolReset( pTmpPool, NULL); - if (pRecord) - { - pRecord->clear(); - } - } - - pStateInfo->pValue = pValue; - pStateInfo->pData = pData; - pStateInfo->pvField = pvField; - pStateInfo->pRecord = pRecord; - - if( *peElmCorruptCode != FLM_NO_CORRUPTION) - { - *puiErrElmRecOffsetRV = uiSaveElmRecOffset; - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine checks all of the blocks/links in a sub-tree of a - B-TREE. It calls itself recursively whenever it descends a level - in the tree. -*****************************************************************************/ -FSTATIC RCODE chkVerifySubTree( - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxChkInfo, - STATE_INFO * pParentState, - STATE_INFO * pStateInfo, - FLMUINT uiBlkAddress, - POOL * pTmpPool, - FLMBYTE * pucResetKey, - FLMUINT uiResetKeyLen, - FLMUINT uiResetDrn) -{ - RCODE rc = FERR_OK; - SCACHE * pSCache = NULL; - FLMBYTE * pBlk = NULL; - FLMUINT uiLevel = pStateInfo->uiLevel; - FLMUINT uiBlkType = pStateInfo->uiBlkType; - FLMUINT uiLfType = pStateInfo->pLogicalFile->pLFile->uiLfType; - FLMUINT uiBlockSize = - pDbInfo->pDb->pFile->FileHdr.uiBlockSize; - FLMUINT uiParentBlkAddress; - FLMBYTE * pChildBlkAddr; - FLMUINT uiChildBlkAddress; - FLMUINT uiPrevNextBlkAddress; - eCorruptionType eElmCorruptCode; - eCorruptionType eBlkCorruptionCode = FLM_NO_CORRUPTION; - eCorruptionType eLastCorruptCode = FLM_NO_CORRUPTION; - FLMUINT uiNumErrors = 0; - FLMUINT uiErrElmRecOffset = 0; - FLMUINT64 ui64SaveKeyCount = 0; - FLMUINT64 ui64SaveKeyRefs = 0; - BLOCK_INFO SaveBlkInfo; - BLOCK_INFO * pBlkInfo; - FLMBOOL bProcessElm; - FLMBOOL bCountElm; - FLMBOOL bDescendToChildBlocks; - FLMINT iCompareStatus; - eCorruptionType eHdrCorruptCode; - - /* Setup the state information. */ - - pStateInfo->pBlk = NULL; - pStateInfo->uiBlkAddress = uiBlkAddress; - uiPrevNextBlkAddress = pStateInfo->uiNextBlkAddr; - uiParentBlkAddress = (pParentState) - ? pParentState->uiBlkAddress - : BT_END; - - f_yieldCPU(); - - /* Read the sub-tree root block into memory. */ - - bDescendToChildBlocks = TRUE; - if (RC_BAD( rc = chkBlkRead( pDbInfo, - uiBlkAddress, - pStateInfo->pLogicalFile ? pStateInfo->pLogicalFile->pLFile : NULL, - &pBlk, &pSCache,&eBlkCorruptionCode))) - { - if (eBlkCorruptionCode != FLM_NO_CORRUPTION) - { - uiNumErrors++; - eLastCorruptCode = eBlkCorruptionCode; - chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, 0, 0, 0xFFFF, 0, pBlk); - if (eBlkCorruptionCode == FLM_BAD_BLK_CHECKSUM) - { - bDescendToChildBlocks = FALSE; - - /* - Allow to continue the check, but if this is a non-leaf block - a non-zero eBlkCorruptionCode will prevent us from descending to - child blocks. Set rc to SUCCESS so we won't goto Exit below. - */ - - rc = FERR_OK; - } - else if (eBlkCorruptionCode == FLM_COULD_NOT_SYNC_BLK) - { - eLastCorruptCode = eBlkCorruptionCode; - - /* - Need the goto here, because rc is changed to SUCCESS, - and the goto below would get skipped. - */ - - rc = FERR_OK; - goto fix_state; - } - } - else if (rc == FERR_OLD_VIEW) - { - pDbInfo->bReposition = TRUE; - } - - /* If rc was not changed to SUCCESS above, goto Exit. */ - - if (RC_BAD( rc)) - goto Exit; - } - pStateInfo->pBlk = pBlk; - - /* Verify the block header */ - - /* Don't recount the block if we are resetting. */ - - if (!uiResetKeyLen) - { - pDbInfo->pProgress->ui64BytesExamined += (FLMUINT64)uiBlockSize; - pBlkInfo = &pStateInfo->BlkInfo; - } - else - { - pBlkInfo = NULL; - } - chkCallProgFunc( pDbInfo); - - /* Check the block header. */ - - if ((eHdrCorruptCode = - flmVerifyBlockHeader( pStateInfo, pBlkInfo, uiBlockSize, - (pParentState == NULL) - ? BT_END - : 0, - (pParentState == NULL) - ? BT_END - : pParentState->uiLastChildAddr, - TRUE, TRUE)) == FLM_NO_CORRUPTION) - { - - /* - Verify the previous block's next block address -- it should - equal the current block's address. - */ - - if ((uiPrevNextBlkAddress) && - (uiPrevNextBlkAddress != uiBlkAddress)) - { - eHdrCorruptCode = FLM_BAD_PREV_BLK_NEXT; - } - } - if (eHdrCorruptCode != FLM_NO_CORRUPTION) - { - eLastCorruptCode = eHdrCorruptCode; - uiNumErrors++; - chkReportError( pDbInfo, eHdrCorruptCode, LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, 0, 0, 0xFFFF, 0, - pBlk); - } - - /* Go through the elements in the block. */ - - pStateInfo->uiElmOffset = BH_OVHD; - while ((pStateInfo->uiElmOffset < pStateInfo->uiEndOfBlock) && - (RC_OK( pDbInfo->LastStatusRc))) - { - - /* - If we are resetting, save any statistical information so we - can back it out if we need to. - */ - - if (uiResetKeyLen) - { - ui64SaveKeyCount = pStateInfo->ui64KeyCount; - ui64SaveKeyRefs = pStateInfo->ui64KeyRefs; - f_memcpy( &SaveBlkInfo, &pStateInfo->BlkInfo, sizeof( BLOCK_INFO)); - bCountElm = FALSE; - bProcessElm = FALSE; - } - else - { - bCountElm = TRUE; - bProcessElm = TRUE; - } - - pStateInfo->BlkInfo.ui64ElementCount++; - - if ((eElmCorruptCode = flmVerifyElement( pStateInfo, pDbInfo->uiFlags)) != FLM_NO_CORRUPTION) - { - - /* Report any errors in the element. */ - - eLastCorruptCode = eElmCorruptCode; - uiNumErrors++; - if (RC_BAD( rc = chkReportError( pDbInfo, eElmCorruptCode, - LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, - pStateInfo->uiElmOffset, pStateInfo->uiElmDrn, - 0xFFFF, 0, pBlk))) - { - break; - } - } - - /* Keep track of the number of continuation elements. */ - - if ((uiBlkType == BHT_LEAF) && - (!BBE_IS_FIRST( pStateInfo->pElm)) && - (pStateInfo->uiElmLen != BBE_LEM_LEN)) - { - pStateInfo->BlkInfo.ui64ContElementCount++; - pStateInfo->BlkInfo.ui64ContElmBytes += pStateInfo->uiElmLen; - } - - /* Do some further checking. */ - - if (eElmCorruptCode != FLM_NO_CORRUPTION) - { - pStateInfo->bElmRecOK = FALSE; - } - else - { - /* See if we are resetting */ - - iCompareStatus = 0; - if ((uiResetKeyLen) && - (pStateInfo->bValidKey) && - ((!pStateInfo->uiCurKeyLen) || - ((iCompareStatus = flmCompareKeys( pStateInfo->pCurKey, - pStateInfo->uiCurKeyLen, - pucResetKey, uiResetKeyLen)) >= 0))) - { - if (iCompareStatus > 0) - { - if (uiBlkType == BHT_LEAF) - { - uiResetKeyLen = 0; - pucResetKey = NULL; - uiResetDrn = 0; - bCountElm = TRUE; - } - bProcessElm = TRUE; - } - else if( uiLfType == LF_INDEX) - { - FLMBYTE * pTmpElm = pStateInfo->pElm; - FLMUINT uiLowestDrn = FSGetDomain( &pTmpElm, - pStateInfo->uiElmOvhd); - - if( uiResetDrn >= uiLowestDrn) - { - bProcessElm = TRUE; - bCountElm = TRUE; - } - } - else - { - /* Processing a container */ - bProcessElm = TRUE; - } - } - - if (uiBlkType == BHT_LEAF) - { - /* No need to parse LEM element. */ - - if ((pStateInfo->uiCurKeyLen != 0) && (pStateInfo->bValidKey)) - { - if (uiLfType == LF_CONTAINER) - { - if (pStateInfo->uiElmDrn != DRN_LAST_MARKER) - { - if( RC_BAD( rc = chkVerifyElmFields( pStateInfo, - pDbInfo, pIxChkInfo, pTmpPool, - &uiErrElmRecOffset, &eElmCorruptCode))) - { - goto Exit; - } - } - } - else if( bProcessElm) - { - uiErrElmRecOffset = 0xFFFF; - if( !pDbInfo->pProgress->bPhysicalCorrupt && (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING)) - { - if(( RC_BAD( rc = flmVerifyIXRefs( pStateInfo, pIxChkInfo, - uiResetDrn, &eElmCorruptCode))) || - (pDbInfo->bReposition)) - { - goto Exit; - } - } - else - { - if(( RC_BAD( rc = flmVerifyIXRefs( pStateInfo, NULL, - uiResetDrn, &eElmCorruptCode))) || - (pDbInfo->bReposition)) - { - goto Exit; - } - } - } - } - - if( bProcessElm) - { - uiResetKeyLen = 0; - pucResetKey = NULL; - uiResetDrn = 0; - - if (eElmCorruptCode != FLM_NO_CORRUPTION) - { - - /* Report any errors in the element. */ - - eLastCorruptCode = eElmCorruptCode; - uiNumErrors++; - chkReportError( pDbInfo, eElmCorruptCode, - LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, - pStateInfo->uiElmOffset, - pStateInfo->uiElmDrn, - uiErrElmRecOffset, - pStateInfo->uiFieldNum, - pBlk); - - if (RC_BAD( pDbInfo->LastStatusRc)) - { - break; - } - } - } - } - else - { - if (uiBlkType == BHT_NON_LEAF_DATA) - { - pChildBlkAddr = &pStateInfo->pElm [BNE_DATA_CHILD_BLOCK]; - } - else - { - pChildBlkAddr = &pStateInfo->pElm [BNE_CHILD_BLOCK]; - } - uiChildBlkAddress = (FLMUINT)FB2UD( pChildBlkAddr ); - - /* - Check the child sub-tree -- NOTE, this is a recursive call. - First see if we have a pucResetKey that we want to position - to. If so, make sure we are positioned to it before - descending to the child block. - */ - - if (bProcessElm) - { - if (!bDescendToChildBlocks) - { - rc = FERR_OK; - } - else - { - rc = chkVerifySubTree( pDbInfo, pIxChkInfo, pStateInfo, - (pStateInfo - 1), uiChildBlkAddress, pTmpPool, - pucResetKey, uiResetKeyLen, uiResetDrn); - } - - if ((RC_BAD( rc)) || - (RC_BAD( pDbInfo->LastStatusRc)) || - (pDbInfo->bReposition)) - { - goto Exit; - } - - /* - Once we reach the key, set it to an empty to key so that - we will always descend to the child block after this point. - */ - - uiResetKeyLen = 0; - pucResetKey = NULL; - uiResetDrn = 0; - } - - /* Save the child block address in the level information. */ - - pStateInfo->uiLastChildAddr = uiChildBlkAddress; - } - } - - /* - If we were resetting on this element, restore the statistics to what - they were before. - */ - - if (!bCountElm) - { - pStateInfo->ui64KeyCount = ui64SaveKeyCount; - pStateInfo->ui64KeyRefs = ui64SaveKeyRefs; - f_memcpy( &pStateInfo->BlkInfo, &SaveBlkInfo, sizeof( BLOCK_INFO)); - } - - /* Go to the next element. */ - - pStateInfo->uiElmOffset += pStateInfo->uiElmLen; - } - - /* Verify that we ended exactly on the end of the block. */ - - if ((eLastCorruptCode == FLM_NO_CORRUPTION) && - (pStateInfo->uiEndOfBlock >= BH_OVHD) && - (pStateInfo->uiEndOfBlock <= uiBlockSize) && - (pStateInfo->uiElmOffset > pStateInfo->uiEndOfBlock)) - { - eLastCorruptCode = FLM_BAD_ELM_END; - uiNumErrors++; - chkReportError( pDbInfo, eLastCorruptCode, LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, - pStateInfo->uiElmOffset, 0, 0xFFFF, 0, - pBlk); - } - - /* Verify that the last key in the block matches the parent's key. */ - - if ((eLastCorruptCode == FLM_NO_CORRUPTION) && (pParentState) && - (RC_OK( pDbInfo->LastStatusRc))) - { - if ((pStateInfo->bValidKey) && (pParentState->bValidKey) && - (flmCompareKeys( pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, - pParentState->pCurKey, - pParentState->uiCurKeyLen) != 0)) - { - eLastCorruptCode = FLM_BAD_PARENT_KEY; - uiNumErrors++; - chkReportError( pDbInfo, eLastCorruptCode, LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiLevel, uiBlkAddress, - uiParentBlkAddress, - 0, 0, 0xFFFF, 0, pBlk); - } - } - -fix_state: - - /* - If the block could not be verified, set the level's next block - address and last child address to zero to indicate that we really - aren't sure we're at the right place in this level in the B-TREE. - */ - - if (eLastCorruptCode != FLM_NO_CORRUPTION) - { - pStateInfo->BlkInfo.eCorruption = eLastCorruptCode; - pStateInfo->BlkInfo.uiNumErrors += uiNumErrors; - - /* - Reset all child block states. - */ - - for( ;;) - { - pStateInfo->uiNextBlkAddr = 0; - pStateInfo->uiLastChildAddr = 0; - pStateInfo->bValidKey = FALSE; - pStateInfo->uiElmLastFlag = 0xFF; - - /* - Quit when the leaf level has been reached. - */ - - if( pStateInfo->uiLevel == 0) - { - break; - } - pStateInfo--; - } - } - -Exit: - - if( pSCache) - { - ScaReleaseCache( pSCache, FALSE); - } - else if( pBlk) - { - f_free( &pBlk); - } - - pStateInfo->pBlk = NULL; - - return( rc); -} - -/*************************************************************************** -Desc: This routine reads the LFH areas from disk to make sure they are up - to date in memory. -*****************************************************************************/ -FSTATIC RCODE chkGetLfInfo( - DB_INFO * pDbInfo, - POOL * pPool, - LF_STATS * pLfStats, - LFILE * pLFile, - LF_STATS * pCurrLfStats, - FLMBOOL * pbCurrLfLevelChangedRV) -{ - SCACHE * pSCache = NULL; - FLMBYTE * pBlk = NULL; - FLMUINT uiSaveLevel; - eCorruptionType eBlkCorruptionCode; - RCODE rc = FERR_OK; - - /* Read in the block containing the logical file header. */ - - if (RC_BAD( rc = chkBlkRead( pDbInfo, - pLFile->uiBlkAddress, pLFile, &pBlk, &pSCache, - &eBlkCorruptionCode))) - { - - /* Log the error. */ - - if (eBlkCorruptionCode != FLM_NO_CORRUPTION) - { - - //Bug #22003 - chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_LFH_LIST, - 0, 0, 0xFF, - pLFile->uiBlkAddress, 0, 0, 0, - 0xFFFF, 0, pBlk); - } - goto Exit; - } - - /* Copy the LFH from the block to the LFILE. */ - - uiSaveLevel = pLfStats->uiNumLevels; - if (RC_BAD( rc = flmBufferToLFile( - &pBlk[ pLFile->uiOffsetInBlk], pLFile, - pLFile->uiBlkAddress, - pLFile->uiOffsetInBlk))) - { - goto Exit; - } - - /* - Read root block to get the number of levels in the B-TREE - */ - - if (pLFile->uiRootBlk == BT_END) - { - pLfStats->uiNumLevels = 0; - } - else - { - if (RC_BAD( rc = chkBlkRead( pDbInfo, - pLFile->uiRootBlk, pLFile, &pBlk, &pSCache, - &eBlkCorruptionCode))) - { - if (eBlkCorruptionCode != FLM_NO_CORRUPTION) - { - //Bug #22003 - chkReportError( pDbInfo, eBlkCorruptionCode, LOCALE_B_TREE, - pLFile->uiLfNum, pLFile->uiLfType, 0xFF, - pLFile->uiRootBlk, 0, 0, 0, - 0xFFFF, 0, pBlk); - } - goto Exit; - } - pLfStats->uiNumLevels = (FLMUINT)(pBlk [BH_LEVEL]) + 1; - - /* - GW Bug 55264: Need to make sure that the level extracted from - the block is valid. - */ - - if( pBlk [BH_LEVEL] >= BH_MAX_LEVELS) - { - chkReportError( pDbInfo, FLM_BAD_BLK_HDR_LEVEL, LOCALE_B_TREE, - pLFile->uiLfNum, pLFile->uiLfType, - (FLMUINT)(pBlk [BH_LEVEL]), - pLFile->uiRootBlk, 0, 0, 0, - 0xFFFF, 0, pBlk); - /* - Force pLfStats->uiNumLevels to 1 so that we don't crash - */ - - pLfStats->uiNumLevels = 1; - } - } - - /* - If the number of levels changed, reset the level information - on this logical file. - */ - - if (uiSaveLevel != pLfStats->uiNumLevels && pLfStats->uiNumLevels) - { - if (pLfStats->uiNumLevels > uiSaveLevel) - { - if ((pLfStats->pLevelInfo = - (LEVEL_INFO *)GedPoolCalloc( pPool, - (FLMUINT)(sizeof( LEVEL_INFO) * pLfStats->uiNumLevels))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - if (pCurrLfStats == pLfStats) - { - *pbCurrLfLevelChangedRV = TRUE; - } - } - -Exit: - - if( pSCache) - { - ScaReleaseCache( pSCache, FALSE); - } - else if( pBlk) - { - f_free( &pBlk); - } - - return( rc); -} - - -/*************************************************************************** -Desc: This routine allocates and initializes the LF table (array of - LF_HDR structures). -*****************************************************************************/ -FSTATIC RCODE chkSetupLfTable( - DB_INFO * pDbInfo, - POOL * pPool) -{ - FLMUINT uiCnt; - FLMUINT uiNumIndexes = 0; - FLMUINT uiIxStart; - FLMUINT uiNumDataCont = 0; - FLMUINT uiNumDictCont = 0; - FLMUINT uiIxOffset; - FLMUINT uiDataOffset; - FLMUINT uiDictOffset; - FDB * pDb = pDbInfo->pDb; - LFILE * pLFile; - LFILE * pTmpLFile; - LF_HDR * pLogicalFile; - LF_STATS * pLfStats; - RCODE rc = FERR_OK; - - /* - Set up the table such that the dictionary is checked first, - followed by data containers, and then indexes. This is - necessary for the logical (index) check to work. The - data records must be extracted before the indexes are - checked so that the temporary result set, used during - the logical check, can be built. - */ - - pDbInfo->pProgress->uiNumFields = - pDbInfo->pProgress->uiNumIndexes = - pDbInfo->pProgress->uiNumContainers = 0; - pDbInfo->pProgress->uiNumLogicalFiles = - (FLMUINT)((pDb->pDict) - ? (FLMUINT)pDb->pDict->uiLFileCnt - : (FLMUINT)0); - - /* Determine the number of fields. */ - - if (pDb->pDict) - { - chkCountFields( pDb->pDict, &pDbInfo->pProgress->uiNumFields); - - for (uiCnt = 0, pLFile = (LFILE *)pDb->pDict->pLFileTbl; - uiCnt < pDb->pDict->uiLFileCnt; - uiCnt++, pLFile++) - { - if (pLFile->uiLfType == LF_INDEX) - { - pDbInfo->pProgress->uiNumIndexes++; - uiNumIndexes++; - } - else - { - pDbInfo->pProgress->uiNumContainers++; - if( pLFile->uiLfNum == FLM_DICT_CONTAINER) - { - uiNumDictCont++; - } - else - { - uiNumDataCont++; - } - } - } - } - - /* Allocate memory for each LFILE, then set up each LFILE. */ - - if (!pDbInfo->pProgress->uiNumLogicalFiles) - { - pDbInfo->pLogicalFiles = NULL; - pDbInfo->pProgress->pLfStats = NULL; - } - else - { - if ((pDbInfo->pLogicalFiles = - (LF_HDR *)GedPoolCalloc( pPool, - (FLMUINT)(sizeof( LF_HDR) * - pDbInfo->pProgress->uiNumLogicalFiles))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - if ((pDbInfo->pProgress->pLfStats = - (LF_STATS *)GedPoolCalloc( pPool, - (FLMUINT)(sizeof( LF_STATS) * - pDbInfo->pProgress->uiNumLogicalFiles))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - uiDictOffset = 0; - uiDataOffset = uiNumDictCont; - uiIxOffset = uiDataOffset + uiNumDataCont; - uiIxStart = uiIxOffset; - - for (uiCnt = 0, pTmpLFile = (LFILE *)pDb->pDict->pLFileTbl; - uiCnt < pDbInfo->pProgress->uiNumLogicalFiles; - uiCnt++, pTmpLFile++) - { - if( pTmpLFile->uiLfType == LF_INDEX) - { - FLMUINT uiTmpIxOffset = uiIxOffset; - - // Indexes need to be in order from lowest to highest - // because the result set is sorted that way. - - while (uiTmpIxOffset > uiIxStart) - { - if (pDbInfo->pLogicalFiles [uiTmpIxOffset - 1].pLFile->uiLfNum < - pTmpLFile->uiLfNum) - { - break; - } - f_memcpy( &pDbInfo->pLogicalFiles [uiTmpIxOffset], - &pDbInfo->pLogicalFiles [uiTmpIxOffset - 1], - sizeof( LF_HDR)); - f_memcpy( &pDbInfo->pProgress->pLfStats [uiTmpIxOffset], - &pDbInfo->pProgress->pLfStats [uiTmpIxOffset - 1], - sizeof( LF_STATS)); - uiTmpIxOffset--; - } - - pLogicalFile = &(pDbInfo->pLogicalFiles[ uiTmpIxOffset]); - pLfStats = &(pDbInfo->pProgress->pLfStats[ uiTmpIxOffset]); - uiIxOffset++; - } - else - { - if( pTmpLFile->uiLfNum == FLM_DICT_CONTAINER) - { - pLogicalFile = &(pDbInfo->pLogicalFiles[ uiDictOffset]); - pLfStats = &(pDbInfo->pProgress->pLfStats[ uiDictOffset]); - uiDictOffset++; - } - else - { - pLogicalFile = &(pDbInfo->pLogicalFiles[ uiDataOffset]); - pLfStats = &(pDbInfo->pProgress->pLfStats[ uiDataOffset]); - uiDataOffset++; - } - } - pLogicalFile->pLfStats = pLfStats; - - /* - Copy the LFILE information - so we can return the - information even after the database has been closed. - */ - - if ((pLogicalFile->pLFile = pLFile = - (LFILE *)GedPoolAlloc( pPool, - (FLMUINT)sizeof( LFILE))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Copy the LFILE structure so we can get enough information - to read them from disk, then read them from disk so we have - a read-consistent view of them. - */ - - f_memcpy( pLFile, pTmpLFile, sizeof( LFILE)); - if (RC_BAD( rc = flmLFileRead( pDb, pLFile))) - { - goto Exit; - } - pLfStats->uiLfType = pLFile->uiLfType; - if (pLFile->uiLfType == LF_INDEX) - { - pLfStats->uiIndexNum = pLFile->uiLfNum; - pLfStats->uiContainerNum = 0; - } - else - { - pLfStats->uiIndexNum = 0; - pLfStats->uiContainerNum = pLFile->uiLfNum; - } - - /* - If the logical file is an index, get pointers to the index - definition and its field definitions. - */ - - if (pLFile->uiLfType == LF_INDEX) - { - IXD * pTmpIxd; - IFD_p pTmpIfd; - - if (RC_BAD( rc = fdictGetIndex( - pDb->pDict, - pDb->pFile->bInLimitedMode, - pLFile->uiLfNum, - NULL, &pTmpIxd, TRUE))) - { - if (rc == FERR_BAD_IX) - { - chkReportError( pDbInfo, FLM_BAD_PCODE_IXD_TBL, - LOCALE_IXD_TBL, - pLFile->uiLfNum, pLFile->uiLfType, - 0xFF, 0, - 0, 0, 0, 0xFFFF, 0, - NULL); - rc = RC_SET( FERR_PCODE_ERROR); - } - - goto Exit; - } - - pTmpIfd = pTmpIxd->pFirstIfd; - - /* - Copy the IXD and IFD information - so we can return the - information even after the database has been closed. - */ - - if ((pLogicalFile->pIxd = (IXD *)GedPoolAlloc( pPool, - (FLMUINT)(sizeof( IXD) + - sizeof( IFD) * pTmpIxd->uiNumFlds))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pLogicalFile->pIfd = (IFD_p)(void *)(&pLogicalFile->pIxd [1]); - f_memcpy( pLogicalFile->pIxd, pTmpIxd, sizeof( IXD)); - f_memcpy( pLogicalFile->pIfd, pTmpIfd, - sizeof( IFD) * pTmpIxd->uiNumFlds); - pLfStats->uiContainerNum = pLogicalFile->pIxd->uiContainerNum; - } - - /* - Get the current number of levels in the logical file and - allocate an array of LEVEL_INFO structures for the levels. - */ - - pLfStats->uiNumLevels = 0; - if (RC_BAD( rc = chkGetLfInfo( pDbInfo, pPool, pLfStats, pLFile, - NULL, NULL))) - { - goto Exit; - } - } - } - -Exit: - - return( rc); -} - - -/*************************************************************************** -Desc: This routine checks all of the B-TREES in the database -- all - indexes and containers. -*****************************************************************************/ -RCODE chkVerifyBTrees( - DB_INFO * pDbInfo, - POOL * pPool, - FLMBOOL * pbStartOverRV) -{ - RCODE rc = FERR_OK; - FDB * pDb = pDbInfo->pDb; - FLMUINT uiCurrLf; - FLMUINT uiCurrLevel; - FLMBYTE * pKeyBuffer = NULL; - FLMUINT uiKeysAllocated = 0; - STATE_INFO State [BH_MAX_LEVELS]; - FLMBOOL bStateInitialized [BH_MAX_LEVELS]; - FLMBYTE ucResetKeyBuff [MAX_KEY_SIZ]; - FLMBYTE * pucResetKey = NULL; - FLMUINT uiResetKeyLen = 0; - FLMUINT uiResetDrn = 0; - LF_HDR * pLogicalFile; - LF_STATS * pLfStats; - LFILE * pLFile; - FLMUINT uiSaveDictSeq; - FLMUINT uiTmpLf; - LF_STATS * pTmpLfStats; - POOL tmpPool; - FLMBOOL bRSFinalized = FALSE; - DB_CHECK_PROGRESS * pProgress = pDbInfo->pProgress; - IX_CHK_INFO IxChkInfo; - IX_CHK_INFO * pIxChkInfo = NULL; - void * pvPoolMark; - FILE_HDR * pFileHdr = &pDb->pFile->FileHdr; - - for (uiCurrLevel = 0; uiCurrLevel < BH_MAX_LEVELS; uiCurrLevel++) - { - bStateInitialized [uiCurrLevel] = FALSE; - } - - if (*pbStartOverRV) - { - goto Exit; - } - - pvPoolMark = GedPoolMark( pPool); - uiSaveDictSeq = pDb->pDict->uiDictSeq; - - if( RC_BAD( rc = chkSetupLfTable( pDbInfo, pPool))) - { - goto Exit; - } - - if( pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) - { - if( RC_BAD( rc = chkSetupIxInfo( pDbInfo, &IxChkInfo))) - { - goto Exit; - } - pIxChkInfo = &IxChkInfo; - } - - /* - Loop through all of the logical files in the database - and perform a structural and logical check. - */ - - uiCurrLf = 0; - while (uiCurrLf < pDbInfo->pProgress->uiNumLogicalFiles) - { - pProgress->uiCurrLF = uiCurrLf + 1; - pLogicalFile = &pDbInfo->pLogicalFiles [uiCurrLf]; - pLfStats = &pDbInfo->pProgress->pLfStats [uiCurrLf]; - pLFile = pLogicalFile->pLFile; - if (pLFile->uiRootBlk == BT_END) - { - rc = FERR_OK; - uiCurrLf++; - uiResetKeyLen = 0; - pucResetKey = NULL; - uiResetDrn = 0; - continue; - } - - /* Allocate space to hold the keys, if not already allocated. */ - - if (uiKeysAllocated < pLfStats->uiNumLevels) - { - - /* If there is already a key allocated, deallocate it */ - - if (pKeyBuffer) - { - f_free( &pKeyBuffer); - uiKeysAllocated = 0; - } - - if( RC_BAD( rc = f_alloc( - pLfStats->uiNumLevels * MAX_KEY_SIZ, &pKeyBuffer))) - { - goto Exit; - } - uiKeysAllocated = pLfStats->uiNumLevels; - } - - /* Setup PROGRESS_CHECK_INFO structure */ - - pProgress->iCheckPhase = CHECK_B_TREE; - pProgress->bStartFlag = TRUE; - pProgress->uiLfNumber = pLFile->uiLfNum; - pProgress->uiLfType = pLFile->uiLfType; - - if( pLFile->uiLfType == LF_INDEX) - { - pProgress->bUniqueIndex = (pLogicalFile->pIxd->uiFlags & IXD_UNIQUE) ? TRUE : FALSE; - } - - if (RC_BAD( rc = chkCallProgFunc( pDbInfo))) - { - break; - } - - pProgress->bStartFlag = FALSE; - - f_yieldCPU(); - - - /* Initialize the state information for each level of the B-TREE. */ - - for (uiCurrLevel = 0; uiCurrLevel < pLfStats->uiNumLevels; uiCurrLevel++) - { - - /* - If we are resetting to a particular key, save the statistics - which were gathered so far. - */ - - if (uiResetKeyLen) - { - - /* Save the statistics which were gathered. */ - - pLfStats->pLevelInfo [uiCurrLevel].ui64KeyCount = - State [uiCurrLevel].ui64KeyCount; - f_memcpy( &pLfStats->pLevelInfo [uiCurrLevel].BlockInfo, - &State [uiCurrLevel].BlkInfo, sizeof( BLOCK_INFO)); - } - - flmInitReadState( &State [uiCurrLevel], &bStateInitialized [uiCurrLevel], - pFileHdr->uiVersionNum, - pDb, pLogicalFile, uiCurrLevel, - (FLMUINT)((!uiCurrLevel) - ? (FLMUINT)BHT_LEAF - : (FLMUINT)BHT_NON_LEAF), - &pKeyBuffer [uiCurrLevel * MAX_KEY_SIZ]); - - if (!uiResetKeyLen) - { - State [uiCurrLevel].uiLastChildAddr = BT_END; - State [uiCurrLevel].uiElmLastFlag = TRUE; - } - else - { - - /* Restore the statistics which were gathered so far. */ - - State [uiCurrLevel].ui64KeyCount = - pLfStats->pLevelInfo [uiCurrLevel].ui64KeyCount; - f_memcpy( &State [uiCurrLevel].BlkInfo, - &pLfStats->pLevelInfo [uiCurrLevel].BlockInfo, - sizeof( BLOCK_INFO)); - } - } - - /* - Need to finalize the result set used by the logical - check. If the current logical file is an index and the - result set has not been finalized, call chkRSFinalize. - */ - - if( !pDbInfo->pProgress->bPhysicalCorrupt && - (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) && - bRSFinalized == FALSE && pLFile->uiLfType == LF_INDEX) - { - FLMUINT64 ui64NumRSKeys = 0; - - /* - Finalize the result set. - */ - - if( RC_BAD( rc = chkRSFinalize( pIxChkInfo, &ui64NumRSKeys))) - { - goto Exit; - } - - /* - Reset uiNumKeys to reflect the number of keys - in the result set now that all duplicates have - been eliminated. - */ - - if( pDbInfo->pProgress->ui64NumKeys > ui64NumRSKeys) - { - pDbInfo->pProgress->ui64NumDuplicateKeys = - pDbInfo->pProgress->ui64NumKeys - ui64NumRSKeys; - } - pDbInfo->pProgress->ui64NumKeys = ui64NumRSKeys; - - /* - Set bRSFinalized to TRUE so that subsequent passes will not - attempt to finalize the result set again. - */ - - bRSFinalized = TRUE; - } - - /* - Call chkVerifySubTree to check the B-TREE starting at the - root block. - */ - - GedPoolInit( &tmpPool, 512); - pDbInfo->bReposition = FALSE; - rc = chkVerifySubTree( pDbInfo, pIxChkInfo, NULL, - &State [pLfStats->uiNumLevels - 1], - pLFile->uiRootBlk, &tmpPool, - pucResetKey, uiResetKeyLen, uiResetDrn); - GedPoolFree( &tmpPool); - - if (rc == FERR_OLD_VIEW) - { - - // If it is a read transaction, reset. - - if( flmGetDbTransType( pDb) == FLM_READ_TRANS) - { - - // Free the KrefCntrl - - KrefCntrlFree( pDb); - - // Abort the read transaction - - if( RC_BAD( rc = flmAbortDbTrans( pDb))) - { - goto Exit; - } - - // Try to start a new read transaction - - if( RC_BAD( rc = flmBeginDbTrans( pDb, - FLM_READ_TRANS, 0, FLM_DONT_POISON_CACHE))) - { - goto Exit; - } - } - rc = FERR_OK; - pDbInfo->bReposition = TRUE; - } - if (RC_BAD( rc)) - { - goto Exit; - } - - // We may get told to reposition if we had to repair - // an index or we got an old view error. - - if (pDbInfo->bReposition) - { - - /* If the dictionary has changed we must start all over. */ - - if (pDb->pDict->uiDictSeq != uiSaveDictSeq) - { - *pbStartOverRV = TRUE; - goto Exit; - } - - /* - Save the current key at the bottom level of the B-Tree. - This is the point we want to try to reset to. Don't change - the reset key if the current key length is zero - this may - have occurred because of some error - we want to keep moving - forward in the file if at all possible. - */ - - if (State [0].uiCurKeyLen) - { - uiResetKeyLen = State [0].uiCurKeyLen; - pucResetKey = &ucResetKeyBuff [0]; - uiResetDrn = State [0].uiCurrIxRefDrn; - f_memcpy( pucResetKey, State [0].pCurKey, uiResetKeyLen); - } - - // Re-read each logical file's LFH information. - - pProgress->ui64DatabaseSize = - FSGetSizeInBytes( pDb->pFile->uiMaxFileSize, - pDb->LogHdr.uiLogicalEOF); - - /* - Reread each of the LFH blocks and update the root block - address and other pertinent information for each logical - file. - */ - - for (uiTmpLf = 0, pTmpLfStats = pDbInfo->pProgress->pLfStats; - uiTmpLf < pDbInfo->pProgress->uiNumLogicalFiles; - uiTmpLf++, pTmpLfStats++) - { - FLMBOOL bCurrLfLevelChanged = FALSE; - - if (RC_BAD( rc = chkGetLfInfo( pDbInfo, pPool, - pTmpLfStats, pDbInfo->pLogicalFiles [uiTmpLf].pLFile, - pLfStats, &bCurrLfLevelChanged))) - { - goto Exit; - } - - /* - If the number of levels for the current logical file - changed, reset things so we will recheck the entire logical - file. - */ - - if (bCurrLfLevelChanged) - { - pucResetKey = NULL; - uiResetKeyLen = 0; - } - } - continue; - } - - /* - Verify that all of the levels' next block address's - are BT_END. - */ - - if (RC_OK( pDbInfo->LastStatusRc)) - { - for (uiCurrLevel = 0; uiCurrLevel < pLfStats->uiNumLevels; uiCurrLevel++) - { - - /* Save the statistics which were gathered. */ - - pLfStats->pLevelInfo [uiCurrLevel].ui64KeyCount = - State [uiCurrLevel].ui64KeyCount; - f_memcpy( &pLfStats->pLevelInfo [uiCurrLevel].BlockInfo, - &State [uiCurrLevel].BlkInfo, sizeof( BLOCK_INFO)); - - /* - Make sure the last block had a NEXT block address - of BT_END. - */ - - if ((State [uiCurrLevel].uiNextBlkAddr) && - (State [uiCurrLevel].uiNextBlkAddr != BT_END)) - { - chkReportError( pDbInfo, FLM_BAD_LAST_BLK_NEXT, - LOCALE_B_TREE, - pDbInfo->pProgress->uiLfNumber, - pDbInfo->pProgress->uiLfType, - uiCurrLevel, 0, 0, 0, 0, - 0xFFFF, 0, NULL); - } - } - } - - if (RC_BAD( pDbInfo->LastStatusRc)) - { - break; - } - - uiCurrLf++; - pucResetKey = NULL; - uiResetKeyLen = 0; - uiResetDrn = 0; - - } - - /* - If index check was requested, no structural corruptions - were detected, and this is the last logical file, need to make - sure that the result set is empty. - */ - - if( RC_OK( rc) && !pDbInfo->pProgress->bPhysicalCorrupt && - (pDbInfo->uiFlags & FLM_CHK_INDEX_REFERENCING) && - bRSFinalized == TRUE && - uiCurrLf == pDbInfo->pProgress->uiNumLogicalFiles) - { - for( ;;) - { - if( RC_BAD( rc = chkGetNextRSKey( pIxChkInfo))) - { - if( rc == FERR_EOF_HIT || rc == FERR_NOT_FOUND) - { - rc = FERR_OK; - break; - } - goto Exit; - } - else - { - /* Updated statistics */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumKeysExamined++; - - if( RC_BAD( rc = chkResolveIXMissingKey( - &(State[ 0]), pIxChkInfo))) - { - goto Exit; - } - } - } - } - - /* Clear the unique index flag */ - - pProgress->bUniqueIndex = FALSE; - -Exit: - - // Clear the pRecord for each level in the state array. - - for (uiCurrLevel = 0; uiCurrLevel < BH_MAX_LEVELS; uiCurrLevel++) - { - if (bStateInitialized [uiCurrLevel] && State [uiCurrLevel].pRecord) - { - State [uiCurrLevel].pRecord->Release(); - State [uiCurrLevel].pRecord = NULL; - } - } - - /* Cleanup any temporary index check files */ - - if( pIxChkInfo != NULL) - { - chkFreeIxInfo( pIxChkInfo); - } - - if (pKeyBuffer) - { - f_free( &pKeyBuffer); - } - - if (RC_OK( rc) && RC_BAD( pDbInfo->LastStatusRc)) - { - rc = pDbInfo->LastStatusRc; - } - - return( rc); -} - - -/******************************************************************** -Desc: -*********************************************************************/ -RCODE chkReportError( - DB_INFO * pDbInfo, - eCorruptionType eCorruption, - eCorruptionLocale eErrLocale, - FLMUINT uiErrLfNumber, - FLMUINT uiErrLfType, - FLMUINT uiErrBTreeLevel, - FLMUINT uiErrBlkAddress, - FLMUINT uiErrParentBlkAddress, - FLMUINT uiErrElmOffset, - FLMUINT uiErrDrn, - FLMUINT uiErrElmRecOffset, - FLMUINT uiErrFieldNum, - FLMBYTE * pBlk) -{ - CORRUPT_INFO CorruptInfo; - FLMBOOL bFixErr; - - CorruptInfo.eCorruption = eCorruption; - CorruptInfo.eErrLocale = eErrLocale; - CorruptInfo.uiErrLfNumber = uiErrLfNumber; - CorruptInfo.uiErrLfType = uiErrLfType; - CorruptInfo.uiErrBTreeLevel = uiErrBTreeLevel; - CorruptInfo.uiErrBlkAddress = uiErrBlkAddress; - CorruptInfo.uiErrParentBlkAddress = uiErrParentBlkAddress; - CorruptInfo.uiErrElmOffset = uiErrElmOffset; - CorruptInfo.uiErrDrn = uiErrDrn; - CorruptInfo.uiErrElmRecOffset = uiErrElmRecOffset; - CorruptInfo.uiErrFieldNum = uiErrFieldNum; - CorruptInfo.pBlk = pBlk; - CorruptInfo.pErrIxKey = NULL; - CorruptInfo.pErrRecord = NULL; - CorruptInfo.pErrRecordKeyList = NULL; - if ((pDbInfo->fnStatusFunc) && (RC_OK( pDbInfo->LastStatusRc))) - { - bFixErr = FALSE; - pDbInfo->LastStatusRc = (*pDbInfo->fnStatusFunc)( FLM_PROBLEM_STATUS, - (void *)&CorruptInfo, - (void *)&bFixErr, - pDbInfo->pProgress->AppArg); - } - if (eCorruption != FLM_OLD_VIEW) - { - pDbInfo->pProgress->bPhysicalCorrupt = TRUE; - pDbInfo->uiFlags &= ~FLM_CHK_INDEX_REFERENCING; - } - - return( pDbInfo->LastStatusRc); -} - -/*************************************************************************** -Desc: Initializes an IX_CHK_INFO structure -*****************************************************************************/ -FSTATIC RCODE chkSetupIxInfo( - DB_INFO * pDbInfo, - IX_CHK_INFO * pIxInfoRV - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiIxCount = 0; - FLMUINT uiIxNum = 0; - IXD * pIxd; - LFILE * pLFile; - char szTmpIoPath [F_PATH_MAX_SIZE]; - char szBaseName [F_FILENAME_SIZE]; - FDB * pDb = pDbInfo->pDb; - - f_memset( pIxInfoRV, 0, sizeof( IX_CHK_INFO)); - GedPoolInit( &(pIxInfoRV->pool), 512); - pIxInfoRV->pDbInfo = pDbInfo; - - /* Set up the result set path */ - - if( RC_BAD( rc = flmGetTmpDir( szTmpIoPath))) - { - if( rc == FERR_IO_PATH_NOT_FOUND || - rc == FERR_IO_INVALID_PATH) - { - if( RC_BAD( rc = f_pathReduce( pDb->pFile->pszDbPath, - szTmpIoPath, szBaseName))) - { - goto Exit; - } - } - else - { - goto Exit; - } - } - - /* - Initialize the result set. The result set will be used - to build an ordered list of keys for comparision to - the database's indexes. - */ - - if( RC_BAD( rc = chkRSInit( szTmpIoPath, &(pIxInfoRV->pRSet)))) - { - goto Exit; - } - - /* Build list of all indexes */ - - uiIxCount = 0; - if( pDb->pDict) - { - uiIxCount += pDb->pDict->uiIxdCnt; - } - - /* - Allocate memory to save each index number and its associated - container number. - */ - - if( RC_BAD( rc = f_alloc( - (FLMUINT)((sizeof( FLMUINT) * uiIxCount) + (sizeof( FLMBOOL) * uiIxCount)), - &(pIxInfoRV->puiIxArray)))) - { - goto Exit; - } - - /* Save the index numbers into the array. */ - - uiIxCount = 0; - if( pDb->pDict) - { - for( uiIxNum = 0, pIxd = (IXD *)pDb->pDict->pIxdTbl; - uiIxNum < pDb->pDict->uiIxdCnt; - uiIxNum++, pIxd++) - { - pIxInfoRV->puiIxArray[ uiIxCount] = pIxd->uiIndexNum; - uiIxCount++; - } - } - - if( RC_OK( fdictGetIndex( pDb->pDict, - pDb->pFile->bInLimitedMode, - FLM_DICT_INDEX, &pLFile, NULL))) - { - pIxInfoRV->puiIxArray[ uiIxCount] = FLM_DICT_INDEX; - uiIxCount++; - } - - pIxInfoRV->uiIxCount = uiIxCount; - pIxInfoRV->bGetNextRSKey = TRUE; - -Exit: - - /* - Clean up any memory on error exit. - */ - - if( RC_BAD( rc)) - { - GedPoolFree( &(pIxInfoRV->pool)); - if( pIxInfoRV->puiIxArray) - { - f_free( &(pIxInfoRV->puiIxArray)); - } - } - - return( rc); -} - -/******************************************************************** -Desc: Outputs keys to the temporary result set -*********************************************************************/ -FSTATIC RCODE chkOutputIndexKeys( - STATE_INFO * pStateInfo, - IX_CHK_INFO * pIxChkInfo, - IXD * pIxd, - REC_KEY * pKeyList - ) -{ - FLMUINT uiKeyLen; - REC_KEY * pKey; - FLMBYTE ucBuf[ MAX_KEY_SIZ + RS_KEY_OVERHEAD]; - RCODE rc = FERR_OK; - - - pKey = pKeyList; - while( pKey) - { - /* Set the index and reference */ - - UW2FBA( (FLMUINT16)pIxd->uiIndexNum, &(ucBuf[ RS_IX_OFFSET])); - UD2FBA( (FLMUINT32)pStateInfo->uiElmDrn, &(ucBuf[ RS_REF_OFFSET])); - - /* Convert the key tree to a collation key */ - - if( RC_BAD( rc = KYTreeToKey( pIxChkInfo->pDbInfo->pDb, - pIxd, pKey->pKey, pKey->pKey->getContainerID(), - &(ucBuf[ RS_KEY_OVERHEAD]), &uiKeyLen, 0))) - { - goto Exit; - } - - /* Add the composite key (index, ref, key) to the result set */ - - if( RC_BAD( rc = chkRSAddEntry( pIxChkInfo->pRSet, ucBuf, - uiKeyLen + RS_KEY_OVERHEAD))) - { - goto Exit; - } - - /* - Update statistics. Note that uiNumKeys will reflect the - total number of keys generated by records, including any - duplicate keys. This value is updated to reflect the - correct number of keys once the result set has been finalized. - */ - - pIxChkInfo->pDbInfo->pProgress->ui64NumKeys++; - pKey = pKey->pNextKey; - } - -Exit: - - return( rc); -} diff --git a/flaim/src/flclose.cpp b/flaim/src/flclose.cpp index 50269c0..621ffec 100644 --- a/flaim/src/flclose.cpp +++ b/flaim/src/flclose.cpp @@ -41,7 +41,7 @@ RCODE flmDbClose( if (IsInCSMode( pDb)) { - CS_CONTEXT_p pCSContext = pDb->pCSContext; + CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( pCSContext->bConnectionGood) diff --git a/flaim/src/flconvrt.cpp b/flaim/src/flconvrt.cpp index 66c0b0e..e130ca0 100644 --- a/flaim/src/flconvrt.cpp +++ b/flaim/src/flconvrt.cpp @@ -24,9 +24,9 @@ #include "flaimsys.h" -/*API~*********************************************************************** +/**************************************************************************** Desc: Upgrades a database to the latest FLAIM version. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbUpgrade( HFDB hDb, FLMUINT uiNewVersion, @@ -90,13 +90,14 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( switch (uiOldVersion) { - case FLM_VER_3_0: - case FLM_VER_3_02: - case FLM_VER_4_0: - case FLM_VER_4_3: - case FLM_VER_4_31: - case FLM_VER_4_50: - case FLM_VER_4_51: + case FLM_FILE_FORMAT_VER_3_0: + case FLM_FILE_FORMAT_VER_3_02: + case FLM_FILE_FORMAT_VER_4_0: + case FLM_FILE_FORMAT_VER_4_3: + case FLM_FILE_FORMAT_VER_4_31: + case FLM_FILE_FORMAT_VER_4_50: + case FLM_FILE_FORMAT_VER_4_51: + case FLM_FILE_FORMAT_VER_4_60: // Upgrades from these versions are supported. @@ -108,12 +109,13 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( switch (uiNewVersion) { - case FLM_VER_4_3: - case FLM_VER_4_31: - case FLM_VER_4_50: - case FLM_VER_4_51: - case FLM_CURRENT_VERSION_NUM: - + case FLM_FILE_FORMAT_VER_4_3: + case FLM_FILE_FORMAT_VER_4_31: + case FLM_FILE_FORMAT_VER_4_50: + case FLM_FILE_FORMAT_VER_4_51: + case FLM_FILE_FORMAT_VER_4_60: + case FLM_CUR_FILE_FORMAT_VER_NUM: + { // Verify that we can do the upgrade if (uiNewVersion < uiOldVersion) @@ -123,15 +125,19 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( } else if (uiNewVersion == uiOldVersion) { - // No need to do upgrade - already there. goto Exit; } + break; + } + default: + { rc = RC_SET( FERR_UNALLOWED_UPGRADE); goto Exit; + } } // Save the state of RFL logging flag. @@ -209,13 +215,14 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( // If version is prior to 4.0, upgrade the non-leaf blocks in // container B-Trees. - if (uiOldVersion < FLM_VER_4_0 && uiNewVersion >= FLM_VER_4_0) + if (uiOldVersion < FLM_FILE_FORMAT_VER_4_0 && + uiNewVersion >= FLM_FILE_FORMAT_VER_4_0) { // Upgrade non-leaf blocks in container B-Trees. - if (RC_BAD( rc = FSVersionConversion40( pDb, FLM_CURRENT_VERSION_NUM, - fnStatusCallback, UserData))) + if (RC_BAD( rc = FSVersionConversion40( pDb, + FLM_CUR_FILE_FORMAT_VER_NUM, fnStatusCallback, UserData))) { goto Exit; } @@ -223,7 +230,8 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( // If versions is pre-4.3, upgrade log header and RFL stuff. - if (uiOldVersion < FLM_VER_4_3 && uiNewVersion >= FLM_VER_4_3) + if (uiOldVersion < FLM_FILE_FORMAT_VER_4_3 && + uiNewVersion >= FLM_FILE_FORMAT_VER_4_3) { // Initialize backup options @@ -332,7 +340,8 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( bExpandingFileCount = TRUE; } - if (uiOldVersion < FLM_VER_4_31 && uiNewVersion >= FLM_VER_4_31) + if (uiOldVersion < FLM_FILE_FORMAT_VER_4_31 && + uiNewVersion >= FLM_FILE_FORMAT_VER_4_31) { // NOTE: We could really set the LOG_LAST_RFL_COMMIT_ID to anything, @@ -346,7 +355,8 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( #ifdef FLM_USE_NICI - if (uiOldVersion < FLM_VER_4_60 && uiNewVersion >= FLM_VER_4_60) + if (uiOldVersion < FLM_FILE_FORMAT_VER_4_60 && + uiNewVersion >= FLM_FILE_FORMAT_VER_4_60) { if( RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE))) @@ -415,7 +425,8 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( // Makes no sense before that because prior to 4.30 there was no // possibility of keeping RFL files and doing a restore from them. - if (!(pDb->uiFlags & FDB_REPLAYING_RFL) && uiOldVersion >= FLM_VER_4_3) + if (!(pDb->uiFlags & FDB_REPLAYING_RFL) && + uiOldVersion >= FLM_FILE_FORMAT_VER_4_3) { // We would have turned logging OFF above, so we need to // turn it back on here. @@ -469,7 +480,8 @@ FLMEXP RCODE FLMAPI FlmDbUpgrade( // Set up to use a new RFL directory. Must do this only after // setting FileHdr.uiVersionNum above. - if (uiOldVersion < FLM_VER_4_3 && uiNewVersion >= FLM_VER_4_3) + if (uiOldVersion < FLM_FILE_FORMAT_VER_4_3 && + uiNewVersion >= FLM_FILE_FORMAT_VER_4_3) { char szTmpName [F_PATH_MAX_SIZE]; @@ -547,9 +559,9 @@ Exit: return( rc ); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Adds an encryption key to the database. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmEnableEncryption( HFDB hDb, FLMBYTE ** ppucWrappingKeyRV, @@ -565,7 +577,7 @@ FLMEXP RCODE FLMAPI FlmEnableEncryption( FLMUINT uiFlags = FLM_GET_TRANS_FLAGS( FLM_UPDATE_TRANS); FLMBOOL bTransBegun = FALSE; - // We must will start our own transaction. Then we will force a checkpoint + // We must start our own transaction. Then we will force a checkpoint // when we commit the transaction if ( pDb->uiTransType != FLM_NO_TRANS) @@ -675,10 +687,10 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Changes the way the database key is stored in the database. Either it is encrypted using a password or it is wrapped in the server key. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbWrapKey( HFDB hDb, const char * pszPassword) diff --git a/flaim/src/flcreate.cpp b/flaim/src/flcreate.cpp index f704bff..ddad5e1 100644 --- a/flaim/src/flcreate.cpp +++ b/flaim/src/flcreate.cpp @@ -40,9 +40,9 @@ FSTATIC RCODE flmInitFileHdrs( FLMBYTE * pInitBuf, FLMUINT uiBufSize); -/*API~*********************************************************************** +/**************************************************************************** Desc : Creates a new FLAIM database. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbCreate( const char * pszDbFileName, const char * pszDataDir, @@ -55,7 +55,10 @@ FLMEXP RCODE FLMAPI FlmDbCreate( RCODE rc = FERR_OK; CS_CONTEXT * pCSContext; - *phDbRV = HFDB_NULL; + if( phDbRV) + { + *phDbRV = HFDB_NULL; + } if( !pszDbFileName || !pszDbFileName[ 0]) { @@ -74,7 +77,7 @@ FLMEXP RCODE FLMAPI FlmDbCreate( if( RC_BAD( rc = flmOpenOrCreateDbClientServer( pszDbFileName, pszDataDir, pszRflDir, 0, pszDictFileName, - pszDictBuf, pCreateOpts, FALSE, pCSContext, (FDB_p *)phDbRV))) + pszDictBuf, pCreateOpts, FALSE, pCSContext, (FDB * *)phDbRV))) { (void)flmCloseCSConnection( &pCSContext); } @@ -83,7 +86,7 @@ FLMEXP RCODE FLMAPI FlmDbCreate( if( RC_BAD( rc = flmCreateNewFile( pszDbFileName, pszDataDir, pszRflDir, pszDictFileName, pszDictBuf, pCreateOpts, - 0, (FDB_p *)phDbRV))) + 0, (FDB * *)phDbRV))) { goto Exit; } @@ -104,18 +107,20 @@ RCODE flmCreateNewFile( const char * pszDictBuf, CREATE_OPTS * pCreateOpts, FLMUINT uiTransID, - FDB_p * ppDb, + FDB * * ppDb, REBUILD_STATE * pRebuildState) { RCODE rc = FERR_OK; - FDB * pDb; + FDB * pDb = NULL; FFILE * pFile; FLMBOOL bFileCreated = FALSE; FLMBOOL bNewFile = FALSE; - FLMBOOL bAllocatedFdb = FALSE; FLMBOOL bMutexLocked = FALSE; - *ppDb = NULL; + if( ppDb) + { + *ppDb = NULL; + } #ifndef FLM_USE_NICI F_UNREFERENCED_PARM( pRebuildState); @@ -123,12 +128,10 @@ RCODE flmCreateNewFile( // Allocate and initialize an FDB structure. - if (RC_BAD( rc = flmAllocFdb( ppDb))) + if (RC_BAD( rc = flmAllocFdb( &pDb))) { goto Exit; } - pDb = *ppDb; - bAllocatedFdb = TRUE; f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; @@ -203,7 +206,7 @@ RCODE flmCreateNewFile( else { pDb->pSFileHdl->SetBlockSize( DEFAULT_BLKSIZ); - pDb->pSFileHdl->SetDbVersion( FLM_CURRENT_VERSION_NUM); + pDb->pSFileHdl->SetDbVersion( FLM_CUR_FILE_FORMAT_VER_NUM); } #ifdef FLM_USE_NICI @@ -211,7 +214,7 @@ RCODE flmCreateNewFile( // Create a new F_CCS object for the database wrapping key if the new // database version is at least ver 4.60 - if (!pCreateOpts || pCreateOpts->uiVersionNum >= FLM_VER_4_60) + if (!pCreateOpts || pCreateOpts->uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) { if ((pFile->pDbWrappingKey = f_new F_CCS) == NULL) { @@ -228,8 +231,8 @@ RCODE flmCreateNewFile( // Only generate a key when this is not part of a rebuild operation or // the original database version was less than 4.60 - if (!pRebuildState || - pRebuildState->pHdrInfo->FileHdr.uiVersionNum < FLM_VER_4_60) + if (!pRebuildState || pRebuildState->pHdrInfo->FileHdr.uiVersionNum < + FLM_FILE_FORMAT_VER_4_60) { if (RC_BAD( rc = pFile->pDbWrappingKey->generateWrappingKey())) { @@ -239,8 +242,8 @@ RCODE flmCreateNewFile( else { if( RC_BAD( rc = pFile->pDbWrappingKey->setKeyFromStore( - &pRebuildState->pLogHdr[LOG_DATABASE_KEY], - FB2UW(&pRebuildState->pLogHdr[LOG_DATABASE_KEY_LEN]), + &pRebuildState->pLogHdr[ LOG_DATABASE_KEY], + FB2UW(&pRebuildState->pLogHdr[ LOG_DATABASE_KEY_LEN]), NULL, NULL, FALSE))) { goto Exit; @@ -293,6 +296,13 @@ RCODE flmCreateNewFile( goto Exit; } + // Start the database monitor thread + + if( RC_BAD( rc = flmStartDbMonitorThread( pFile))) + { + goto Exit; + } + Exit: if( bMutexLocked) @@ -300,7 +310,7 @@ Exit: f_mutexUnlock( gv_FlmSysData.hShareMutex); } - rc = flmCompleteOpenOrCreate( ppDb, rc, bNewFile, bAllocatedFdb); + rc = flmCompleteOpenOrCreate( &pDb, rc, bNewFile, pDb ? TRUE : FALSE); if( RC_BAD( rc)) { @@ -308,8 +318,10 @@ Exit: { (void)gv_FlmSysData.pFileSystem->Delete( pszFilePath); } - - *ppDb = NULL; + } + else if( ppDb) + { + *ppDb = pDb; } return( rc); @@ -467,7 +479,7 @@ FSTATIC RCODE flmInitFileHdrs( FLMUINT uiBufSize) { RCODE rc = FERR_OK; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; FLMBYTE * pucLastCommittedLogHdr; FLMUINT uiLogicalEOF; FLMUINT uiWriteBytes; @@ -501,7 +513,7 @@ FSTATIC RCODE flmInitFileHdrs( // Reserve only room for LFH in 4.3 and above. uiLogicalEOF = (FLMUINT)((pFile->FileHdr.uiVersionNum >= - FLM_VER_4_3) + FLM_FILE_FORMAT_VER_4_3) ? (FLMUINT)pFile->FileHdr.uiFirstLFHBlkAddr + uiBlkSize : (FLMUINT)pFile->FileHdr.uiFirstLFHBlkAddr + @@ -546,7 +558,7 @@ FSTATIC RCODE flmInitFileHdrs( ? pCreateOpts->uiMinRflFileSize : (FLMUINT)DEFAULT_MIN_RFL_FILE_SIZE); - if( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) + if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) { FLMUINT16 ui16Tmp; @@ -653,14 +665,19 @@ FSTATIC RCODE flmInitFileHdrs( { goto Exit; } - // IMPORTANT NOTE: pucBuf must be freed before going to Exit!!! + + // Verify that the field in the log header is long enough to + // hold the key. + + if( ui32KeyLen > FLM_MAX_DB_ENC_KEY_LEN) + { + f_free( &pucBuf); + rc = RC_SET_AND_ASSERT( FERR_BAD_ENC_KEY); + goto Exit; + } - // Assert that the field in the log header is long enough to - // hold the key. Note: This test is only valid if the key - // field is the last one in the log header!! - flmAssert( ui32KeyLen <= (LOG_HEADER_SIZE - LOG_DATABASE_KEY)); - - UW2FBA(ui32KeyLen, &pucLastCommittedLogHdr[LOG_DATABASE_KEY_LEN]); + UW2FBA(ui32KeyLen, &pucLastCommittedLogHdr[ LOG_DATABASE_KEY_LEN]); + f_memcpy( &pucLastCommittedLogHdr[LOG_DATABASE_KEY], pucBuf, ui32KeyLen); f_free( &pucBuf); @@ -705,7 +722,7 @@ FSTATIC RCODE flmInitFileHdrs( // Initialize and output the first pcode block. - if (pFile->FileHdr.uiVersionNum < FLM_VER_4_3) + if (pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { FLMUINT uiPcodeAddr; diff --git a/flaim/src/flerror.cpp b/flaim/src/flerror.cpp index a56e559..07fb27b 100644 --- a/flaim/src/flerror.cpp +++ b/flaim/src/flerror.cpp @@ -24,6 +24,99 @@ #include "flaimsys.h" +// WARNING: ANY CHANGES MADE TO THE FlmCorruptStrings TABLE MUST BE +// REFLECTED IN THE CHECK CODE DEFINES FOUND IN flaim.h + +char * FlmCorruptStrings[ FLM_LAST_CORRUPT_ERROR] = +{ + "OK", // 0 + "BAD_CHAR", // 1 + "BAD_ASIAN_CHAR", // 2 + "BAD_CHAR_SET", // 3 + "BAD_TEXT_FIELD", // 4 + "BAD_NUMBER_FIELD", // 5 + "BAD_CONTEXT_FIELD", // 6 + "BAD_FIELD_TYPE", // 7 + "BAD_IX_DEF", // 8 + "MISSING_REQ_KEY_FIELD", // 9 + "BAD_TEXT_KEY_COLL_CHAR", // 10 + "BAD_TEXT_KEY_CASE_MARKER", // 11 + "BAD_NUMBER_KEY", // 12 + "BAD_CONTEXT_KEY", // 13 + "BAD_BINARY_KEY", // 14 + "BAD_DRN_KEY", // 15 + "BAD_KEY_FIELD_TYPE", // 16 + "BAD_KEY_COMPOUND_MARKER", // 17 + "BAD_KEY_POST_MARKER", // 18 + "BAD_KEY_POST_BYTE_COUNT", // 19 + "BAD_KEY_LEN", // 20 + "BAD_LFH_LIST_PTR", // 21 + "BAD_LFH_LIST_END", // 22 + "BAD_PCODE_LIST_END", // 23 + "BAD_BLK_END", // 24 + "KEY_COUNT_MISMATCH", // 25 + "REF_COUNT_MISMATCH", // 26 + "BAD_CONTAINER_IN_KEY", // 27 + "BAD_BLK_HDR_ADDR", // 28 + "BAD_BLK_HDR_LEVEL", // 29 + "BAD_BLK_HDR_PREV", // 30 + "BAD_BLK_HDR_NEXT", // 31 + "BAD_BLK_HDR_TYPE", // 32 + "BAD_BLK_HDR_ROOT_BIT", // 33 + "BAD_BLK_HDR_BLK_END", // 34 + "BAD_BLK_HDR_LF_NUM", // 35 + "BAD_AVAIL_LIST_END", // 36 + "BAD_PREV_BLK_NEXT", // 37 + "BAD_FIRST_ELM_FLAG", // 38 + "BAD_LAST_ELM_FLAG", // 39 + "BAD_LEM", // 40 + "BAD_ELM_LEN", // 41 + "BAD_ELM_KEY_SIZE", // 42 + "BAD_ELM_PKC_LEN", // 43 + "BAD_ELM_KEY_ORDER", // 44 + "BAD_ELM_KEY_COMPRESS", // 45 + "BAD_CONT_ELM_KEY", // 46 + "NON_UNIQUE_FIRST_ELM_KEY", // 47 + "BAD_ELM_FLD_OVERHEAD", // 48 + "BAD_ELM_FLD_LEVEL_JUMP", // 49 + "BAD_ELM_FLD_NUM", // 50 + "BAD_ELM_FLD_LEN", // 51 + "BAD_ELM_FLD_TYPE", // 52 + "BAD_ELM_END", // 53 + "BAD_PARENT_KEY", // 54 + "BAD_ELM_DOMAIN_SEN", // 55 + "BAD_ELM_BASE_SEN", // 56 + "BAD_ELM_IX_REF", // 57 + "BAD_ELM_ONE_RUN_SEN", // 58 + "BAD_ELM_DELTA_SEN", // 59 + "BAD_ELM_DOMAIN", // 60 + "BAD_LAST_BLK_NEXT", // 61 + "BAD_FIELD_PTR", // 62 + "REBUILD_REC_EXISTS", // 63 + "REBUILD_KEY_NOT_UNIQUE", // 64 + "NON_UNIQUE_ELM_KEY_REF", // 65 + "OLD_VIEW", // 66 + "COULD_NOT_SYNC_BLK", // 67 + "IX_REF_REC_NOT_FOUND", // 68 + "IX_KEY_NOT_FOUND_IN_REC", // 69 + "DRN_NOT_IN_KEY_REFSET", // 70 + "BAD_BLK_CHECKSUM", // 71 + "BAD_LAST_DRN", // 72 + "BAD_FILE_SIZE", // 73 + "BAD_AVAIL_BLOCK_COUNT", // 74 + "BAD_DATE_FIELD", // 75 + "BAD_TIME_FIELD", // 76 + "BAD_TMSTAMP_FIELD", // 77 + "BAD_DATE_KEY", // 78 + "BAD_TIME_KEY", // 79 + "BAD_TMSTAMP_KEY", // 80 + "BAD_BLOB_FIELD", // 81 + "BAD_PCODE_IXD_TBL", // 82 + "DICT_REC_ADD_ERR", // 83 + "FLM_BAD_FIELD_FLAG", // 84 + "FLM_BAD_FOP", // 85 +}; + /**************************************************************************** Desc: The primary purpose of this function is to provide a way to easily trap errors when they occur. Just put a breakpoint in this function @@ -35,12 +128,16 @@ Note: Some of the most common errors will be coded so the use can set a RCODE flmMakeErr( RCODE rc, const char * pszFile, - int iLine) + int iLine, + FLMBOOL bAssert) { if( rc == FERR_OK) + { return FERR_OK; + } // Switch on warning type return codes + if( rc <= FERR_NOT_FOUND) { switch(rc) @@ -60,6 +157,7 @@ RCODE flmMakeErr( default: break; } + return( rc); } @@ -106,13 +204,288 @@ RCODE flmMakeErr( break; } + if( bAssert) + { + flmAssert( 0); + } + return( rc); } #endif -#if defined( FLM_NLM) && !defined( __MWERKS__) - int gv_iFlerrorDummy(void) +/**************************************************************************** +Desc : Returns a pointer to the string representation of a corruption + error code. +****************************************************************************/ +const char * FlmVerifyErrToStr( + eCorruptionType eCorruption) +{ + return( FlmCorruptStrings [eCorruption]); +} + +/**************************************************************************** +Desc: Returns a pointer to the ASCII string representation of a FLAIM + return code. +****************************************************************************/ +FLMEXP const char * FLMAPI FlmErrorString( + RCODE rc) +{ + const char * pszStr; + + if( (pszStr = flmErrorString( rc)) == NULL) { - return( 0); + pszStr = "Unknown Error"; } -#endif + + return( pszStr); +} + +/**************************************************************************** +Desc: Returns a pointer to a static RCODE string or NULL if the RCODE + cannot be mapped +****************************************************************************/ +const char * flmErrorString( + RCODE rc) +{ + if( RC_OK( rc)) + { + return( "FERR_OK"); + } + +#define CASE_RET( c) \ + case c: return( #c ) + + switch( rc) + { + CASE_RET( FERR_BOF_HIT); + CASE_RET( FERR_EOF_HIT); + CASE_RET( FERR_END); + CASE_RET( FERR_EXISTS); + CASE_RET( FERR_FAILURE); + CASE_RET( FERR_NOT_FOUND); + CASE_RET( FERR_BAD_DICT_ID); + CASE_RET( FERR_BAD_CONTAINER); + CASE_RET( FERR_NO_ROOT_BLOCK); + CASE_RET( FERR_BAD_DRN); + CASE_RET( FERR_BAD_FIELD_NUM); + CASE_RET( FERR_BAD_FIELD_TYPE); + CASE_RET( FERR_BAD_HDL); + CASE_RET( FERR_BAD_IX); + CASE_RET( FERR_BACKUP_ACTIVE); + CASE_RET( FERR_SERIAL_NUM_MISMATCH); + CASE_RET( FERR_BAD_RFL_DB_SERIAL_NUM); + CASE_RET( FERR_BTREE_ERROR); + CASE_RET( FERR_BTREE_FULL); + CASE_RET( FERR_BAD_RFL_FILE_NUMBER); + CASE_RET( FERR_CANNOT_DEL_ITEM); + CASE_RET( FERR_CANNOT_MOD_FIELD_TYPE); + CASE_RET( FERR_CONV_BAD_DEST_TYPE); + CASE_RET( FERR_CONV_BAD_DIGIT); + CASE_RET( FERR_CONV_BAD_SRC_TYPE); + CASE_RET( FERR_RFL_FILE_NOT_FOUND); + CASE_RET( FERR_CONV_DEST_OVERFLOW); + CASE_RET( FERR_CONV_ILLEGAL); + CASE_RET( FERR_CONV_NULL_SRC); + CASE_RET( FERR_CONV_NULL_DEST); + CASE_RET( FERR_CONV_NUM_OVERFLOW); + CASE_RET( FERR_CONV_NUM_UNDERFLOW); + CASE_RET( FERR_DATA_ERROR); + CASE_RET( FERR_DD_ERROR); + CASE_RET( FERR_INVALID_FILE_SEQUENCE); + CASE_RET( FERR_ILLEGAL_OP); + CASE_RET( FERR_DUPLICATE_DICT_REC); + CASE_RET( FERR_CANNOT_CONVERT); + CASE_RET( FERR_UNSUPPORTED_VERSION); + CASE_RET( FERR_FILE_ER); + CASE_RET( FERR_BAD_FIELD_LEVEL); + CASE_RET( FERR_GED_BAD_RECID); + CASE_RET( FERR_GED_BAD_VALUE); + CASE_RET( FERR_GED_MAXLVLNUM); + CASE_RET( FERR_GED_SKIP_LEVEL); + CASE_RET( FERR_ILLEGAL_TRANS); + CASE_RET( FERR_ILLEGAL_TRANS_OP); + CASE_RET( FERR_INCOMPLETE_LOG); + CASE_RET( FERR_INVALID_BLOCK_LENGTH); + CASE_RET( FERR_INVALID_TAG); + CASE_RET( FERR_KEY_NOT_FOUND); + CASE_RET( FERR_VALUE_TOO_LARGE); + CASE_RET( FERR_MEM); + CASE_RET( FERR_BAD_RFL_SERIAL_NUM); + CASE_RET( FERR_NEWER_FLAIM); + CASE_RET( FERR_CANNOT_MOD_FIELD_STATE); + CASE_RET( FERR_NO_MORE_DRNS); + CASE_RET( FERR_NO_TRANS_ACTIVE); + CASE_RET( FERR_NOT_UNIQUE); + CASE_RET( FERR_NOT_FLAIM); + CASE_RET( FERR_NULL_RECORD); + CASE_RET( FERR_NO_HTTP_STACK); + CASE_RET( FERR_OLD_VIEW); + CASE_RET( FERR_PCODE_ERROR); + CASE_RET( FERR_PERMISSION); + CASE_RET( FERR_SYNTAX); + CASE_RET( FERR_CALLBACK_FAILURE); + CASE_RET( FERR_TRANS_ACTIVE); + CASE_RET( FERR_RFL_TRANS_GAP); + CASE_RET( FERR_BAD_COLLATED_KEY); + CASE_RET( FERR_UNSUPPORTED_FEATURE); + CASE_RET( FERR_MUST_DELETE_INDEXES); + CASE_RET( FERR_RFL_INCOMPLETE); + CASE_RET( FERR_CANNOT_RESTORE_RFL_FILES); + CASE_RET( FERR_INCONSISTENT_BACKUP); + CASE_RET( FERR_BLOCK_CHECKSUM); + CASE_RET( FERR_ABORT_TRANS); + CASE_RET( FERR_NOT_RFL); + CASE_RET( FERR_BAD_RFL_PACKET); + CASE_RET( FERR_DATA_PATH_MISMATCH); + CASE_RET( FERR_HTTP_REGISTER_FAILURE); + CASE_RET( FERR_HTTP_DEREG_FAILURE); + CASE_RET( FERR_IX_FAILURE); + CASE_RET( FERR_HTTP_SYMS_EXIST); + CASE_RET( FERR_FILE_EXISTS); + CASE_RET( FERR_SYM_RESOLVE_FAIL); + CASE_RET( FERR_BAD_SERVER_CONNECTION); + CASE_RET( FERR_CLOSING_DATABASE); + CASE_RET( FERR_INVALID_CRC); + CASE_RET( FERR_KEY_OVERFLOW); + CASE_RET( FERR_NOT_IMPLEMENTED); + CASE_RET( FERR_MUTEX_OPERATION_FAILED); + CASE_RET( FERR_MUTEX_UNABLE_TO_LOCK); + CASE_RET( FERR_SEM_OPERATION_FAILED); + CASE_RET( FERR_SEM_UNABLE_TO_LOCK); + CASE_RET( FERR_BAD_REFERENCE); + CASE_RET( FERR_UNALLOWED_UPGRADE); + CASE_RET( FERR_ID_RESERVED); + CASE_RET( FERR_CANNOT_RESERVE_ID); + CASE_RET( FERR_DUPLICATE_DICT_NAME); + CASE_RET( FERR_CANNOT_RESERVE_NAME); + CASE_RET( FERR_BAD_DICT_DRN); + CASE_RET( FERR_CANNOT_MOD_DICT_REC_TYPE); + CASE_RET( FERR_PURGED_FLD_FOUND); + CASE_RET( FERR_DUPLICATE_INDEX); + CASE_RET( FERR_TOO_MANY_OPEN_DBS); + CASE_RET( FERR_ACCESS_DENIED); + CASE_RET( FERR_CACHE_ERROR); + CASE_RET( FERR_BLOB_MISSING_FILE); + CASE_RET( FERR_NO_REC_FOR_KEY); + CASE_RET( FERR_DB_FULL); + CASE_RET( FERR_TIMEOUT); + CASE_RET( FERR_CURSOR_SYNTAX); + CASE_RET( FERR_THREAD_ERR); + CASE_RET( FERR_UNIMPORT_SYMBOL); + CASE_RET( FERR_EMPTY_QUERY); + CASE_RET( FERR_INDEX_OFFLINE); + CASE_RET( FERR_TRUNCATED_KEY); + CASE_RET( FERR_INVALID_PARM); + CASE_RET( FERR_USER_ABORT); + CASE_RET( FERR_RFL_DEVICE_FULL); + CASE_RET( FERR_MUST_WAIT_CHECKPOINT); + CASE_RET( FERR_NAMED_SEMAPHORE_ERR); + CASE_RET( FERR_LOAD_LIBRARY); + CASE_RET( FERR_UNLOAD_LIBRARY); + CASE_RET( FERR_IMPORT_SYMBOL); + CASE_RET( FERR_BLOCK_FULL); + CASE_RET( FERR_BAD_BASE64_ENCODING); + CASE_RET( FERR_MISSING_FIELD_TYPE); + CASE_RET( FERR_BAD_DATA_LENGTH); + CASE_RET( FERR_IO_ACCESS_DENIED); + CASE_RET( FERR_IO_BAD_FILE_HANDLE); + CASE_RET( FERR_IO_COPY_ERR); + CASE_RET( FERR_IO_DISK_FULL); + CASE_RET( FERR_IO_END_OF_FILE); + CASE_RET( FERR_IO_OPEN_ERR); + CASE_RET( FERR_IO_SEEK_ERR); + CASE_RET( FERR_IO_MODIFY_ERR); + CASE_RET( FERR_IO_PATH_NOT_FOUND); + CASE_RET( FERR_IO_TOO_MANY_OPEN_FILES); + CASE_RET( FERR_IO_PATH_TOO_LONG); + CASE_RET( FERR_IO_NO_MORE_FILES); + CASE_RET( FERR_DELETING_FILE); + CASE_RET( FERR_IO_FILE_LOCK_ERR); + CASE_RET( FERR_IO_FILE_UNLOCK_ERR); + CASE_RET( FERR_IO_PATH_CREATE_FAILURE); + CASE_RET( FERR_IO_RENAME_FAILURE); + CASE_RET( FERR_IO_INVALID_PASSWORD); + CASE_RET( FERR_SETTING_UP_FOR_READ); + CASE_RET( FERR_SETTING_UP_FOR_WRITE); + CASE_RET( FERR_IO_AT_PATH_ROOT); + CASE_RET( FERR_INITIALIZING_IO_SYSTEM); + CASE_RET( FERR_FLUSHING_FILE); + CASE_RET( FERR_IO_INVALID_PATH); + CASE_RET( FERR_IO_CONNECT_ERROR); + CASE_RET( FERR_OPENING_FILE); + CASE_RET( FERR_DIRECT_OPENING_FILE); + CASE_RET( FERR_CREATING_FILE); + CASE_RET( FERR_DIRECT_CREATING_FILE); + CASE_RET( FERR_READING_FILE); + CASE_RET( FERR_DIRECT_READING_FILE); + CASE_RET( FERR_WRITING_FILE); + CASE_RET( FERR_DIRECT_WRITING_FILE); + CASE_RET( FERR_POSITIONING_IN_FILE); + CASE_RET( FERR_GETTING_FILE_SIZE); + CASE_RET( FERR_TRUNCATING_FILE); + CASE_RET( FERR_PARSING_FILE_NAME); + CASE_RET( FERR_CLOSING_FILE); + CASE_RET( FERR_GETTING_FILE_INFO); + CASE_RET( FERR_EXPANDING_FILE); + CASE_RET( FERR_GETTING_FREE_BLOCKS); + CASE_RET( FERR_CHECKING_FILE_EXISTENCE); + CASE_RET( FERR_RENAMING_FILE); + CASE_RET( FERR_SETTING_FILE_INFO); + CASE_RET( FERR_NICI_CONTEXT); + CASE_RET( FERR_NICI_FIND_INIT); + CASE_RET( FERR_NICI_FIND_OBJECT); + CASE_RET( FERR_NICI_WRAPKEY_NOT_FOUND); + CASE_RET( FERR_NICI_ATTRIBUTE_VALUE); + CASE_RET( FERR_NICI_BAD_ATTRIBUTE); + CASE_RET( FERR_NICI_BAD_RANDOM); + CASE_RET( FERR_NICI_WRAPKEY_FAILED); + CASE_RET( FERR_NICI_GENKEY_FAILED); + CASE_RET( FERR_REQUIRE_PASSWD); + CASE_RET( FERR_NICI_SHROUDKEY_FAILED); + CASE_RET( FERR_NICI_UNSHROUDKEY_FAILED); + CASE_RET( FERR_NICI_UNWRAPKEY_FAILED); + CASE_RET( FERR_NICI_ENC_INIT_FAILED); + CASE_RET( FERR_NICI_ENCRYPT_FAILED); + CASE_RET( FERR_NICI_DECRYPT_INIT_FAILED); + CASE_RET( FERR_NICI_DECRYPT_FAILED); + CASE_RET( FERR_NICI_INIT_FAILED); + CASE_RET( FERR_NICI_KEY_NOT_FOUND); + CASE_RET( FERR_NICI_INVALID_ALGORITHM); + CASE_RET( FERR_FLD_NOT_ENCRYPTED); + CASE_RET( FERR_BAD_ENCDEF_ID); + CASE_RET( FERR_CANNOT_SET_KEY); + CASE_RET( FERR_MISSING_ENC_TYPE); + CASE_RET( FERR_CANNOT_MOD_ENC_TYPE); + CASE_RET( FERR_MISSING_ENC_KEY); + CASE_RET( FERR_CANNOT_CHANGE_KEY); + CASE_RET( FERR_BAD_ENC_KEY); + CASE_RET( FERR_CANNOT_MOD_ENC_STATE); + CASE_RET( FERR_DATA_SIZE_MISMATCH); + CASE_RET( FERR_ENCRYPTION_UNAVAILABLE); + CASE_RET( FERR_PURGED_ENCDEF_FOUND); + CASE_RET( FERR_FLD_NOT_DECRYPTED); + CASE_RET( FERR_PBE_ENCRYPT_FAILED); + CASE_RET( FERR_DIGEST_FAILED); + CASE_RET( FERR_DIGEST_INIT_FAILED); + CASE_RET( FERR_EXTRACT_KEY_FAILED); + CASE_RET( FERR_INJECT_KEY_FAILED); + CASE_RET( FERR_PBE_DECRYPT_FAILED); + CASE_RET( FERR_PASSWD_INVALID); + CASE_RET( FERR_SVR_NOIP_ADDR); + CASE_RET( FERR_SVR_SOCK_FAIL); + CASE_RET( FERR_SVR_CONNECT_FAIL); + CASE_RET( FERR_SVR_BIND_FAIL); + CASE_RET( FERR_SVR_LISTEN_FAIL); + CASE_RET( FERR_SVR_ACCEPT_FAIL); + CASE_RET( FERR_SVR_SELECT_ERR); + CASE_RET( FERR_SVR_SOCKOPT_FAIL); + CASE_RET( FERR_SVR_DISCONNECT); + CASE_RET( FERR_SVR_READ_FAIL); + CASE_RET( FERR_SVR_WRT_FAIL); + CASE_RET( FERR_SVR_READ_TIMEOUT); + CASE_RET( FERR_SVR_WRT_TIMEOUT); + CASE_RET( FERR_SVR_ALREADY_CLOSED); + default: + return( NULL); + } +} diff --git a/flaim/src/flerrstr.cpp b/flaim/src/flerrstr.cpp deleted file mode 100644 index dd51b02..0000000 --- a/flaim/src/flerrstr.cpp +++ /dev/null @@ -1,130 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Convert check error codes into strings. -// Tabs: 3 -// -// Copyright (c) 1992-2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flerrstr.cpp 12262 2006-01-19 14:42:10 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/* -** WARNING: ANY CHANGES MADE TO THE FlmCorruptStrings TABLE MUST BE -** REFLECTED IN THE CHECK CODE DEFINES FOUND IN flaim.h -*/ - -const char * FlmCorruptStrings[ FLM_LAST_CORRUPT_ERROR] -= { - "OK", // 0 - "BAD_CHAR", // 1 - "BAD_ASIAN_CHAR", // 2 - "BAD_CHAR_SET", // 3 - "BAD_TEXT_FIELD", // 4 - "BAD_NUMBER_FIELD", // 5 - "BAD_CONTEXT_FIELD", // 6 - "BAD_FIELD_TYPE", // 7 - "BAD_IX_DEF", // 8 - "MISSING_REQ_KEY_FIELD", // 9 - "BAD_TEXT_KEY_COLL_CHAR", // 10 - "BAD_TEXT_KEY_CASE_MARKER", // 11 - "BAD_NUMBER_KEY", // 12 - "BAD_CONTEXT_KEY", // 13 - "BAD_BINARY_KEY", // 14 - "BAD_DRN_KEY", // 15 - "BAD_KEY_FIELD_TYPE", // 16 - "BAD_KEY_COMPOUND_MARKER", // 17 - "BAD_KEY_POST_MARKER", // 18 - "BAD_KEY_POST_BYTE_COUNT", // 19 - "BAD_KEY_LEN", // 20 - "BAD_LFH_LIST_PTR", // 21 - "BAD_LFH_LIST_END", // 22 - "BAD_PCODE_LIST_END", // 23 - "BAD_BLK_END", // 24 - "KEY_COUNT_MISMATCH", // 25 - "REF_COUNT_MISMATCH", // 26 - "BAD_CONTAINER_IN_KEY", // 27 - "BAD_BLK_HDR_ADDR", // 28 - "BAD_BLK_HDR_LEVEL", // 29 - "BAD_BLK_HDR_PREV", // 30 - "BAD_BLK_HDR_NEXT", // 31 - "BAD_BLK_HDR_TYPE", // 32 - "BAD_BLK_HDR_ROOT_BIT", // 33 - "BAD_BLK_HDR_BLK_END", // 34 - "BAD_BLK_HDR_LF_NUM", // 35 - "BAD_AVAIL_LIST_END", // 36 - "BAD_PREV_BLK_NEXT", // 37 - "BAD_FIRST_ELM_FLAG", // 38 - "BAD_LAST_ELM_FLAG", // 39 - "BAD_LEM", // 40 - "BAD_ELM_LEN", // 41 - "BAD_ELM_KEY_SIZE", // 42 - "BAD_ELM_PKC_LEN", // 43 - "BAD_ELM_KEY_ORDER", // 44 - "BAD_ELM_KEY_COMPRESS", // 45 - "BAD_CONT_ELM_KEY", // 46 - "NON_UNIQUE_FIRST_ELM_KEY", // 47 - "BAD_ELM_FLD_OVERHEAD", // 48 - "BAD_ELM_FLD_LEVEL_JUMP", // 49 - "BAD_ELM_FLD_NUM", // 50 - "BAD_ELM_FLD_LEN", // 51 - "BAD_ELM_FLD_TYPE", // 52 - "BAD_ELM_END", // 53 - "BAD_PARENT_KEY", // 54 - "BAD_ELM_DOMAIN_SEN", // 55 - "BAD_ELM_BASE_SEN", // 56 - "BAD_ELM_IX_REF", // 57 - "BAD_ELM_ONE_RUN_SEN", // 58 - "BAD_ELM_DELTA_SEN", // 59 - "BAD_ELM_DOMAIN", // 60 - "BAD_LAST_BLK_NEXT", // 61 - "BAD_FIELD_PTR", // 62 - "REBUILD_REC_EXISTS", // 63 - "REBUILD_KEY_NOT_UNIQUE", // 64 - "NON_UNIQUE_ELM_KEY_REF", // 65 - "OLD_VIEW", // 66 - "COULD_NOT_SYNC_BLK", // 67 - "IX_REF_REC_NOT_FOUND", // 68 - "IX_KEY_NOT_FOUND_IN_REC", // 69 - "DRN_NOT_IN_KEY_REFSET", // 70 - "BAD_BLK_CHECKSUM", // 71 - "BAD_LAST_DRN", // 72 - "BAD_FILE_SIZE", // 73 - "BAD_AVAIL_BLOCK_COUNT", // 74 - "BAD_DATE_FIELD", // 75 - "BAD_TIME_FIELD", // 76 - "BAD_TMSTAMP_FIELD", // 77 - "BAD_DATE_KEY", // 78 - "BAD_TIME_KEY", // 79 - "BAD_TMSTAMP_KEY", // 80 - "BAD_BLOB_FIELD", // 81 - "BAD_PCODE_IXD_TBL", // 82 - "DICT_REC_ADD_ERR", // 83 - "FLM_BAD_FIELD_FLAG", // 84 - }; - -/*API~*********************************************************************** -Desc : Returns a pointer to the string representation of a corruption - error code. -*END************************************************************************/ -const char * FlmVerifyErrToStr( - eCorruptionType eCorruption - ) -{ - return( FlmCorruptStrings [eCorruption]); -} diff --git a/flaim/src/flfixed.h b/flaim/src/flfixed.h index 3799799..607cf1f 100644 --- a/flaim/src/flfixed.h +++ b/flaim/src/flfixed.h @@ -123,7 +123,7 @@ private: #define NUM_BUF_ALLOCATORS 22 -typedef struct +typedef struct FLM_ALLOC_USAGE { FLMUINT64 ui64Slabs; FLMUINT64 ui64SlabBytes; @@ -232,20 +232,20 @@ public: return( m_phMutex); } - typedef struct Block + typedef struct BLOCK { void * pvAllocator; - Block * pNext; - Block * pPrev; - Block * pNextBlockWithAvailCells; - Block * pPrevBlockWithAvailCells; + BLOCK * pNext; + BLOCK * pPrev; + BLOCK * pNextBlockWithAvailCells; + BLOCK * pPrevBlockWithAvailCells; FLMBYTE * pLocalAvailCellListHead; FLMUINT32 ui32NextNeverUsedCell; FLMUINT32 ui32AvailCellCount; FLMUINT32 ui32AllocatedCells; } BLOCK; - typedef struct CellHeader + typedef struct CELLHEADER { BLOCK * pContainingBlock; #ifdef FLM_DEBUG @@ -253,7 +253,7 @@ public: #endif } CELLHEADER; - typedef struct CellAvailNext + typedef struct CELLAVAILNEXT { FLMBYTE * pNextInList; #ifdef FLM_DEBUG diff --git a/flaim/src/flgdrecs.cpp b/flaim/src/flgdrecs.cpp deleted file mode 100644 index 125e79c..0000000 --- a/flaim/src/flgdrecs.cpp +++ /dev/null @@ -1,348 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Routines for adding, modifying, and deleting fields in a FlmRecord. -// Tabs: 3 -// -// Copyright (c) 1995-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// PERPETRATOR TO CRIMINAL AND CIVIL LIABILITY. -// -// $Id: flgdrecs.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define UBUF_SIZE 32 - -/**************************************************************************** -Desc: This routine adds a field to a record. -****************************************************************************/ -RCODE flmAddField( - FlmRecord * pRecord, - FLMUINT uiTagNum, - const void * pvData, - FLMUINT uiDataLen, - FLMUINT uiDataType) -{ - RCODE rc = FERR_OK; - void * pvField; - - // Insert new field. - - if( RC_BAD( rc = pRecord->insertLast( 1, uiTagNum, uiDataType, &pvField))) - { - goto Exit; - } - - switch( uiDataType) - { - case FLM_TEXT_TYPE: - { - rc = pRecord->setNative( pvField, (const char *)pvData); - - break; - } - - case FLM_NUMBER_TYPE: - { - FLMUINT uiNum; - - switch (uiDataLen) - { - case 0: - uiNum = (FLMUINT)(*((FLMUINT *)(pvData))); - break; - case 1: - uiNum = (FLMUINT)(*((FLMBYTE *)(pvData))); - break; - case 2: - uiNum = (FLMUINT)(*((FLMUINT16 *)(pvData))); - break; - case 4: - uiNum = (FLMUINT)(*((FLMUINT32 *)(pvData))); - break; - default: - flmAssert( 0); - rc = RC_SET( FERR_INVALID_PARM); - goto Exit; - } - rc = pRecord->setUINT( pvField, uiNum); - break; - } - case FLM_BINARY_TYPE: - { - rc = pRecord->setBinary( pvField, pvData, uiDataLen); - break; - } - default : - { - flmAssert( 0); - break; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: This routine modifies the first matching field in a record. - If the field is not found, a new field will be created. -****************************************************************************/ -RCODE flmModField( - FlmRecord * pRecord, - FLMUINT uiTagNum, - const void * pvData, - FLMUINT uiDataLen, - FLMUINT uiDataType) -{ - RCODE rc = FERR_OK; - void * pvField; - - if( (pvField = pRecord->find( pRecord->root(), uiTagNum)) == NULL) - { - // Create the field. - - if( RC_BAD( rc = pRecord->insertLast( 1, uiTagNum, uiDataType, &pvField))) - { - goto Exit; - } - } - - switch( uiDataType) - { - case FLM_TEXT_TYPE: - { - rc = pRecord->setNative( pvField, (const char *)pvData); - break; - } - - case FLM_NUMBER_TYPE: - { - FLMUINT uiNum; - switch (uiDataLen) - { - case 0: - uiNum = (FLMUINT)(*((FLMUINT *)(pvData))); - case 1: - uiNum = (FLMUINT)(*((FLMBYTE *)(pvData))); - break; - case 2: - uiNum = (FLMUINT)(*((FLMUINT16 *)(pvData))); - break; - case 4: - uiNum = (FLMUINT)(*((FLMUINT32 *)(pvData))); - break; - default: - flmAssert( 0); - rc = RC_SET( FERR_INVALID_PARM); - goto Exit; - } - - rc = pRecord->setUINT( pvField, uiNum); - break; - } - - case FLM_BINARY_TYPE: - { - rc = pRecord->setBinary( pvField, pvData, uiDataLen); - break; - } - - default : - { - flmAssert( 0); - break; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: This routine searches for a specific numeric field and deletes - that field from the record. -****************************************************************************/ -RCODE flmDelField( - FlmRecord * pRecord, - FLMUINT uiTagNum, - FLMUINT uiValue) -{ - RCODE rc = FERR_OK; - FLMUINT uiNum; - void * pvField; - - if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) - { - for(;;) - { - if( pRecord->getFieldID( pvField) == uiTagNum) - { - if( RC_BAD( rc = pRecord->getUINT( pvField, &uiNum))) - { - goto Exit; - } - - if( uiNum == uiValue) - { - pRecord->remove( pvField); - break; - } - } - - pvField = pRecord->nextSibling( pvField); - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: This routine finds a field in a record and increments its value. - The value of 1 will be assigned if the field is not present. -****************************************************************************/ -RCODE flmIncrField( - FlmRecord * pRecord, - FLMUINT uiTagNum) -{ - RCODE rc = FERR_OK; - void * pvField; - - if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) - { - FLMUINT uiNum; - - if( RC_OK( rc = pRecord->getUINT( pvField, &uiNum))) - { - uiNum++; - rc = pRecord->setUINT( pvField, uiNum); - } - } - else - { - // Create the field and set the value to one. - - if( RC_OK( rc = pRecord->insertLast( 1, uiTagNum, - FLM_NUMBER_TYPE, &pvField))) - { - rc = pRecord->setUINT( pvField, 1); - } - } - - return( rc); -} - -/**************************************************************************** -Desc: This routine finds a field in a record and decrements its value. -****************************************************************************/ -RCODE flmDecrField( - FlmRecord * pRecord, - FLMUINT uiTagNum) -{ - RCODE rc = FERR_OK; - void * pvField; - - if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) - { - FLMUINT uiNum; - - if( RC_OK( rc = pRecord->getUINT( pvField, &uiNum))) - { - uiNum--; - rc = pRecord->setUINT( pvField, uiNum); - } - } - - return( rc); -} - -/**************************************************************************** -Desc: This routine adds a field to a GEDCOM tree -****************************************************************************/ -RCODE gedAddField( - POOL * pPool, - NODE * pRecord, - FLMUINT uiTagNum, - const void * pvData, - FLMUINT uiDataLen, - FLMUINT uiDataType) -{ - RCODE rc = FERR_OK; - NODE * pChildNode; - FLMUINT uiNum; - - if ((pChildNode = GedNodeMake( pPool, uiTagNum, &rc)) == NULL) - { - goto Exit; - } - - switch( uiDataType) - { - case FLM_TEXT_TYPE: - { - rc = GedPutNATIVE( pPool, pChildNode, (const char *)pvData); - break; - } - - case FLM_NUMBER_TYPE: - { - switch (uiDataLen) - { - case 0: - uiNum = (FLMUINT)(*((FLMUINT *)(pvData))); - break; - case 1: - uiNum = (FLMUINT)(*((FLMBYTE *)(pvData))); - break; - case 2: - uiNum = (FLMUINT)(*((FLMUINT16 *)(pvData))); - break; - case 4: - uiNum = (FLMUINT)(*((FLMUINT32 *)(pvData))); - break; - default: - flmAssert( 0); - rc = RC_SET( FERR_INVALID_PARM); - goto Exit; - } - - rc = GedPutUINT( pPool, pChildNode, uiNum); - break; - } - - case FLM_BINARY_TYPE: - { - rc = GedPutBINARY( pPool, pChildNode, pvData, uiDataLen); - break; - } - } - - if (RC_BAD( rc)) - { - goto Exit; - } - - GedChildGraft( pRecord, pChildNode, GED_LAST); - -Exit: - - return( rc); -} diff --git a/flaim/src/flgethdr.cpp b/flaim/src/flgethdr.cpp deleted file mode 100644 index 696ce01..0000000 --- a/flaim/src/flgethdr.cpp +++ /dev/null @@ -1,64 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Read and parse database header into a structure. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flgethdr.cpp 12262 2006-01-19 14:42:10 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*************************************************************************** -Desc: This routine reads the header information in a FLAIM database, - verifies the password, and returns the file header and log - header information. -*****************************************************************************/ -RCODE flmGetHdrInfo( - F_SuperFileHdl * pSFileHdl, /* Pointer to file handle. */ - FILE_HDR * pFileHdrRV, /* Returns file header information. */ - LOG_HDR * pLogHdrRV, /* Returns log header information. */ - FLMBYTE * pLogHdr - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * pBuf = NULL; - F_FileHdlImp * pCFileHdl; - - if (RC_BAD( rc = f_alloc( 2048, &pBuf))) - { - goto Exit; - } - - if( RC_BAD( rc = pSFileHdl->GetFileHdl( 0, FALSE, &pCFileHdl))) - { - goto Exit; - } - - rc = flmReadAndVerifyHdrInfo( NULL, pCFileHdl, - pBuf, pFileHdrRV, pLogHdrRV, pLogHdr); - -Exit: - - if( pBuf) - { - f_free( &pBuf); - } - - return( rc); -} diff --git a/flaim/src/flindex.cpp b/flaim/src/flindex.cpp index 9f72656..d2d0862 100644 --- a/flaim/src/flindex.cpp +++ b/flaim/src/flindex.cpp @@ -38,9 +38,9 @@ FSTATIC RCODE flmIndexStatusCS( FLMUINT uiIndexNum, FINDEX_STATUS * pIndexStatus); -/*API~*********************************************************************** +/**************************************************************************** Desc : Return the status of the index. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexStatus( HFDB hDb, FLMUINT uiIndexNum, @@ -115,7 +115,7 @@ FLMEXP RCODE FLMAPI FlmIndexStatus( // Sanity check #ifdef FLM_DEBUG - if( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_51 && + if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_51 && bSuspended != bTrackerIxSuspended) { flmAssert( 0); @@ -145,10 +145,10 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Return the number of the next index. Pass in zero to get the first index. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexGetNext( HFDB hDb, FLMUINT * puiIndexNum) @@ -164,7 +164,7 @@ FLMEXP RCODE FLMAPI FlmIndexGetNext( { fdbInitCS( pDb); - CS_CONTEXT_p pCSContext = pDb->pCSContext; + CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( !pCSContext->bConnectionGood) @@ -235,7 +235,7 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Suspend the selected index from doing any key updates on records that are equal or higher than the next record ID value in the container that the index references. If the index is offline @@ -244,7 +244,7 @@ Desc : Suspend the selected index from doing any key updates on records suspended FERR_OK will be returned. A suspended index is not persistant if the database goes down. Notes: An update transaction will be started if necessary. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexSuspend( HFDB hDb, FLMUINT uiIndexNum) @@ -262,7 +262,7 @@ FLMEXP RCODE FLMAPI FlmIndexSuspend( { fdbInitCS( pDb); - CS_CONTEXT_p pCSContext = pDb->pCSContext; + CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( !pCSContext->bConnectionGood) @@ -448,12 +448,12 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : If the index was suspended, restart the background process that will get the index up to date so that it will eventually be online. Returns FERR_OK with no change if the index is already online. Notes: An update transaction will be started if necessary. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmIndexResume( HFDB hDb, FLMUINT uiIndexNum) @@ -470,7 +470,7 @@ FLMEXP RCODE FLMAPI FlmIndexResume( { fdbInitCS( pDb); - CS_CONTEXT_p pCSContext = pDb->pCSContext; + CS_CONTEXT * pCSContext = pDb->pCSContext; FCL_WIRE Wire( pCSContext, pDb); if( !pCSContext->bConnectionGood) @@ -1395,7 +1395,7 @@ Loop_Again: { // flmIndexSetOfRecords brought the index on-line - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIndexNum, @@ -1570,7 +1570,7 @@ F_BKGND_IX * flmBackgroundIndexGet( /**************************************************************************** Desc : Return the status of the index (via C/S protocol) -*END************************************************************************/ +****************************************************************************/ FSTATIC RCODE flmIndexStatusCS( FDB * pDb, FLMUINT uiIndexNum, diff --git a/flaim/src/flkeymak.cpp b/flaim/src/flkeymak.cpp deleted file mode 100644 index 673ab29..0000000 --- a/flaim/src/flkeymak.cpp +++ /dev/null @@ -1,543 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Generate a key from a collated key. -// Tabs: 3 -// -// Copyright (c) 1999-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flkeymak.cpp 12263 2006-01-19 14:43:23 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/******************************************************************** -Desc: Build a responce tree of NODEs for the key output. -*********************************************************************/ -RCODE flmIxKeyOutput( - IXD_p pIxd, - FLMBYTE * pucFromKey, - FLMUINT uiKeyLen, - FlmRecord ** ppKeyRV, // Returns key - FLMBOOL bFullFldPaths) // If true add full field paths -{ - RCODE rc = FERR_OK; - FlmRecord * pKey = NULL; - void * pvField; - FLMBYTE ucKeyBuf[ MAX_KEY_SIZ + 12]; - FLMBYTE * pucToKey = &ucKeyBuf[ 0]; - FLMBYTE * pucPostBuf = NULL; - IFD_p pIfd; - FLMUINT uiLongValue; - FLMUINT uiToKeyLen; - FLMUINT uiLanguage = pIxd->uiLanguage; - FLMUINT uiFromKeyLen; - FLMUINT uiFromRemaining; - FLMUINT uiPostLen; - FLMUINT uiPostPos; - FLMUINT uiTempFromKeyLen; - FLMUINT uiFldType; - FLMUINT uiDataType; - FLMBOOL bDataRightTruncated; - FLMBOOL bFirstSubstring; - FLMBOOL bSigSign; - FLMBYTE ucTemp; - FLMUINT uiContainer; - FLMUINT uiMaxKeySize; - - // If the index is on all containers, see if this key has - // a container component. If so, strip it off. - - if( (uiContainer = pIxd->uiContainerNum) == 0) - { - FLMUINT uiContainerPartLen = getIxContainerPartLen( pIxd); - - if (uiKeyLen <= uiContainerPartLen) - { - flmAssert( 0); - rc = RC_SET( FERR_BTREE_ERROR); - goto Exit; - } - uiContainer = getContainerFromKey( pucFromKey, uiKeyLen); - - // Subtract off the bytes for the container part. - - uiKeyLen -= uiContainerPartLen; - uiMaxKeySize = MAX_KEY_SIZ - uiContainerPartLen; - } - else - { - uiMaxKeySize = MAX_KEY_SIZ; - } - - // Old code did this. - flmAssert( uiLanguage != 0xFFFF); - - if (*ppKeyRV) - { - if( (*ppKeyRV)->isReadOnly() || (*ppKeyRV)->isCached()) - { - (*ppKeyRV)->Release(); - *ppKeyRV = NULL; - } - else - { - (*ppKeyRV)->clear(); - } - } - - if( (pKey = *ppKeyRV) == NULL) - { - if( (pKey = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - *ppKeyRV = pKey; - } - - pKey->setContainerID( uiContainer); - - uiFromKeyLen = uiFromRemaining = uiKeyLen; - pIfd = pIxd->pFirstIfd; - - // If post index, get post low/up section. - - if( pIfd->uiFlags & IFD_POST ) - { - - // Last byte has low/upper length - - uiPostLen = pucFromKey[ uiFromKeyLen - 1 ]; - pucPostBuf = &pucFromKey[ uiFromKeyLen - uiPostLen - 1 ]; - uiPostPos = 0; - } - - // Allocate [key] root field - // VISIT: Removed to be more pure. - - if (RC_BAD( rc = pKey->insertLast( 0, FLM_KEY_TAG, FLM_CONTEXT_TYPE, NULL))) - { - goto Exit; - } - - // Loop for each compound piece of key - - for( ;;) - { - FLMBOOL bIsAsianCompound; - FLMUINT uiMarker; - - bDataRightTruncated = bFirstSubstring = FALSE; - - bIsAsianCompound = (FLMBOOL)(((uiLanguage >= FIRST_DBCS_LANG) && - (uiLanguage <= LAST_DBCS_LANG) && - (IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE) && - (!(pIfd->uiFlags & IFD_CONTEXT))) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - - uiMarker = (FLMUINT)((bIsAsianCompound) - ? (FLMUINT)((FLMUINT)(*pucFromKey << 8) + - *(pucFromKey+1)) - : (FLMUINT) *pucFromKey); - uiFldType = (FLMUINT) IFD_GET_FIELD_TYPE( pIfd); - uiDataType = IFD_GET_FIELD_TYPE( pIfd); - - // Hit a compound marker or end of key marker - // Check includes COMPOUND_MARKER & END_COMPOUND_MARKER - - if( uiMarker <= NULL_KEY_MARKER) - { - - // If the field is required or single field then generate an empty node. - - if( ((pIfd->uiFlags & IFD_OPTIONAL) == 0) || - (uiFldType == FLM_TEXT_TYPE) || - (uiFldType == FLM_BINARY_TYPE) || - ((pIfd->uiFlags & IFD_LAST) && !pIfd->uiCompoundPos )) - { - if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, - uiDataType, bFullFldPaths, pKey, &pvField))) - goto Exit; - } - if( uiMarker == END_COMPOUND_MARKER) // Used for post keys - break; - - uiFromKeyLen = 0; // This piece is zero - skip it - may be others - } - else - { - - // If compound key or if only field used in index - // output the key elements field number or else 'NA' - - if( pIfd->uiFlags & IFD_CONTEXT) - { - if( RC_BAD( rc = flmBuildKeyPaths( pIfd, - flmBigEndianToUINT16( &pucFromKey [1]), - uiDataType, bFullFldPaths, pKey, &pvField))) - { - goto Exit; - } - uiFromKeyLen = KY_CONTEXT_LEN; - } - - else - { - if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, - uiDataType, bFullFldPaths, pKey, &pvField))) - { - goto Exit; - } - - // Grab only the Nth section of key if compound key - // Null out key if uiToKeyLen gets 0 - - UD2FBA( 0, pucToKey); - - switch( uiDataType) - { - case FLM_TEXT_TYPE: - - uiTempFromKeyLen = uiFromKeyLen; - uiToKeyLen = FColStrToText( pucFromKey, &uiTempFromKeyLen, pucToKey, - uiLanguage, pucPostBuf, &uiPostPos, - &bDataRightTruncated, &bFirstSubstring); - uiFromKeyLen = uiTempFromKeyLen; - break; - - case FLM_NUMBER_TYPE: - { - FLMUINT uiFirstColNibble; // Current collated nibble - FLMUINT uiFirstNumNibble; // Current output nibble - FLMBYTE * pucOutPtr; // Output pointer - FLMBYTE * pucColPtr; - FLMUINT uiBytesProcessed; - - // Start at byte after sign/magnitude byte - - pucColPtr = pucFromKey + 1; - uiBytesProcessed = 1; - uiFirstColNibble = 1; - - // Determine the sign of the number - - pucOutPtr = pucToKey; - if( (bSigSign = (*pucFromKey & SIG_POS)) == 0) - { - *pucOutPtr = 0xB0; - uiFirstNumNibble = 0; - } - else - { - uiFirstNumNibble = 1; - } - - // Parse through the collated number outputting data - // to the buffer as we go. - - for( ;;) - { - // Determine what we are pointing at - - if( (ucTemp = *pucColPtr) <= COMPOUND_MARKER) - { - break; - } - - if( uiFirstColNibble++ & 1) - { - ucTemp >>= 4; - } - else - { - ucTemp &= 0x0F; - pucColPtr++; - uiBytesProcessed++; - } - - // A hex F signifies the end of a collated number with an - // odd number of nibbles - - if( ucTemp == 0x0F) - { - break; - } - - // Convert collated number nibble to BCD nibble - // and lay it in buffer - - ucTemp -= COLLATED_DIGIT_OFFSET; - - // Is number negative? - - if( !bSigSign) - { - // Negative values are ~ed - - ucTemp = (FLMBYTE)(10 -(ucTemp + 1)); - } - - if( uiFirstNumNibble++ & 1) - { - *pucOutPtr = (FLMBYTE)(ucTemp << 4); - } - else - { - *pucOutPtr++ += ucTemp; - } - - if( uiBytesProcessed == uiFromKeyLen) - { - break; - } - } - - // Append Terminator code to internal number - - *pucOutPtr++ |= (uiFirstNumNibble & 1) ? 0xFF : 0x0F; - uiToKeyLen = (FLMUINT) (pucOutPtr - pucToKey); - uiFromKeyLen = uiBytesProcessed; - rc = FERR_OK; - break; - } - - case FLM_BINARY_TYPE: - { - FLMUINT uiMaxLength; - FLMBYTE * pucSrc = pucFromKey; - - uiMaxLength = ((uiFromKeyLen >> 1) < uiMaxKeySize) - ? (FLMUINT)(uiFromKeyLen >> 1) - : (FLMUINT)uiMaxKeySize; - uiToKeyLen = 0; - while( (uiToKeyLen < uiMaxLength) && ((ucTemp = *pucSrc) >= COLLS)) - { - - // Take two bytes from source to make one byte in dest - - pucToKey[ uiToKeyLen++] = - (FLMBYTE)(((ucTemp - COLLS) << 4) + (*(pucSrc + 1) - COLLS)); - pucSrc += 2; - } - - if( (uiToKeyLen < (uiFromKeyLen >> 1)) && (*pucSrc >= COLLS)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - } - else - { - rc = FERR_OK; - uiFromKeyLen = uiToKeyLen << 1; - - // FLAIM has a bug where the binary fields don't have - // the COLL_TRUNCATED value on truncated values. - // The good news is that we know the true length of - // binary fields. - if( *pucSrc == COLL_TRUNCATED) - { - uiFromKeyLen++; - bDataRightTruncated = TRUE; - } - else if( uiToKeyLen >= pIfd->uiLimit) - { - bDataRightTruncated = TRUE; - } - } - break; - } - - case FLM_CONTEXT_TYPE: - default: - uiFromKeyLen = 5; - - uiLongValue = flmBigEndianToUINT32( pucFromKey + 1); - UD2FBA( (FLMUINT32)uiLongValue, pucToKey); - uiToKeyLen = 4; - break; - } - - if( RC_BAD( rc)) - { - goto Exit; - } - - // Allocate and Copy Value into the node - - if( uiToKeyLen) - { - FLMBYTE * pucValue; - - if( RC_BAD(rc = pKey->allocStorageSpace( pvField, - uiDataType, uiToKeyLen, 0, 0, 0, &pucValue, NULL))) - { - goto Exit; - } - - f_memcpy( pucValue, pucToKey, uiToKeyLen); - } - - // Set first sub-string and truncated flags. - - if( (pIfd->uiFlags & IFD_SUBSTRING) && !bFirstSubstring) - { - pKey->setLeftTruncated( pvField, TRUE); - } - if( bDataRightTruncated) - { - pKey->setRightTruncated( pvField, TRUE); - } - } - } - - // Compute variables for next section of compound key - // Add 1 for compound marker if still is stuff in key - - if( uiFromRemaining != uiFromKeyLen) - { - uiFromKeyLen += (FLMUINT)(bIsAsianCompound ? (FLMUINT)2 : (FLMUINT)1); - } - pucFromKey += uiFromKeyLen; /* Position to end of section */ - if( (uiFromKeyLen = (uiFromRemaining -= uiFromKeyLen)) == 0) - { - break; /* Finished with this key */ - } - while( ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) - { - pIfd++; - } - if( pIfd->uiFlags & IFD_LAST) - { - break; - } - - pIfd++; - } - - // Check if we have one field left. - - if( (pIfd->uiFlags & IFD_LAST) == 0) - { - while( (pIfd->uiFlags & IFD_LAST) == 0) - { - pIfd++; - } - if( (pIfd->uiFlags & IFD_OPTIONAL) == 0) - { - if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, - uiDataType, bFullFldPaths, pKey, &pvField))) - { - goto Exit; - } - } - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: This module will read all references of an index key. - The references will be output number defined as REFS_PER_NODE -****************************************************************************/ -RCODE flmBuildKeyPaths( - IFD_p pIfd, - FLMUINT uiFldNum, - FLMUINT uiDataType, - FLMBOOL bFullFldPaths, - FlmRecord * pKey, - void ** ppvField) -{ - RCODE rc = FERR_OK; - void * pvField; - void * pvParentField; - void * pvChildField; - FLMUINT * pFieldPath; - FLMUINT uiTempDataType; - FLMUINT uiFieldPos; - FLMUINT uiTargetFieldID; - - // Easy case first. - if( !bFullFldPaths) - { - rc = pKey->insertLast( 1, uiFldNum, uiDataType, &pvField); - goto Exit; - } - - pFieldPath = pIfd->pFieldPathPToC; - pvParentField = pKey->root(); - uiFieldPos = 0; - // Loop finding field matches. - - pvField = pKey->find( pvParentField, pFieldPath[ uiFieldPos]); - if( pvField) - { - pvParentField = pvField; - uiFieldPos++; - uiTargetFieldID = pFieldPath[ uiFieldPos]; - - // Loop finding matching children from this point on. - - for( pvChildField = pKey->firstChild( pvParentField); pvChildField; ) - { - if( pKey->getFieldID( pvChildField) == uiTargetFieldID) - { - // On the child field? - if( pFieldPath[ uiFieldPos + 1] == 0) - { - pvField = pvChildField; - // Set the data type in case the data length is zero. - pKey->allocStorageSpace( pvField, uiDataType, 0, 0, 0, 0, NULL, NULL); - break; - } - pvParentField = pvChildField; - uiFieldPos++; - uiTargetFieldID = pFieldPath[ uiFieldPos]; - pvChildField = pKey->firstChild( pvParentField); - } - else - { - pvChildField = pKey->nextSibling( pvChildField); - } - } - } - - // Insert the rest of the field path down to the value field (uiFieldPos==0). - - uiTempDataType = FLM_CONTEXT_TYPE; - for( ; pFieldPath[ uiFieldPos]; uiFieldPos++) - { - // Add the real data type for the last field, otherwise set as context. - if( pFieldPath[ uiFieldPos + 1] == 0) - { - uiTempDataType = uiDataType; - } - - if( RC_BAD( rc = pKey->insert( pvParentField, INSERT_LAST_CHILD, - pFieldPath[ uiFieldPos], uiTempDataType, &pvField))) - { - goto Exit; - } - pvParentField = pvField; - } - -Exit: - *ppvField = pvField; - return( rc); -} diff --git a/flaim/src/flkeyret.cpp b/flaim/src/flkeyret.cpp index c2bf21e..a52c458 100644 --- a/flaim/src/flkeyret.cpp +++ b/flaim/src/flkeyret.cpp @@ -37,13 +37,13 @@ FSTATIC RCODE flmKeyRetrieveCS( FSTATIC RCODE flmNextKey( FDB * pDb, LFILE * pLFile, - BTSK_p pStack, + BTSK * pStack, FLMUINT * pudRefDrn); -/*API~*********************************************************************** +/**************************************************************************** Desc: Retrieves a key from an index based on a passed-in GEDCOM tree and DRN. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmKeyRetrieve( HFDB hDb, FLMUINT uiIndex, @@ -57,10 +57,10 @@ FLMEXP RCODE FLMAPI FlmKeyRetrieve( { BTSK stack[ BH_MAX_LEVELS]; FLMBOOL bStackInitialized = FALSE; - BTSK_p pStack = &stack[0]; + BTSK * pStack = &stack[0]; DIN_STATE dinState; FDB * pDb = (FDB *)hDb; - IXD_p pIxd = NULL; + IXD * pIxd = NULL; LFILE * pLFile; FLMBYTE * pSearchKeyBuf = NULL; FLMBYTE * pKeyBuf = NULL; @@ -430,14 +430,11 @@ Exit_CS: return( rc); } - /**************************************************************************** -Name : flmKeyRetrieveCS -Area : RETRIEVAL Desc: Retrieves a key from an index based on a passed-in GEDCOM tree and DRN. VISIT: On reading data records and FO_EXCL, increment the DRN instead of positioning to the DRN and then scanning to the next record. -*END************************************************************************/ +****************************************************************************/ FSTATIC RCODE flmKeyRetrieveCS( FDB * pDb, FLMUINT uiIndex, @@ -483,7 +480,7 @@ FSTATIC RCODE flmKeyRetrieveCS( goto Exit; } - if( pCSContext->uiServerFlaimVer >= FLM_VER_4_50) + if( pCSContext->uiServerFlaimVer >= FLM_FILE_FORMAT_VER_4_50) { if( uiIndex) { @@ -586,7 +583,7 @@ Desc: Go to the next key given a valid cursor. Get & position to reference FSTATIC RCODE flmNextKey( FDB * pDb, LFILE * pLFile, - BTSK_p pStack, + BTSK * pStack, FLMUINT * puiRefDrn) { RCODE rc; @@ -636,3 +633,45 @@ FSTATIC RCODE flmNextKey( Exit: return( rc); } + +/**************************************************************************** +Desc: Given an input key tree a FLAIM collated key will be built and returned + to the user. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmKeyBuild( + HFDB hDb, + FLMUINT uiIxNum, + FLMUINT uiContainer, + FlmRecord * pRecord, + FLMUINT uiFlag, + FLMBYTE * pKeyBuf, + FLMUINT * puiKeyLenRV) +{ + RCODE rc; + FDB * pDb = (FDB *)hDb; + IXD * pIxd; + FLMBOOL bImplicitTrans = FALSE; + + if( RC_OK( rc = fdbInit( pDb, FLM_READ_TRANS, + TRUE, 0, &bImplicitTrans))) + { + if( RC_OK( rc = fdictGetIndex( + pDb->pDict, pDb->pFile->bInLimitedMode, + uiIxNum, NULL, &pIxd))) + { + + /* Build the collated key */ + + rc = KYTreeToKey( pDb, pIxd, pRecord, uiContainer, + pKeyBuf, puiKeyLenRV, uiFlag ); + } + } + + if( bImplicitTrans) + { + (void)flmAbortDbTrans( pDb); + } + + (void)fdbExit( pDb); + return( rc); +} diff --git a/flaim/src/flkeys.cpp b/flaim/src/flkeys.cpp deleted file mode 100644 index f93975f..0000000 --- a/flaim/src/flkeys.cpp +++ /dev/null @@ -1,65 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Index key building and comparison routines. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flkeys.cpp 12263 2006-01-19 14:43:23 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Desc: Given an input key tree a FLAIM collated key will be built and returned - to the user. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmKeyBuild( - HFDB hDb, - FLMUINT uiIxNum, - FLMUINT uiContainer, - FlmRecord * pRecord, - FLMUINT uiFlag, - FLMBYTE * pKeyBuf, - FLMUINT * puiKeyLenRV) -{ - RCODE rc; - FDB * pDb = (FDB *)hDb; - IXD_p pIxd; - FLMBOOL bImplicitTrans = FALSE; - - if( RC_OK( rc = fdbInit( pDb, FLM_READ_TRANS, - TRUE, 0, &bImplicitTrans))) - { - if( RC_OK( rc = fdictGetIndex( - pDb->pDict, pDb->pFile->bInLimitedMode, - uiIxNum, NULL, &pIxd))) - { - - /* Build the collated key */ - - rc = KYTreeToKey( pDb, pIxd, pRecord, uiContainer, - pKeyBuf, puiKeyLenRV, uiFlag ); - } - } - -//Exit: - if( bImplicitTrans) - (void)flmAbortDbTrans( pDb); - (void)fdbExit( pDb); - return( rc); -} diff --git a/flaim/src/flmimon.h b/flaim/src/flmimon.h index baf1561..3de9dfb 100644 --- a/flaim/src/flmimon.h +++ b/flaim/src/flmimon.h @@ -680,20 +680,20 @@ public: virtual ~F_NameTableMgr(); F_NameTable * getNameTable( - FFILE_p pFile); + FFILE * pFile); RCODE releaseNameTable( - FFILE_p pFile); + FFILE * pFile); private: FLMUINT initNameTable( - FFILE_p pFile); + FFILE * pFile); struct { F_MUTEX hMutex; - FFILE_p pFile; + FFILE * pFile; FLMUINT uiDictSeq; F_NameTable * pNameTable; } m_tablearray[ TABLE_ARRAY_SIZE]; @@ -790,7 +790,7 @@ public: private: void write_data( - FDB_p pDb, + FDB * pDb, const char * pszFDBAddress, FLMUINT uiBucket); }; @@ -828,7 +828,7 @@ public: private: void write_data( - FFILE_p pFile, + FFILE * pFile, void * pvFFileAddress, DATASTRUCT * pDataStruct); }; @@ -964,23 +964,6 @@ public: }; -/**************************************************************************** -Desc: The class that displays the event headers in gv_FlmSysData -*****************************************************************************/ -class F_EventHdrPage : public F_WebPage -{ -public: - - RCODE display( - FLMUINT uiNumParams, - const char ** ppszParams); - -private: - - RCODE displayEvent( - FEVENT_p pCurrentEvent); -}; - /********************************************************* Desc: Return HTML code that defines the SecureDbInfo popup window contents. @@ -1226,7 +1209,7 @@ protected: FLMUINT * puiBlkAddress, FLMUINT * puiLowTransID, FLMUINT * puiHighTransID, - FFILE_p * ppFile); + FFILE * * ppFile); void notFoundErr(); @@ -1644,11 +1627,11 @@ private: void gatherLockStats( STAT_GATHER * pStatGather, - FFILE_p pFile); + FFILE * pFile); void gatherCPStats( STAT_GATHER * pStatGather, - FFILE_p pFile); + FFILE * pFile); void freeCPInfoHeaders( STAT_GATHER * pStatGather); diff --git a/flaim/src/flmstat.cpp b/flaim/src/flmstat.cpp index 2ff4241..bafa6c1 100644 --- a/flaim/src/flmstat.cpp +++ b/flaim/src/flmstat.cpp @@ -1249,11 +1249,11 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Returns statistics that have been collected for a share. Notes: The statistics returned will be the statistics for ALL databases associated with the share structure. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmGetStats( FLM_STATS * pFlmStats) { diff --git a/flaim/src/flopen.cpp b/flaim/src/flopen.cpp index 377190a..d12efaa 100644 --- a/flaim/src/flopen.cpp +++ b/flaim/src/flopen.cpp @@ -24,15 +24,13 @@ #include "flaimsys.h" -#define MAX_DIRTY_PERCENT 70 - FSTATIC RCODE flmPhysFileOpen( - FDB_p pDb, - const char * pszFilePath, - const char * pszRflDir, - FLMUINT uiOpenFlags, - FLMBOOL bNewFile, - F_Restore * pRestoreObj); + FDB * pDb, + const char * pszFilePath, + const char * pszRflDir, + FLMUINT uiOpenFlags, + FLMBOOL bNewFile, + F_Restore * pRestoreObj); FSTATIC RCODE flmReadFileHdr( FDB * pDb, @@ -50,9 +48,12 @@ FSTATIC RCODE flmDoRecover( FDB * pDb, F_Restore * pRestoreObj); -/*API~*********************************************************************** +FSTATIC RCODE flmDbMonitor( + F_Thread * pThread); + +/**************************************************************************** Desc : Opens an existing FLAIM database. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbOpen( const char * pszDbFileName, const char * pszDataDir, @@ -84,19 +85,19 @@ FLMEXP RCODE FLMAPI FlmDbOpen( pszDbFileName, pszDataDir, pszRflDir, uiOpenFlags, NULL, NULL, NULL, TRUE, - pCSContext, (FDB_p *)phDbRV))) + pCSContext, (FDB * *)phDbRV))) { (void)flmCloseCSConnection( &pCSContext); } goto Exit; } - /* Open the file. */ + // Open the file if (RC_BAD( rc = flmOpenFile( NULL, pszDbFileName, pszDataDir, pszRflDir, uiOpenFlags, FALSE, - NULL, NULL, pszPassword, (FDB_p *)phDbRV))) + NULL, NULL, pszPassword, (FDB * *)phDbRV))) { goto Exit; } @@ -120,7 +121,7 @@ RCODE flmOpenOrCreateDbClientServer( CREATE_OPTS * pCreateOpts, FLMBOOL bOpening, CS_CONTEXT * pCSContext, - FDB_p * ppDb) + FDB * * ppDb) { RCODE rc = FERR_OK; FLMBOOL bAllocatedFdb = FALSE; @@ -130,11 +131,11 @@ RCODE flmOpenOrCreateDbClientServer( FLMUNICODE * puzTmp; POOL pool; FCL_WIRE Wire( pCSContext); - FDB_p pDb; + FDB * pDb; GedPoolInit( &pool, 128); - /* Allocate and initialize an FDB structure. */ + // Allocate and initialize an FDB structure if (RC_BAD( rc = flmAllocFdb( ppDb))) { @@ -144,7 +145,7 @@ RCODE flmOpenOrCreateDbClientServer( bAllocatedFdb = TRUE; - /* Convert the paths to UNICODE. */ + // Convert the paths to Unicode if( RC_BAD( rc = fcsConvertNativeToUnicode( &pool, pszDbPath, &puzDbPath))) @@ -170,7 +171,7 @@ RCODE flmOpenOrCreateDbClientServer( } } - /* Send a request to open or create the database. */ + // Send a request to open or create the database if( RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_DATABASE, (FLMUINT)((bOpening) @@ -214,10 +215,11 @@ RCODE flmOpenOrCreateDbClientServer( if (pszDictFileName) { - /* Convert the path to UNICODE. */ + // Convert the path to Unicode GedPoolReset( &pool, NULL); - if (RC_BAD( rc = fcsConvertNativeToUnicode( &pool, pszDictFileName, &puzTmp))) + if (RC_BAD( rc = fcsConvertNativeToUnicode( &pool, pszDictFileName, + &puzTmp))) { goto Exit; } @@ -230,10 +232,11 @@ RCODE flmOpenOrCreateDbClientServer( if (pszDictBuf) { - /* Convert the path to UNICODE. */ + // Convert the path to Unicode GedPoolReset( &pool, NULL); - if (RC_BAD( rc = fcsConvertNativeToUnicode( &pool, pszDictBuf, &puzTmp))) + if (RC_BAD( rc = fcsConvertNativeToUnicode( &pool, pszDictBuf, + &puzTmp))) { goto Exit; } @@ -246,7 +249,8 @@ RCODE flmOpenOrCreateDbClientServer( if (pCreateOpts) { - if (RC_BAD( rc = Wire.sendCreateOpts( WIRE_VALUE_CREATE_OPTS, pCreateOpts))) + if (RC_BAD( rc = Wire.sendCreateOpts( WIRE_VALUE_CREATE_OPTS, + pCreateOpts))) { goto Transmission_Error; } @@ -258,7 +262,7 @@ RCODE flmOpenOrCreateDbClientServer( goto Transmission_Error; } - /* Read the response. */ + // Read the response if (RC_BAD( rc = Wire.read())) { @@ -299,7 +303,7 @@ Desc: Allocates and initializes an FDB structure for a database which is to be opened or created. ****************************************************************************/ RCODE flmAllocFdb( - FDB_p * ppDb) + FDB * * ppDb) { RCODE rc = FERR_OK; FDB * pDb = NULL; @@ -320,7 +324,8 @@ RCODE flmAllocFdb( GedPoolInit( &pDb->TempPool, (MAX_KEY_SIZ * 4)); #if defined( FLM_DEBUG) && (defined( FLM_WIN) || defined( FLM_NLM)) - /* Create the semaphore for controlling access to the structure. */ + + // Create a mutex for controlling access to the structure pDb->hMutex = F_MUTEX_NULL; if (RC_BAD( rc = f_mutexCreate( &pDb->hMutex))) @@ -352,7 +357,7 @@ Desc: This routine performs all of the necessary steps to complete waiting for the open or create to complete. ****************************************************************************/ RCODE flmCompleteOpenOrCreate( - FDB_p * ppDb, + FDB * * ppDb, RCODE rc, FLMBOOL bNewFile, FLMBOOL bAllocatedFdb) @@ -362,11 +367,9 @@ RCODE flmCompleteOpenOrCreate( if (RC_OK( rc)) { - /* - If this is a newly created FFILE, we need to notify any - threads waiting for the file to be created or opened that - the create or open is now complete. - */ + // If this is a newly created FFILE, we need to notify any + // threads waiting for the file to be created or opened that + // the create or open is now complete. if (bNewFile) { @@ -379,12 +382,10 @@ RCODE flmCompleteOpenOrCreate( { FFILE * pFile = pDb->pFile; - /* - Temporarily increment the use count on the FFILE structure - so that it will NOT be put into the UNUSED list by the call - to flmDbClose below. If it is put into the UNUSED list, - it can be freed by another thread. - */ + // Temporarily increment the use count on the FFILE structure + // so that it will NOT be put into the UNUSED list by the call + // to flmDbClose below. If it is put into the UNUSED list, + // it can be freed by another thread. if (bNewFile) { @@ -433,22 +434,24 @@ RCODE flmOpenFile( F_Restore * pRestoreObj, F_FileHdlImp * pLockFileHdl, const char * pszPassword, - FDB_p * ppDb) + FDB * * ppDb) { RCODE rc; FLMBOOL bNewFile = FALSE; FLMBOOL bMutexLocked = FALSE; FLMBOOL bAllocatedFdb = FALSE; - FDB_p pDb; + FDB * pDb; FLMBOOL bNeedToOpen = FALSE; - /* Allocate and initialize an FDB structure. */ + // Allocate and initialize an FDB structure if (RC_BAD( rc = flmAllocFdb( ppDb))) { goto Exit; } + pDb = *ppDb; + if (bInternalOpen) { pDb->uiFlags |= FDB_INTERNAL_OPEN; @@ -458,23 +461,20 @@ RCODE flmOpenFile( f_mutexLock( gv_FlmSysData.hShareMutex); bMutexLocked = TRUE; - /* - Free any unused structures that have been unused for the maximum - amount of time. May unlock and re-lock the global mutex. - */ + // Free any unused structures that have been unused for the maximum + // amount of time. May unlock and re-lock the global mutex. flmCheckNUStructs( 0); - /* - Look up the file using flmFindFile to see if we already - have the file open. - */ + // Look up the file using flmFindFile to see if we already + // have the file open. if (!pFile) { bNeedToOpen = TRUE; // May unlock and re-lock the global mutex. + if (RC_BAD( rc = flmFindFile( pszDbPath, pszDataDir, &pFile))) { goto Exit; @@ -488,7 +488,8 @@ RCODE flmOpenFile( if (!pFile) { - if (RC_BAD( rc = flmAllocFile( pszDbPath, pszDataDir, pszPassword, &pFile))) + if (RC_BAD( rc = flmAllocFile( pszDbPath, pszDataDir, + pszPassword, &pFile))) { goto Exit; } @@ -502,24 +503,18 @@ RCODE flmOpenFile( flmAssert( pFile->uiFlags & DBF_BEING_OPENED); flmAssert( !(pFile->uiFlags & DBF_IN_NU_LIST)); - /* - Put the FFILE back in the NU list. FlmDbRestore removed the FFILE from - the NU list after allocating it so that it would not disappear during - the restore. When the FFILE is linked to the FDB (below), the FFILE - will be removed from the NU list. - */ + // Put the FFILE back in the NU list. FlmDbRestore removed the FFILE from + // the NU list after allocating it so that it would not disappear during + // the restore. When the FFILE is linked to the FDB (below), the FFILE + // will be removed from the NU list. flmLinkFileToNUList( pFile); - /* - Assign the lock file handle - */ + // Assign the lock file handle pFile->pLockFileHdl = pLockFileHdl; - /* - Set to NULL to prevent lock file from being released below - */ + // Set to NULL to prevent lock file from being released below pLockFileHdl = NULL; @@ -537,13 +532,13 @@ RCODE flmOpenFile( // If there is a password, verify that it matches the current password. - if ( pszPassword && pszPassword[0]) + if( pszPassword && pszPassword[0]) { - if ( pFile->pszDbPassword) + if( pFile->pszDbPassword) { - if ( f_strcmp( pszPassword, pFile->pszDbPassword) != 0) + if( f_strcmp( pszPassword, pFile->pszDbPassword) != 0) { - if (uiOpenFlags & FO_ALLOW_LIMITED) + if( uiOpenFlags & FO_ALLOW_LIMITED) { pFile->bInLimitedMode = TRUE; pFile->rcLimitedCode = RC_SET( FERR_PASSWD_INVALID); @@ -555,7 +550,7 @@ RCODE flmOpenFile( } } } - else if (uiOpenFlags & FO_ALLOW_LIMITED) + else if( uiOpenFlags & FO_ALLOW_LIMITED) { pFile->bInLimitedMode = TRUE; pFile->rcLimitedCode = RC_SET( FERR_PASSWD_INVALID); @@ -566,10 +561,7 @@ RCODE flmOpenFile( goto Exit; } } - - // If there was no password passed in, but there should have been, then oops. - - else if (pFile->pszDbPassword && pFile->pszDbPassword[0]) + else if (pFile->pszDbPassword && pFile->pszDbPassword[ 0]) { if (uiOpenFlags & FO_ALLOW_LIMITED) { @@ -586,8 +578,10 @@ RCODE flmOpenFile( // Link the FDB to the file. rc = flmLinkFdbToFile( pDb, pFile); + f_mutexUnlock( gv_FlmSysData.hShareMutex); bMutexLocked = FALSE; + if (RC_BAD(rc)) { goto Exit; @@ -606,16 +600,26 @@ RCODE flmOpenFile( } } - // Start a checkpoint thread - if (bNewFile && !(uiOpenFlags & FO_DONT_REDO_LOG)) { + // Start the checkpoint thread + flmAssert( pFile->pCPThrd == NULL); + if (RC_BAD( rc = flmStartCPThread( pFile))) { goto Exit; } + // Start the database monitor thread + + flmAssert( pFile->pMonitorThrd == NULL); + + if (RC_BAD( rc = flmStartDbMonitorThread( pFile))) + { + goto Exit; + } + if( !(uiOpenFlags & FO_DONT_RESUME_BACKGROUND_THREADS)) { if (RC_BAD( rc = flmStartBackgrndIxThrds( pDb))) @@ -649,7 +653,7 @@ Exit: /**************************************************************************** Desc: This routine checks to see if it is OK for another FDB to use a file. If so, it increments the file's use counter. NOTE: This routine - assumes that the calling routine has locked the semaphore. + assumes that the calling routine has locked the global mutex. ****************************************************************************/ RCODE flmVerifyFileUse( F_MUTEX hMutex, @@ -744,22 +748,18 @@ RCODE flmCreateLckFile( F_FileHdlImp * pLockFileHdl = NULL; FLMUINT uiBaseLen; - /* - Extract the base name and put a .lck extension on it to create - the full path for the .lck file. - */ + // Extract the base name and put a .lck extension on it to create + // the full path for the .lck file. flmGetDbBasePath( szLockPath, pszFilePath, &uiBaseLen); f_strcpy( &szLockPath[ uiBaseLen], ".lck"); - /* - Attempt to create the lock file. If that succeeds, we are - OK to use the database. If it fails, the lock file may have - been left because of a crash if FLAIM was not shut down properly. - Hence, we first try to delete the file. If that succeeds, we - then attempt to create the file again. If it, or the 2nd create - fail, we simply return an access denied error. - */ + // Attempt to create the lock file. If that succeeds, we are + // OK to use the database. If it fails, the lock file may have + // been left because of a crash if FLAIM was not shut down properly. + // Hence, we first try to delete the file. If that succeeds, we + // then attempt to create the file again. If it, or the 2nd create + // fail, we simply return an access denied error. #ifndef FLM_UNIX if( RC_BAD( gv_FlmSysData.pFileSystem->Create( szLockPath, @@ -829,19 +829,17 @@ RCODE flmGetExclAccess( FLMBOOL bNotifyWaiters = FALSE; FLMBOOL bMutexLocked = FALSE; - /* - If pFile->pLockFileHdl is non-NULL, it means that we currently - have the file locked with a lock file. There is no need to make - this test inside a mutex lock, because the lock file handle can only - be set to NULL when the use count goes to zero, meaning that the thread - that sets it to NULL will be the only thread accessing it. - - However, it is possible that two or more threads will simultaneously - test pLockFileHdl and discover that it is NULL. In that case, - we allow one thread to proceed and attempt to get a lock on the file - while the other threads wait to be notified of the results of the - attempt to lock the file. - */ + // If pFile->pLockFileHdl is non-NULL, it means that we currently + // have the file locked with a lock file. There is no need to make + // this test inside a mutex lock, because the lock file handle can only + // be set to NULL when the use count goes to zero, meaning that the thread + // that sets it to NULL will be the only thread accessing it. + // + // However, it is possible that two or more threads will simultaneously + // test pLockFileHdl and discover that it is NULL. In that case, + // we allow one thread to proceed and attempt to get a lock on the file + // while the other threads wait to be notified of the results of the + // attempt to lock the file. if (pFile->pLockFileHdl) { @@ -854,11 +852,9 @@ RCODE flmGetExclAccess( if (pFile->bBeingLocked) { - /* - If the file is in the process of being locked by another - thread, wait for the lock to complete. NOTE: flmWaitNotifyReq will - re-lock the mutex before returning. - */ + // If the file is in the process of being locked by another + // thread, wait for the lock to complete. NOTE: flmWaitNotifyReq will + // re-lock the mutex before returning. rc = flmWaitNotifyReq( gv_FlmSysData.hShareMutex, &pFile->pLockNotifies, (void *)0); @@ -867,12 +863,10 @@ RCODE flmGetExclAccess( else { - /* - No other thread was attempting to lock the file, so - set this thread up to make the attempt. Other threads - coming in at this point will be required to wait and - be notified of the results. - */ + // No other thread was attempting to lock the file, so + // set this thread up to make the attempt. Other threads + // coming in at this point will be required to wait and + // be notified of the results. pFile->bBeingLocked = TRUE; bNotifyWaiters = TRUE; @@ -892,7 +886,7 @@ Exit: FNOTIFY * pNotify; F_SEM hSem; - /* Notify any thread waiting on the lock what its status is. */ + // Notify any thread waiting on the lock what its status is if( !bMutexLocked) { @@ -929,7 +923,7 @@ Desc: This routine checks to see if it is OK for another FDB to use a file. assumes that the global mutex is NOT locked. ****************************************************************************/ FSTATIC RCODE flmPhysFileOpen( - FDB_p pDb, + FDB * pDb, const char * pszFilePath, // File name const char * pszRflDir, // RFL directory FLMUINT uiOpenFlags, // Flags for doing physical open @@ -952,6 +946,7 @@ FSTATIC RCODE flmPhysFileOpen( { bAllowLimitedMode = TRUE; } + if( RC_BAD( rc = flmReadFileHdr( pDb, pFile->pucLogHdrWriteBuf, &LogHdr, bAllowLimitedMode))) { @@ -1017,10 +1012,8 @@ FSTATIC RCODE flmPhysFileOpen( } } - /* - We must have exclusive access. Create a lock file for that - purpose, if there is not already a lock file. - */ + // We must have exclusive access. Create a lock file for that + // purpose, if there is not already a lock file. if (!pFile->pLockFileHdl) { @@ -1041,7 +1034,7 @@ FSTATIC RCODE flmPhysFileOpen( goto Exit; } } - + Exit: if (RC_BAD( rc)) @@ -1058,17 +1051,18 @@ Desc: This routine finishes up after creating a new FFILE structure. It of the status of the operation. ****************************************************************************/ RCODE flmNewFileFinish( - FFILE * pFile, /* Pointer to FFILE structure. */ - RCODE OpenRc) /* Return code to send to other threads that are - waiting for the open to complete. */ + FFILE * pFile, + RCODE OpenRc) { FNOTIFY * pNotify; F_SEM hSem; if (!pFile) + { goto Exit; + } - /* Notify anyone waiting on the operation what its status is. */ + // Notify anyone waiting on the operation what its status is pNotify = pFile->pOpenNotifies; while (pNotify) @@ -1081,7 +1075,9 @@ RCODE flmNewFileFinish( pFile->pOpenNotifies = NULL; pFile->uiFlags &= (~(DBF_BEING_OPENED)); + Exit: + return OpenRc; } @@ -1230,7 +1226,7 @@ RCODE flmAllocFile( const char * pszDbPath, const char * pszDataDir, const char * pszDbPassword, - FFILE_p * ppFile) + FFILE * * ppFile) { RCODE rc = FERR_OK; FLMUINT uiAllocLen; @@ -1398,6 +1394,7 @@ Exit: { pFileItemId2->Release(); } + if( RC_BAD( rc)) { if( pFile) @@ -1448,16 +1445,16 @@ FSTATIC RCODE flmReadFileHdr( // Create the database wrapping key from the data in Log Header #ifdef FLM_USE_NICI - if( pFile->FileHdr.uiVersionNum >= FLM_VER_4_60) + if( pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) { FLMUINT32 ui32KeyLen; ui32KeyLen = FB2UW( &pFile->ucLastCommittedLogHdr[ LOG_DATABASE_KEY_LEN]); - // VISIT: Looks like the database was created by a version of flaim that did not have - // encryption. Now we are opening it with a version that does. Do we want to upgrade - // automatically? Perhaps we need a different version, one that says we have encryption or don't??? - // This code will force limited mode and not upgrade. + // Looks like the database was created by a version of FLAIM that did not + // have encryption. Now we are opening it with a version that does. + // Allow the database to be opened in limited mode (i.e., no support + // for encryption). if (ui32KeyLen == 0) { @@ -1483,8 +1480,10 @@ FSTATIC RCODE flmReadFileHdr( goto Exit; } - // If the key was encrypted in a password, then the pszDbPassword parameter better be the key used to encrypt it. - // If the key was not encrypted in a password, the pszDbPassword parameter should be NULL. + // If the key was encrypted in a password, then the pszDbPassword + // parameter better be the key used to encrypt it. + // If the key was not encrypted in a password, the pszDbPassword + // parameter should be NULL. if( RC_BAD( rc = pFile->pDbWrappingKey->setKeyFromStore( &pFile->ucLastCommittedLogHdr[LOG_DATABASE_KEY], @@ -1644,6 +1643,28 @@ Exit: return( rc); } +/*************************************************************************** +Desc: +*****************************************************************************/ +RCODE flmStartDbMonitorThread( + FFILE * pFile) +{ + RCODE rc = FERR_OK; + + flmAssert( pFile->pMonitorThrd == NULL); + + if (RC_BAD( rc = f_threadCreate( &pFile->pMonitorThrd, + flmDbMonitor, "FLAIM Database Monitor", + FLM_DB_MONITOR_THREAD_GROUP, 0, pFile, NULL, 32000))) + { + goto Exit; + } + +Exit: + + return( rc); +} + /**************************************************************************** Desc: This routine functions as a thread. It monitors open files and frees up files which have been closed longer than the maximum @@ -1734,7 +1755,8 @@ FSTATIC RCODE flmCPThread( if (bForceCheckpoint || (gv_FlmSysData.SCacheMgr.uiMaxDirtyCache && - (pFile->uiDirtyCacheCount + pFile->uiLogCacheCount) * pFile->FileHdr.uiBlockSize > + (pFile->uiDirtyCacheCount + pFile->uiLogCacheCount) * + pFile->FileHdr.uiBlockSize > gv_FlmSysData.SCacheMgr.uiMaxDirtyCache)) { if (RC_BAD( dbWriteLock( pFile, pDbStats))) @@ -1886,13 +1908,13 @@ Desc: See if a given database URL name is a client/server connection. **************************************************************************/ RCODE flmGetCSConnection( const char * pszUrlName, - CS_CONTEXT_p * ppCSContextRV) + CS_CONTEXT * * ppCSContextRV) { RCODE rc = FERR_OK; FCL_WIRE Wire; const char * pszHostName = NULL; FLMINT iSubProtocol; - CS_CONTEXT_p pCSContext = NULL; + CS_CONTEXT * pCSContext = NULL; FUrl_p pUrl = NULL; FCS_IPIS * pIpIStream = NULL; FCS_IPOS * pIpOStream = NULL; @@ -1907,9 +1929,7 @@ RCODE flmGetCSConnection( *ppCSContextRV = NULL; - /* - Allocate a C/S context - */ + // Allocate a C/S context if (RC_BAD( rc = f_calloc( sizeof( CS_CONTEXT), &pCSContext))) { @@ -1917,7 +1937,7 @@ RCODE flmGetCSConnection( } GedPoolInit( &pCSContext->pool, 8192); - /* Create a URL out of the URL name. */ + // Create a URL out of the URL name if ((pUrl = f_new FUrl) == NULL) { @@ -1932,20 +1952,18 @@ RCODE flmGetCSConnection( if( pUrl->IsLocal()) { - goto Exit; // Returns SUCCESS in rc and NULL in ppCSContextRV + goto Exit; } - /* Determine the sub-protocol to use. */ + // Determine the sub-protocol to use iSubProtocol = pUrl->GetSubProtocol(); if( iSubProtocol == NO_SUB_PROTOCOL) { - goto Exit; // Returns SUCCESS in rc and NULL in ppCSContext + goto Exit; } - /* - Get the address type. - */ + // Get the address type uiAddrType = pUrl->GetAddrType(); @@ -1988,7 +2006,7 @@ RCODE flmGetCSConnection( goto Exit; } - /* Configure the I/O streams. */ + // Configure the I/O streams if( iSubProtocol == TCP_SUB_PROTOCOL) { @@ -2089,9 +2107,9 @@ RCODE flmGetCSConnection( pCSContext->uiSessionId = FCS_INVALID_ID; f_memcpy( pCSContext->pucAddr, pUrl->GetAddress(), FLM_CS_MAX_ADDR_LEN); f_strncpy( pCSContext->pucUrl, pszUrlName, FLM_CS_MAX_ADDR_LEN - 1); - pCSContext->pucUrl[ FLM_CS_MAX_ADDR_LEN - 1] = '\0'; // Truncate the string (if necessary) + pCSContext->pucUrl[ FLM_CS_MAX_ADDR_LEN - 1] = '\0'; - /* Configure the wire object */ + // Configure the wire object Wire.setContext( pCSContext); @@ -2099,7 +2117,7 @@ RCODE flmGetCSConnection( Retry_Connect: - /* Send a request to open a session. */ + // Send a request to open a session if (RC_BAD( rc = Wire.sendOpcode( FCS_OPCLASS_SESSION, FCS_OP_SESSION_OPEN))) { @@ -2123,7 +2141,7 @@ Retry_Connect: goto Exit; } - /* Read the response. */ + // Read the response if (RC_BAD( rc = Wire.read())) { @@ -2138,11 +2156,17 @@ Retry_Connect: switch (uiClientVersion) { case FCS_VERSION_1_1_0: + { break; + } + case FCS_VERSION_1_1_1: + { uiClientVersion = FCS_VERSION_1_1_0; goto Retry_Connect; + } } + goto Exit; } @@ -2150,12 +2174,10 @@ Retry_Connect: pCSContext->uiSessionId = Wire.getSessionId(); pCSContext->uiSessionCookie = Wire.getSessionCookie(); pCSContext->uiServerFlaimVer = Wire.getFlaimVersion(); - if( pCSContext->uiServerFlaimVer < FLM_VER_4_3) + if( pCSContext->uiServerFlaimVer < FLM_FILE_FORMAT_VER_4_3) { - /* - Versions of FLAIM prior to 4.3 did not send the server's code - version. However, they all supported GEDCOM as a wire format. - */ + // Versions of FLAIM prior to 4.3 did not send the server's code + // version. However, they all supported GEDCOM as a wire format. pCSContext->bGedcomSupport = TRUE; } @@ -2165,18 +2187,22 @@ Retry_Connect: ? TRUE : FALSE; } + *ppCSContextRV = pCSContext; pCSContext = NULL; Exit: + if (RC_BAD( rc) || pCSContext) { flmCloseCSConnection( &pCSContext); } + if (pUrl) { pUrl->Release(); } + return( rc); } @@ -2184,14 +2210,14 @@ Exit: Desc: Close a client/server connection. **************************************************************************/ void flmCloseCSConnection( - CS_CONTEXT_p * ppCSContext) + CS_CONTEXT * * ppCSContext) { if( !(*ppCSContext)) { return; } - CS_CONTEXT_p pCSContext = *ppCSContext; + CS_CONTEXT * pCSContext = *ppCSContext; FCL_WIRE Wire( pCSContext); // Send a message to the FLAIM server indicating we are closing @@ -2223,17 +2249,16 @@ void flmCloseCSConnection( goto Clear_Session_ID; } - /* - Read the response. Ignore the return code. - */ + // Read the response. Ignore the return code. (void)Wire.read(); Clear_Session_ID: + pCSContext->uiSessionId = FCS_INVALID_ID; } - /* Free all of the input and output streams and the URL. */ + // Free all of the input and output streams and the URL if( pCSContext->pODataStream) { @@ -2268,3 +2293,135 @@ Clear_Session_ID: GedPoolFree( &pCSContext->pool); f_free( ppCSContext); } + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE flmDbMonitor( + F_Thread * pThread) +{ + RCODE rc = FERR_OK; + FFILE * pFile = (FFILE *)pThread->getParm1(); + FLMUINT uiLastRflEventTime = 0; + FLMUINT64 ui64LastRflEventSize = 0; + + for (;;) + { + if( pThread->getShutdownFlag()) + { + break; + } + + if (pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_61) + { + FLMUINT64 ui64RflDiskUsage; + FLMUINT64 ui64RflDiskThreshold; + FLMUINT uiRflDiskLimitSpaceFreq; + FLMUINT uiRflDiskLimitTimeFreq; + + f_mutexLock( gv_FlmSysData.hShareMutex); + + ui64RflDiskThreshold = ((FLMUINT64) + FB2UD( &pFile->ucLastCommittedLogHdr[ + LOG_RFL_DISK_SPACE_THRESHOLD])) << 10; + + uiRflDiskLimitSpaceFreq = + FB2UD( &pFile->ucLastCommittedLogHdr[ LOG_RFL_LIMIT_SPACE_FREQ]); + + uiRflDiskLimitTimeFreq = + FB2UD( &pFile->ucLastCommittedLogHdr[ LOG_RFL_LIMIT_TIME_FREQ]); + + ui64RflDiskUsage = pFile->ui64RflDiskUsage; + + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + if( ui64RflDiskThreshold && ui64RflDiskUsage > ui64RflDiskThreshold) + { + FLMUINT uiCurrentTime; + char szRflDir[ F_PATH_MAX_SIZE]; + char szRflPrefix[ F_FILENAME_SIZE]; + + f_mutexLock( gv_FlmSysData.hShareMutex); + + f_strcpy( szRflDir, pFile->pRfl->getRflDirPtr()); + f_strcpy( szRflPrefix, pFile->pRfl->getDbPrefixPtr()); + + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + f_timeGetSeconds( &uiCurrentTime); + + if( !uiRflDiskLimitSpaceFreq && !uiRflDiskLimitTimeFreq) + { + uiRflDiskLimitTimeFreq = 30; + } + + if( uiLastRflEventTime || ui64LastRflEventSize) + { + if( !uiRflDiskLimitSpaceFreq || + (ui64LastRflEventSize && ui64RflDiskUsage < + ui64LastRflEventSize + uiRflDiskLimitSpaceFreq)) + { + if( !uiRflDiskLimitTimeFreq || + (uiLastRflEventTime && uiCurrentTime < + uiLastRflEventTime + uiRflDiskLimitTimeFreq)) + { + goto DoneWithRflSizeEvent; + } + } + } + + // Calculate the actual disk usage to make sure we are still + // over the limit + + if( RC_BAD( rc = flmRflCalcDiskUsage( szRflDir, szRflPrefix, + pFile->FileHdr.uiVersionNum, &ui64RflDiskUsage))) + { + goto Exit; + } + + if( ui64RflDiskUsage > ui64RflDiskThreshold) + { + // Log a message + + flmLogMessage( FLM_WARN_MESSAGE, FLM_YELLOW, FLM_BLACK, + "WARNING: The RFL has exceeded the specified size limit of %i64u", + ui64RflDiskThreshold); + + if( gv_FlmSysData.SizeEvents.pEventCBList) + { + FLM_RFL_SIZE_EVENT rflSizeEvent; + + rflSizeEvent.pszRflDir = szRflDir; + rflSizeEvent.ui64RflDiskUsage = ui64RflDiskUsage; + + flmDoEventCallback( F_EVENT_SIZE, F_EVENT_RFL_SIZE, + &rflSizeEvent, NULL); + } + + uiLastRflEventTime = uiCurrentTime; + ui64LastRflEventSize = ui64RflDiskUsage; + } + else + { + // Reset the disk usage. There may have been changes since + // calling flmRflCalcDiskUsage, but this is only an estimate + // anyway. + + f_mutexLock( gv_FlmSysData.hShareMutex); + pFile->ui64RflDiskUsage = ui64RflDiskUsage; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + uiLastRflEventTime = 0; + ui64LastRflEventSize = 0; + } + } +DoneWithRflSizeEvent:; + } + +Exit: + + f_sleep( 1000); + } + + return( FERR_OK); +} diff --git a/flaim/src/flrcodes.cpp b/flaim/src/flrcodes.cpp deleted file mode 100644 index efd8ba7..0000000 --- a/flaim/src/flrcodes.cpp +++ /dev/null @@ -1,292 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Convert error codes into strings. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flrcodes.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Desc: Returns a pointer to the ASCII string representation of a FLAIM - return code. -*END************************************************************************/ -FLMEXP const char * FLMAPI FlmErrorString( - RCODE rc) -{ - const char * pszStr; - - if( (pszStr = flmErrorString( rc)) == NULL) - { - pszStr = "Unknown Error"; - } - - return( pszStr); -} - -/**************************************************************************** -Desc: Returns a pointer to a static RCODE string or NULL if the RCODE - cannot be mapped -****************************************************************************/ -const char * flmErrorString( - RCODE rc) -{ - if( RC_OK( rc)) - { - return( "FERR_OK"); - } - -#define CASE_RET( c) \ - case c: return( #c ) - - switch( rc) - { - CASE_RET( FERR_BOF_HIT); - CASE_RET( FERR_EOF_HIT); - CASE_RET( FERR_END); - CASE_RET( FERR_EXISTS); - CASE_RET( FERR_FAILURE); - CASE_RET( FERR_NOT_FOUND); - CASE_RET( FERR_BAD_DICT_ID); - CASE_RET( FERR_BAD_CONTAINER); - CASE_RET( FERR_NO_ROOT_BLOCK); - CASE_RET( FERR_BAD_DRN); - CASE_RET( FERR_BAD_FIELD_NUM); - CASE_RET( FERR_BAD_FIELD_TYPE); - CASE_RET( FERR_BAD_HDL); - CASE_RET( FERR_BAD_IX); - CASE_RET( FERR_BACKUP_ACTIVE); - CASE_RET( FERR_SERIAL_NUM_MISMATCH); - CASE_RET( FERR_BAD_RFL_DB_SERIAL_NUM); - CASE_RET( FERR_BTREE_ERROR); - CASE_RET( FERR_BTREE_FULL); - CASE_RET( FERR_BAD_RFL_FILE_NUMBER); - CASE_RET( FERR_CANNOT_DEL_ITEM); - CASE_RET( FERR_CANNOT_MOD_FIELD_TYPE); - CASE_RET( FERR_CONV_BAD_DEST_TYPE); - CASE_RET( FERR_CONV_BAD_DIGIT); - CASE_RET( FERR_CONV_BAD_SRC_TYPE); - CASE_RET( FERR_RFL_FILE_NOT_FOUND); - CASE_RET( FERR_CONV_DEST_OVERFLOW); - CASE_RET( FERR_CONV_ILLEGAL); - CASE_RET( FERR_CONV_NULL_SRC); - CASE_RET( FERR_CONV_NULL_DEST); - CASE_RET( FERR_CONV_NUM_OVERFLOW); - CASE_RET( FERR_CONV_NUM_UNDERFLOW); - CASE_RET( FERR_DATA_ERROR); - CASE_RET( FERR_DD_ERROR); - CASE_RET( FERR_INVALID_FILE_SEQUENCE); - CASE_RET( FERR_ILLEGAL_OP); - CASE_RET( FERR_DUPLICATE_DICT_REC); - CASE_RET( FERR_CANNOT_CONVERT); - CASE_RET( FERR_UNSUPPORTED_VERSION); - CASE_RET( FERR_FILE_ER); - CASE_RET( FERR_BAD_FIELD_LEVEL); - CASE_RET( FERR_GED_BAD_RECID); - CASE_RET( FERR_GED_BAD_VALUE); - CASE_RET( FERR_GED_MAXLVLNUM); - CASE_RET( FERR_GED_SKIP_LEVEL); - CASE_RET( FERR_ILLEGAL_TRANS); - CASE_RET( FERR_ILLEGAL_TRANS_OP); - CASE_RET( FERR_INCOMPLETE_LOG); - CASE_RET( FERR_INVALID_BLOCK_LENGTH); - CASE_RET( FERR_INVALID_TAG); - CASE_RET( FERR_KEY_NOT_FOUND); - CASE_RET( FERR_VALUE_TOO_LARGE); - CASE_RET( FERR_MEM); - CASE_RET( FERR_BAD_RFL_SERIAL_NUM); - CASE_RET( FERR_NEWER_FLAIM); - CASE_RET( FERR_CANNOT_MOD_FIELD_STATE); - CASE_RET( FERR_NO_MORE_DRNS); - CASE_RET( FERR_NO_TRANS_ACTIVE); - CASE_RET( FERR_NOT_UNIQUE); - CASE_RET( FERR_NOT_FLAIM); - CASE_RET( FERR_NULL_RECORD); - CASE_RET( FERR_NO_HTTP_STACK); - CASE_RET( FERR_OLD_VIEW); - CASE_RET( FERR_PCODE_ERROR); - CASE_RET( FERR_PERMISSION); - CASE_RET( FERR_SYNTAX); - CASE_RET( FERR_CALLBACK_FAILURE); - CASE_RET( FERR_TRANS_ACTIVE); - CASE_RET( FERR_RFL_TRANS_GAP); - CASE_RET( FERR_BAD_COLLATED_KEY); - CASE_RET( FERR_UNSUPPORTED_FEATURE); - CASE_RET( FERR_MUST_DELETE_INDEXES); - CASE_RET( FERR_RFL_INCOMPLETE); - CASE_RET( FERR_CANNOT_RESTORE_RFL_FILES); - CASE_RET( FERR_INCONSISTENT_BACKUP); - CASE_RET( FERR_BLOCK_CHECKSUM); - CASE_RET( FERR_ABORT_TRANS); - CASE_RET( FERR_NOT_RFL); - CASE_RET( FERR_BAD_RFL_PACKET); - CASE_RET( FERR_DATA_PATH_MISMATCH); - CASE_RET( FERR_HTTP_REGISTER_FAILURE); - CASE_RET( FERR_HTTP_DEREG_FAILURE); - CASE_RET( FERR_IX_FAILURE); - CASE_RET( FERR_HTTP_SYMS_EXIST); - CASE_RET( FERR_FILE_EXISTS); - CASE_RET( FERR_SYM_RESOLVE_FAIL); - CASE_RET( FERR_BAD_SERVER_CONNECTION); - CASE_RET( FERR_CLOSING_DATABASE); - CASE_RET( FERR_INVALID_CRC); - CASE_RET( FERR_KEY_OVERFLOW); - CASE_RET( FERR_NOT_IMPLEMENTED); - CASE_RET( FERR_MUTEX_OPERATION_FAILED); - CASE_RET( FERR_MUTEX_UNABLE_TO_LOCK); - CASE_RET( FERR_SEM_OPERATION_FAILED); - CASE_RET( FERR_SEM_UNABLE_TO_LOCK); - CASE_RET( FERR_BAD_REFERENCE); - CASE_RET( FERR_UNALLOWED_UPGRADE); - CASE_RET( FERR_ID_RESERVED); - CASE_RET( FERR_CANNOT_RESERVE_ID); - CASE_RET( FERR_DUPLICATE_DICT_NAME); - CASE_RET( FERR_CANNOT_RESERVE_NAME); - CASE_RET( FERR_BAD_DICT_DRN); - CASE_RET( FERR_CANNOT_MOD_DICT_REC_TYPE); - CASE_RET( FERR_PURGED_FLD_FOUND); - CASE_RET( FERR_DUPLICATE_INDEX); - CASE_RET( FERR_TOO_MANY_OPEN_DBS); - CASE_RET( FERR_ACCESS_DENIED); - CASE_RET( FERR_CACHE_ERROR); - CASE_RET( FERR_BLOB_MISSING_FILE); - CASE_RET( FERR_NO_REC_FOR_KEY); - CASE_RET( FERR_DB_FULL); - CASE_RET( FERR_TIMEOUT); - CASE_RET( FERR_CURSOR_SYNTAX); - CASE_RET( FERR_THREAD_ERR); - CASE_RET( FERR_UNIMPORT_SYMBOL); - CASE_RET( FERR_EMPTY_QUERY); - CASE_RET( FERR_INDEX_OFFLINE); - CASE_RET( FERR_TRUNCATED_KEY); - CASE_RET( FERR_INVALID_PARM); - CASE_RET( FERR_USER_ABORT); - CASE_RET( FERR_RFL_DEVICE_FULL); - CASE_RET( FERR_MUST_WAIT_CHECKPOINT); - CASE_RET( FERR_NAMED_SEMAPHORE_ERR); - CASE_RET( FERR_LOAD_LIBRARY); - CASE_RET( FERR_UNLOAD_LIBRARY); - CASE_RET( FERR_IMPORT_SYMBOL); - CASE_RET( FERR_BLOCK_FULL); - CASE_RET( FERR_BAD_BASE64_ENCODING); - CASE_RET( FERR_MISSING_FIELD_TYPE); - CASE_RET( FERR_BAD_DATA_LENGTH); - CASE_RET( FERR_IO_ACCESS_DENIED); - CASE_RET( FERR_IO_BAD_FILE_HANDLE); - CASE_RET( FERR_IO_COPY_ERR); - CASE_RET( FERR_IO_DISK_FULL); - CASE_RET( FERR_IO_END_OF_FILE); - CASE_RET( FERR_IO_OPEN_ERR); - CASE_RET( FERR_IO_SEEK_ERR); - CASE_RET( FERR_IO_MODIFY_ERR); - CASE_RET( FERR_IO_PATH_NOT_FOUND); - CASE_RET( FERR_IO_TOO_MANY_OPEN_FILES); - CASE_RET( FERR_IO_PATH_TOO_LONG); - CASE_RET( FERR_IO_NO_MORE_FILES); - CASE_RET( FERR_DELETING_FILE); - CASE_RET( FERR_IO_FILE_LOCK_ERR); - CASE_RET( FERR_IO_FILE_UNLOCK_ERR); - CASE_RET( FERR_IO_PATH_CREATE_FAILURE); - CASE_RET( FERR_IO_RENAME_FAILURE); - CASE_RET( FERR_IO_INVALID_PASSWORD); - CASE_RET( FERR_SETTING_UP_FOR_READ); - CASE_RET( FERR_SETTING_UP_FOR_WRITE); - CASE_RET( FERR_IO_AT_PATH_ROOT); - CASE_RET( FERR_INITIALIZING_IO_SYSTEM); - CASE_RET( FERR_FLUSHING_FILE); - CASE_RET( FERR_IO_INVALID_PATH); - CASE_RET( FERR_IO_CONNECT_ERROR); - CASE_RET( FERR_OPENING_FILE); - CASE_RET( FERR_DIRECT_OPENING_FILE); - CASE_RET( FERR_CREATING_FILE); - CASE_RET( FERR_DIRECT_CREATING_FILE); - CASE_RET( FERR_READING_FILE); - CASE_RET( FERR_DIRECT_READING_FILE); - CASE_RET( FERR_WRITING_FILE); - CASE_RET( FERR_DIRECT_WRITING_FILE); - CASE_RET( FERR_POSITIONING_IN_FILE); - CASE_RET( FERR_GETTING_FILE_SIZE); - CASE_RET( FERR_TRUNCATING_FILE); - CASE_RET( FERR_PARSING_FILE_NAME); - CASE_RET( FERR_CLOSING_FILE); - CASE_RET( FERR_GETTING_FILE_INFO); - CASE_RET( FERR_EXPANDING_FILE); - CASE_RET( FERR_GETTING_FREE_BLOCKS); - CASE_RET( FERR_CHECKING_FILE_EXISTENCE); - CASE_RET( FERR_RENAMING_FILE); - CASE_RET( FERR_SETTING_FILE_INFO); - CASE_RET( FERR_NICI_CONTEXT); - CASE_RET( FERR_NICI_FIND_INIT); - CASE_RET( FERR_NICI_FIND_OBJECT); - CASE_RET( FERR_NICI_WRAPKEY_NOT_FOUND); - CASE_RET( FERR_NICI_ATTRIBUTE_VALUE); - CASE_RET( FERR_NICI_BAD_ATTRIBUTE); - CASE_RET( FERR_NICI_BAD_RANDOM); - CASE_RET( FERR_NICI_WRAPKEY_FAILED); - CASE_RET( FERR_NICI_GENKEY_FAILED); - CASE_RET( FERR_REQUIRE_PASSWD); - CASE_RET( FERR_NICI_SHROUDKEY_FAILED); - CASE_RET( FERR_NICI_UNSHROUDKEY_FAILED); - CASE_RET( FERR_NICI_UNWRAPKEY_FAILED); - CASE_RET( FERR_NICI_ENC_INIT_FAILED); - CASE_RET( FERR_NICI_ENCRYPT_FAILED); - CASE_RET( FERR_NICI_DECRYPT_INIT_FAILED); - CASE_RET( FERR_NICI_DECRYPT_FAILED); - CASE_RET( FERR_NICI_INIT_FAILED); - CASE_RET( FERR_NICI_KEY_NOT_FOUND); - CASE_RET( FERR_NICI_INVALID_ALGORITHM); - CASE_RET( FERR_FLD_NOT_ENCRYPTED); - CASE_RET( FERR_BAD_ENCDEF_ID); - CASE_RET( FERR_CANNOT_SET_KEY); - CASE_RET( FERR_MISSING_ENC_TYPE); - CASE_RET( FERR_CANNOT_MOD_ENC_TYPE); - CASE_RET( FERR_MISSING_ENC_KEY); - CASE_RET( FERR_CANNOT_CHANGE_KEY); - CASE_RET( FERR_BAD_ENC_KEY); - CASE_RET( FERR_CANNOT_MOD_ENC_STATE); - CASE_RET( FERR_DATA_SIZE_MISMATCH); - CASE_RET( FERR_ENCRYPTION_UNAVAILABLE); - CASE_RET( FERR_PURGED_ENCDEF_FOUND); - CASE_RET( FERR_FLD_NOT_DECRYPTED); - CASE_RET( FERR_PBE_ENCRYPT_FAILED); - CASE_RET( FERR_DIGEST_FAILED); - CASE_RET( FERR_DIGEST_INIT_FAILED); - CASE_RET( FERR_EXTRACT_KEY_FAILED); - CASE_RET( FERR_INJECT_KEY_FAILED); - CASE_RET( FERR_PBE_DECRYPT_FAILED); - CASE_RET( FERR_PASSWD_INVALID); - CASE_RET( FERR_SVR_NOIP_ADDR); - CASE_RET( FERR_SVR_SOCK_FAIL); - CASE_RET( FERR_SVR_CONNECT_FAIL); - CASE_RET( FERR_SVR_BIND_FAIL); - CASE_RET( FERR_SVR_LISTEN_FAIL); - CASE_RET( FERR_SVR_ACCEPT_FAIL); - CASE_RET( FERR_SVR_SELECT_ERR); - CASE_RET( FERR_SVR_SOCKOPT_FAIL); - CASE_RET( FERR_SVR_DISCONNECT); - CASE_RET( FERR_SVR_READ_FAIL); - CASE_RET( FERR_SVR_WRT_FAIL); - CASE_RET( FERR_SVR_READ_TIMEOUT); - CASE_RET( FERR_SVR_WRT_TIMEOUT); - CASE_RET( FERR_SVR_ALREADY_CLOSED); - default: - return( NULL); - } -} diff --git a/flaim/src/flrddrct.cpp b/flaim/src/flrddrct.cpp index 9dd62f5..f7a2db7 100644 --- a/flaim/src/flrddrct.cpp +++ b/flaim/src/flrddrct.cpp @@ -32,18 +32,16 @@ FSTATIC RCODE flmRecordRetrieveCS( FlmRecord ** ppRecord, FLMUINT * puiDrnRV); - -/*API~*********************************************************************** -Desc : Retrieves a single record from a container. -*END************************************************************************/ +/**************************************************************************** +Desc: Retrieves a single record from a container. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmRecordRetrieve( HFDB hDb, FLMUINT uiContainer, FLMUINT uiDrn, FLMUINT uiFlag, FlmRecord ** ppRecord, - FLMUINT * puiDrnRV - ) + FLMUINT * puiDrnRV) { FLMUINT uiKeyRelPos; FLMBOOL bTransStarted; @@ -51,7 +49,7 @@ FLMEXP RCODE FLMAPI FlmRecordRetrieve( LFILE * pLFile; BTSK stack[ BH_MAX_LEVELS]; FLMBOOL bStackInitialized = FALSE; - BTSK_p pStack; + BTSK * pStack; FLMBYTE pSearchBuf[ DRN_KEY_SIZ + 4]; FLMBYTE pKeyBuf[ DRN_KEY_SIZ + 4]; FDB * pDb = (FDB *)hDb; @@ -89,9 +87,11 @@ FLMEXP RCODE FLMAPI FlmRecordRetrieve( } // Remove the exclusive case and turn it into an inclusive search. + if( uiFlag & FO_EXCL) { // For records, exclusive is same as inclusive drn+1 + uiDrn++; uiFlag &= ~FO_EXCL; uiFlag = FO_INCL; @@ -134,13 +134,11 @@ FLMEXP RCODE FLMAPI FlmRecordRetrieve( else // only FO_INCL case can exist for the else case. { - /* - Let's be optimistic and see if record is already in cache - before we search the b-tree. Don't try to retrieve the record from - disk if it is not in cache ... the next record may not have a DRN - of uiDrn and we don't want to search the b-tree twice to fetch - the next record. - */ + // Let's be optimistic and see if record is already in cache + // before we search the b-tree. Don't try to retrieve the record from + // disk if it is not in cache ... the next record may not have a DRN + // of uiDrn and we don't want to search the b-tree twice to fetch + // the next record. if( RC_OK( rc = flmRcaRetrieveRec( pDb, &bTransStarted, uiContainer, uiDrn, FALSE, NULL, NULL, ppRecord))) @@ -171,13 +169,14 @@ Search_Record: { goto Exit; } + flmUINT32ToBigEndian( (FLMUINT32)uiDrn, pSearchBuf); FSInitStackCache( &stack [0], BH_MAX_LEVELS); pStack = &stack[0]; bStackInitialized = TRUE; pStack->pKeyBuf = pKeyBuf; - /* Search the B-Tree for the key. */ + // Search the B-Tree for the key. if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, pSearchBuf, 4, 0))) { @@ -232,6 +231,7 @@ Search_Record: { rc = RC_SET( FERR_BTREE_ERROR); } + goto Exit; } } @@ -256,10 +256,12 @@ Search_Record: { rc = RC_SET( FERR_EOF_HIT); } + goto Exit; } // Need to return the record? + if( ppRecord) { if( RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, @@ -283,7 +285,8 @@ Search_Record: ExitCS: - /* Call record validator callback */ + // Call record validator callback + if( pDb->fnRecValidator) { FLMBOOL bSavedInvisTrans; @@ -296,15 +299,16 @@ ExitCS: Exit: - if( bStackInitialized) + if (bStackInitialized) { FSReleaseStackCache( stack, BH_MAX_LEVELS, FALSE); } - if ( bTransStarted) + if (bTransStarted) { - RCODE rc2 = flmAbortDbTrans( pDb); - if ( RC_OK( rc)) + RCODE rc2 = flmAbortDbTrans( pDb); + + if (RC_OK( rc)) { rc = rc2; } @@ -316,14 +320,14 @@ Exit: { pDb = NULL; } + flmExit( FLM_RECORD_RETRIEVE, pDb, rc); - return( rc); } /**************************************************************************** Desc: Retrieves a record based on uiDrn and uiFlag client-server. -*END************************************************************************/ +****************************************************************************/ FSTATIC RCODE flmRecordRetrieveCS( FDB * pDb, FLMUINT uiContainer, @@ -333,14 +337,12 @@ FSTATIC RCODE flmRecordRetrieveCS( FLMUINT * puiDrnRV) { RCODE rc; - CS_CONTEXT_p pCSContext = pDb->pCSContext; + CS_CONTEXT * pCSContext = pDb->pCSContext; void * pvMark = GedPoolMark( &pCSContext->pool); FCL_WIRE Wire( pCSContext, pDb); - /* - Set the record object so that it can be re-used, - if possible - */ + // Set the record object so that it can be re-used, + // if possible if( ppRecord) { @@ -352,13 +354,11 @@ FSTATIC RCODE flmRecordRetrieveCS( } } - /* - Set the temporary pool - */ + // Set the temporary pool Wire.setPool( &pCSContext->pool); - /* Send a request to retrieve the record. */ + // Send a request to retrieve the record if (RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_RECORD, FCS_OP_RECORD_RETRIEVE))) @@ -404,7 +404,7 @@ FSTATIC RCODE flmRecordRetrieveCS( goto Transmission_Error; } - /* Read the response. */ + // Read the response if (RC_BAD( rc = Wire.read())) { @@ -435,6 +435,7 @@ Exit: return( rc); Transmission_Error: + pCSContext->bConnectionGood = FALSE; goto Exit; } diff --git a/flaim/src/flreduce.cpp b/flaim/src/flreduce.cpp index 3ee91ab..c4a0f80 100644 --- a/flaim/src/flreduce.cpp +++ b/flaim/src/flreduce.cpp @@ -25,40 +25,40 @@ #include "flaimsys.h" FSTATIC RCODE FLRReadBlkHdr( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddress, FLMBYTE * pucBlockHeader, FLMINT * iTypeRV); FSTATIC RCODE FLRMoveBtreeBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr, FLMUINT uiLfNumber, FLMBOOL * pbDone); FSTATIC RCODE FLRMovePcodeLFHBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr, FLMUINT uiBlkType); FSTATIC RCODE FLRFreeAvailBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr); FSTATIC RCODE FLRFindPrevAvailBlk( - FDB_p pDb, + FDB * pDb, FLMUINT * puiBlkAddrRV, FLMBOOL * pbFirstChainFlagRV); -/*API~*********************************************************************** +/**************************************************************************** Desc : Reduces the size of a FLAIM database file. Notes: The size of the database file is reduced by freeing a specified number of blocks from the available (unused) block list. The blocks are moved to the end of the file and the file is truncated. If the available block list is empty, FLAIM will attemp to add blocks to the list by freeing log extent blocks. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmDbReduceSize( HFDB hDb, FLMUINT uiCount, @@ -66,7 +66,7 @@ FLMEXP RCODE FLMAPI FlmDbReduceSize( ) { RCODE rc; - FDB_p pDb = (FDB_p) hDb; + FDB * pDb = (FDB *) hDb; F_Rfl * pRfl = NULL; FLMUINT uiLogicalEOF; /* Local variable- change dbd->logEof last*/ FLMUINT uiBlkAddr; @@ -82,7 +82,7 @@ FLMEXP RCODE FLMAPI FlmDbReduceSize( // Lock the database if not already locked. // Cannot lose exclusive access between the checkpoint and - // the update transaction that does the conversion. + // the update transaction that does the truncation. if( (pDb->uiFlags & FDB_HAS_FILE_LOCK) == 0) { @@ -97,10 +97,10 @@ FLMEXP RCODE FLMAPI FlmDbReduceSize( { fdbInitCS( pDb); - CS_CONTEXT_p pCSSession = pDb->pCSContext; + CS_CONTEXT * pCSSession = pDb->pCSContext; FCL_WIRE Wire( pCSSession, pDb); - /* Send a request to reduce the file. */ + // Send a request to reduce the file if (RC_BAD( rc = Wire.sendOp( FCS_OPCLASS_DATABASE, FCS_OP_DB_REDUCE_SIZE))) @@ -121,7 +121,7 @@ FLMEXP RCODE FLMAPI FlmDbReduceSize( goto Transmission_Error; } - /* Read the response. */ + // Read the response if (RC_BAD( rc = Wire.read())) { @@ -133,6 +133,7 @@ FLMEXP RCODE FLMAPI FlmDbReduceSize( goto Exit; Transmission_Error: + pCSSession->bConnectionGood = FALSE; goto Exit; } @@ -143,7 +144,7 @@ Transmission_Error: goto Exit; } - /* Make sure we are NOT in a database transaction. */ + // Make sure we are NOT in a database transaction if (pDb->uiTransType != FLM_NO_TRANS) { @@ -162,17 +163,7 @@ Transmission_Error: pRfl->setLoggingOffState( TRUE); bRestoreLoggingOffFlag = TRUE; - /**------------------------------------------------------------------- - *** Keep looping to here until the count is satisfied or there - *** are not any more log extent blocks to turn into avail blks. - *** The loop does a begin transaction - move blocks - set logical - *** EOF and commits the transaction. During the commit if there are - *** not any avail blocks left then a log extent (if any) will be turned - *** into more avail blocks and we can do this again with more avail - *** blocks. - ***------------------------------------------------------------------*/ - - /* Start a database transaction */ + // Start a database transaction if (RC_BAD(rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, 15, FLM_DONT_POISON_CACHE))) @@ -186,12 +177,9 @@ Transmission_Error: uiBlkSize = pDb->pFile->FileHdr.uiBlockSize; - /**----------------------------------------------------------------- - *** Get the logical end of file and use internally. - *** Loop until there are not any more free blocks left or the - *** input count is matched. Switch on each block type found - *** while backing up through the file. - ***----------------------------------------------------------------*/ + // Get the logical end of file and use internally. + // Loop until there are not any more free blocks left or the + // input count is matched. Switch on each block type found uiLogicalEOF = pDb->LogHdr.uiLogicalEOF; @@ -199,9 +187,7 @@ Transmission_Error: && ((!uiCount) || (uiNumBlksMoved < uiCount))) { - /* Read the last block and determine block type. */ - - /* Special case for 3x files. */ + // Read the last block and determine block type if( FSGetFileOffset( uiLogicalEOF) == 0) { @@ -221,7 +207,8 @@ Transmission_Error: goto Reduce_Size_Error; } - // Adjust to a block bounds. + // Adjust to a block bounds + uiTemp = (uiFileSize / uiBlkSize) * uiBlkSize; if( uiTemp < uiFileSize) { @@ -240,26 +227,39 @@ Transmission_Error: switch( iType ) { case BHT_FREE: + { rc = FLRFreeAvailBlk( pDb, uiBlkAddr ); break; + } case BHT_LEAF: case BHT_NON_LEAF: case BHT_NON_LEAF_DATA: + { rc = FLRMoveBtreeBlk( pDb, uiBlkAddr, FB2UW( &BlkHeader [BH_LOG_FILE_NUM ]), &bDone); break; + } case BHT_LFH_BLK: case BHT_PCODE_BLK: + { rc = FLRMovePcodeLFHBlk( pDb, uiBlkAddr, iType); break; + } + default: + { rc = RC_SET( FERR_BTREE_ERROR); break; + } } + if (RC_BAD(rc)) + { goto Reduce_Size_Error; + } + if (bDone) { break; @@ -277,13 +277,17 @@ Transmission_Error: F_FileHdlImp * pFileHdl; if( uiFileNumber <= 1) + { break; + } // Leave the current file at zero bytes and move to the // previous store file. + uiFileNumber--; // Compute the end of the previous block file. + if( RC_BAD( rc = pDb->pSFileHdl->GetFileHdl( uiFileNumber, TRUE, &pFileHdl))) { @@ -297,6 +301,7 @@ Transmission_Error: uiLogicalEOF = FSBlkAddress( uiFileNumber, uiFileOffset); } + uiLogicalEOF -= uiBlkSize; } @@ -305,7 +310,7 @@ Transmission_Error: // and then turn it back off after logging the packet. if (!(pDb->uiFlags & FDB_REPLAYING_RFL) && - pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) + pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) { // We would have turned logging OFF above, so we need to @@ -326,13 +331,15 @@ Transmission_Error: } } - /* Commit the transaction. */ + // Commit the transaction { FLMBOOL bFlagSet; if (pDb->uiFlags & FDB_DO_TRUNCATE) + { bFlagSet = TRUE; + } else { bFlagSet = FALSE; @@ -340,17 +347,23 @@ Transmission_Error: } rc = flmCommitDbTrans( pDb, uiLogicalEOF, TRUE); + if (!bFlagSet) + { pDb->uiFlags &= (~(FDB_DO_TRUNCATE)); + } + if (RC_BAD( rc)) + { goto Exit; + } } Exit: if( puiCountRV) { - *puiCountRV = uiNumBlksMoved; /* May be more than requested count */ + *puiCountRV = uiNumBlksMoved; } if (bRestoreLoggingOffFlag) @@ -364,7 +377,6 @@ Exit: } flmExit( FLM_DB_REDUCE_SIZE, pDb, rc); - return( rc); Reduce_Size_Error: @@ -378,7 +390,7 @@ Reduce_Size_Error: Desc: Read the block header and return the type of block it is ****************************************************************************/ FSTATIC RCODE FLRReadBlkHdr( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddress, FLMBYTE * pucBlockHeader, FLMINT * piTypeRV ) @@ -524,13 +536,13 @@ Notes: Some of this code could be called in movePcodeLFHBlk but we have to worry about if the block is a root or right most leaf block. ****************************************************************************/ FSTATIC RCODE FLRMoveBtreeBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr, // Block Address FLMUINT uiLfNumber, FLMBOOL * pbDone) { RCODE rc; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; LFILE * pLFile; SCACHE * pSCache; FLMBOOL bReleaseCache = FALSE; @@ -542,7 +554,7 @@ FSTATIC RCODE FLRMoveBtreeBlk( SCACHE * pFreeSCache; FLMBOOL bReleaseCache2 = FALSE; BTSK StackArea; /* Single stack allocation */ - BTSK_p pStack = &StackArea; /* Points to stack - easier to use */ + BTSK * pStack = &StackArea; /* Points to stack - easier to use */ FLMUINT uiElmOvhd; /* Number of bytes in block overhead */ FLMUINT uiSearchKeyLen; /* Length of block's 1st key */ FLMBYTE ucKeyBuf [MAX_KEY_SIZ]; @@ -856,7 +868,7 @@ Desc: Find where a pcode list the input block is located. Move to a free block and change all pointers to the block. ****************************************************************************/ FSTATIC RCODE FLRMovePcodeLFHBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr, FLMUINT uiBlkType) { @@ -870,7 +882,7 @@ FSTATIC RCODE FLRMovePcodeLFHBlk( FLMUINT uiLeftBlkAddr; FLMUINT uiRightBlkAddr; FLMUINT uiFreeBlkAddr; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; FLMUINT uiSavePrevTransID; FLMUINT uiSavePrevBlkAddr; @@ -1039,11 +1051,11 @@ Exit: Desc: Free the input avail block. Link the block out of the free list ****************************************************************************/ FSTATIC RCODE FLRFreeAvailBlk( - FDB_p pDb, + FDB * pDb, FLMUINT uiBlkAddr) { RCODE rc = FERR_OK; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; FLMBYTE ucBlkHeader [BH_OVHD]; FLMBYTE * pucBlk; FLMUINT uiPrevBlkAddr; @@ -1354,7 +1366,7 @@ Desc: Move an avail block out of the avail block list. Worry about version 1.11+ back chaining ****************************************************************************/ FSTATIC RCODE FLRFindPrevAvailBlk( - FDB_p pDb, + FDB * pDb, FLMUINT * puiBlkAddrRV, FLMBOOL * pbFirstChainFlagRV) { diff --git a/flaim/src/flresdrn.cpp b/flaim/src/flresdrn.cpp deleted file mode 100644 index 0e22dc5..0000000 --- a/flaim/src/flresdrn.cpp +++ /dev/null @@ -1,212 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Reserve next DRN. -// Tabs: 3 -// -// Copyright (c) 1995-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: flresdrn.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Desc : Returns the next DRN that record ADD would return. The database/store - must be in an existing update transaction. -Notes: -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmReserveNextDrn( - HFDB hDb, - FLMUINT uiContainer, - FLMUINT * puiDrnRV - ) -{ - RCODE rc; - FDB * pDb = (FDB *)hDb; - LFILE * pLFile; - FLMBOOL bIgnore; - FLMUINT uiDrn = 0; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - // Send the request - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_RECORD, FCS_OP_RESERVE_NEXT_DRN))) - { - goto ExitCS; - } - - if( uiContainer) - { - if (RC_BAD( rc = Wire.sendNumber( - WIRE_VALUE_CONTAINER_ID, uiContainer))) - { - goto Transmission_Error; - } - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response - - if( RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto ExitCS; - } - - *puiDrnRV = Wire.getDrn(); - goto ExitCS; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto ExitCS; - } - - bIgnore = FALSE; // Set to shut up compiler. - - if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - FDB_TRANS_GOING_OK, // byFlags - 0, // wAutoTrans - &bIgnore))) // bStartedAutoTrans - { - goto Exit; - } - - if( pDb->uiFlags & FDB_COMMITTING_TRANS) - { - flmAssert( 0); - rc = RC_SET( FERR_ILLEGAL_TRANS_OP); - goto Exit; - } - - if( RC_BAD( fdictGetContainer( pDb->pDict, uiContainer, &pLFile))) - { -#ifdef FLM_DBG_LOG - uiDrn = 0; -#endif - goto Exit; - } - uiDrn = (FLMUINT) 0; // Must initialize before call. - if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, TRUE, &uiDrn))) - { -#ifdef FLM_DBG_LOG - uiDrn = 0; -#endif - goto Exit; - } - - *puiDrnRV = uiDrn; // Set return value. - -Exit: - - if (RC_OK( rc)) - { - rc = pDb->pFile->pRfl->logUpdatePacket( - RFL_RESERVE_DRN_PACKET, uiContainer, *puiDrnRV, 0); - } - - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) - { - flmUpdEventCallback( pDb, F_EVENT_RESERVE_DRN, hDb, rc, *puiDrnRV, - uiContainer, NULL, NULL); - } - -#ifdef FLM_DBG_LOG - flmDbgLogUpdate( pDb->pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, - uiContainer, uiDrn, rc, "RDrn"); -#endif - -ExitCS: - - flmExit( FLM_RESERVE_NEXT_DRN, pDb, rc); - - return( rc); -} - - -/*API~*********************************************************************** -Desc : Searches for an available DRN in the dictionary container. Differs - from FlmReserveNextDrn in that it will attempt to reuse dictionary - DRNS. The database/store must be in an existing update transaction. -Notes: -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmFindUnusedDictDrn( - HFDB hDb, - FLMUINT uiStartDrn, - FLMUINT uiEndDrn, - FLMUINT * puiDrnRV) -{ - RCODE rc; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore = FALSE; - FDICT_p pDict; - FLMUINT uiCurrDrn; - FLMUINT uiStopSearch; - - if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, FDB_TRANS_GOING_OK, - 0, &bIgnore))) - { - *puiDrnRV = (FLMUINT)-1; - goto Exit; - } - - // Search through the ITT table looking for the first occurance - // of ITT_EMPTY_SLOT - - pDict = pDb->pDict; - uiCurrDrn = f_max( uiStartDrn, 1); - uiStopSearch = f_min( uiEndDrn, pDict->uiIttCnt - 1); - - while (uiCurrDrn <= uiStopSearch) - { - if (pDict->pIttTbl[ uiCurrDrn].uiType == ITT_EMPTY_SLOT) - { - break; - } - else - { - uiCurrDrn++; - } - } - - if (uiCurrDrn > uiEndDrn) - { - rc = RC_SET( FERR_NO_MORE_DRNS); - goto Exit; - } - - *puiDrnRV = uiCurrDrn; - -Exit: - - fdbExit( pDb); - return( rc); -} diff --git a/flaim/src/flsweep.cpp b/flaim/src/flsweep.cpp index 5dd3b08..6d23b90 100644 --- a/flaim/src/flsweep.cpp +++ b/flaim/src/flsweep.cpp @@ -41,7 +41,7 @@ public: ~DbDict(); RCODE Init( - FDB_p pDb, + FDB * pDb, FLMUINT uiMode, FLMBOOL * pbFoundPurgeField); @@ -66,7 +66,7 @@ public: private: - FDB_p m_pDb; + FDB * m_pDb; FLMUINT * m_puiStateTbl; FLMUINT m_uiTblSize; }; @@ -97,7 +97,7 @@ public: } FINLINE void Init( - FDB_p pDb, + FDB * pDb, FLMUINT uiCallbackFreq, STATUS_HOOK fnStatusHook, void * UserData) @@ -120,7 +120,7 @@ public: private: - FDB_p m_pDb; + FDB * m_pDb; FLMUINT m_uiCallbackFreq; STATUS_HOOK m_fnStatusHook; void * m_UserData; @@ -173,7 +173,7 @@ FLMEXP RCODE FLMAPI FlmDbSweep( FLMUINT uiState; SWEEP_INFO SwpInfo; FLMBOOL bStartedTrans = FALSE; - FDB_p pDb = (FDB_p) hDb; + FDB * pDb = (FDB *) hDb; FLMUINT uiEncState; if( IsInCSMode( pDb)) @@ -752,12 +752,12 @@ Desc: Read the dictionary and create a internal table that records the state of field templates within the specified dictionary ****************************************************************************/ RCODE DbDict::Init( - FDB_p pDb, + FDB * pDb, FLMUINT uiMode, // are we looking for checking or purged or both FLMBOOL * pbFoundPurgeField)// [out] dictionary contained field that is marked purged. { RCODE rc = FERR_OK; - ITT_p pItt = NULL; + ITT * pItt = NULL; FLMUINT uiItem; FLMUINT uiCount; FLMUINT uiStateMask = 0; @@ -948,7 +948,7 @@ Desc: Change a field/record's defined state. Currently the only supported Ret: ****************************************************************************/ RCODE flmChangeItemState( - FDB_p pDb, + FDB * pDb, FLMUINT uiItemId, FLMUINT uiNewState) { diff --git a/flaim/src/fltrabrt.cpp b/flaim/src/fltrabrt.cpp deleted file mode 100644 index c866264..0000000 --- a/flaim/src/fltrabrt.cpp +++ /dev/null @@ -1,383 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Abort transaction -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fltrabrt.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: This routine aborts an active transaction for a particular - database. If the database is open via a server, a message is - sent to the server to abort the transaction. Otherwise, the - transaction is rolled back locally. -****************************************************************************/ -RCODE flmAbortDbTrans( - FDB * pDb, - FLMBOOL bOkToLogAbort) -{ - RCODE rc = FERR_OK; - FFILE * pFile = pDb->pFile; - FLMUINT uiTransType; - FLMBYTE * pucLastCommittedLogHdr; - FLMBYTE * pucUncommittedLogHdr; - FLMBOOL bDumpedCache = FALSE; - DB_STATS * pDbStats = pDb->pDbStats; - FLMBOOL bKeepAbortedTrans; - FLMUINT uiTransId; - FLMBOOL bInvisibleTrans; - - // Get transaction type - - if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS) - { - goto Exit; // Will return SUCCESS. - } - - // No recovery required if it is a read transaction. - - if (uiTransType == FLM_READ_TRANS) - { - - if( pDb->KrefCntrl.bKrefSetup) - { - // KrefCntrlFree could be called w/o checking bKrefSetup because - // it checks the flag, but it is more optimal to check the - // flag before making the call because most of the time it will - // be false. - - KrefCntrlFree( pDb); - } - - goto Unlink_From_Trans; - } - -#ifdef FLM_DBG_LOG - flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, - 0, 0, FERR_OK, "TAbrt"); -#endif - - pFile->pRfl->clearLogHdrs(); - - // If the transaction had no update operations, restore it - // to its pre-transaction state - make it appear that no - // transaction ever happened. - - pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0]; - pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0]; - uiTransId = pDb->LogHdr.uiCurrTransID; - - // Free up all keys associated with this database. This is done even - // if we didn't have any update operations because the KREF may - // have been initialized by key generation operations performed - // by cursors, etc. - - KrefCntrlFree( pDb); - - // Free any index counts we may have allocated. - - FSFreeIxCounts( pDb); - - if (pDb->bHadUpdOper) - { - // Dump any BLOB structures that should be aborted. - - FBListAfterAbort( pDb); - - // Dump any start and stop indexing stubs that should be aborted. - - flmIndexingAfterAbort( pDb); - - // Log the abort record to the rfl file, or throw away the logged - // records altogether, depending on the LOG_KEEP_ABORTED_TRANS_IN_RFL - // flag. If the RFL volume is bad, we will not attempt to keep this - // transaction in the RFL. - - if (!pFile->pRfl->seeIfRflVolumeOk()) - { - bKeepAbortedTrans = FALSE; - } - else - { - bKeepAbortedTrans = - (pucUncommittedLogHdr [LOG_KEEP_ABORTED_TRANS_IN_RFL]) - ? TRUE - : FALSE; - } - } - else - { - bKeepAbortedTrans = FALSE; - } - - // Log an abort transaction record to the roll-forward log or - // throw away the entire transaction, depending on the - // bKeepAbortedTrans flag. - - // If the transaction is being "dumped" because of a failed commit, - // don't log anything to the RFL. - - if( bOkToLogAbort) - { - flmAssert( pDb->LogHdr.uiCurrTransID == pFile->pRfl->getCurrTransID()); - if (RC_BAD( rc = pFile->pRfl->logEndTransaction( - RFL_TRNS_ABORT_PACKET, !bKeepAbortedTrans))) - { - goto Exit1; - } - } -#ifdef FLM_DEBUG - else - { - // If bOkToLogAbort is FALSE, this always means that either a - // commit failed while trying to log an end transaction packet or a - // commit packet was logged and the transaction commit subsequently - // failed for some other reason. In either case, the RFL should be - // in a good state, with its current transaction ID reset to 0. If - // not, either bOkToLogAbort is being used incorrectly by the caller - // or there is a bug in the RFL logic. - - flmAssert( pFile->pRfl->getCurrTransID() == 0); - } -#endif - - // If there were no operations in the transaction, restore - // everything as if the transaction never happened. - - if (!pDb->bHadUpdOper) - { - f_mutexLock( gv_FlmSysData.hShareMutex); - pFile->uiUpdateTransID = 0; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - // Pretend we dumped cache - shouldn't be any to worry about at - // this point. - - bDumpedCache = TRUE; - goto Exit1; - } - - // Dump ALL modified cache blocks associated with the DB. - // NOTE: This needs to be done BEFORE the call to flmGetLogHdrInfo - // below, because that call will change pDb->LogHdr.uiCurrTransID, - // and that value is used by flmRcaAbortTrans. - - ScaFreeModifiedBlocks( pDb); - flmRcaAbortTrans( pDb); - bDumpedCache = TRUE; - - // Reset the LogHdr from the last committed log header in pFile. - - flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); - if (RC_BAD( rc = flmPhysRollback( pDb, - (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_ROLLBACK_EOF]), - pFile->uiFirstLogBlkAddress, FALSE, 0))) - { - goto Exit1; - } - - f_mutexLock( gv_FlmSysData.hShareMutex); - - // Put the new transaction ID into the log header even though - // we are not committing. We want to keep the transaction IDs - // incrementing even though we aborted. - - UD2FBA( (FLMUINT32)uiTransId, - &pucLastCommittedLogHdr [LOG_CURR_TRANS_ID]); - - // Preserve where we are at in the roll-forward log. Even though - // the transaction aborted, we may have kept it in the RFL instead of - // throw it away. - - f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_FILE_NUM], - &pucUncommittedLogHdr [LOG_RFL_FILE_NUM], 4); - f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], - &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET], 4); - f_memcpy( &pucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - f_memcpy( &pucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - - // The following items tell us where we are at in the roll-back log. - // During a transaction we may log blocks for the checkpoint or for - // read transactions. So, even though we are aborting this transaction, - // there may be other things in the roll-back log that we don't want - // to lose. These items should not be reset until we do a checkpoint, - // which is when we know it is safe to throw away the entire roll-back log. - - f_memcpy( &pucLastCommittedLogHdr [LOG_ROLLBACK_EOF], - &pucUncommittedLogHdr [LOG_ROLLBACK_EOF], 4); - f_memcpy( &pucLastCommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], - &pucUncommittedLogHdr [LOG_PL_FIRST_CP_BLOCK_ADDR], 4); - - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - pFile->pRfl->commitLogHdrs( pucLastCommittedLogHdr, - pFile->ucCheckpointLogHdr); - -Exit1: - - // Dump cache, if not done above. - - if (!bDumpedCache) - { - ScaFreeModifiedBlocks( pDb); - flmRcaAbortTrans( pDb); - bDumpedCache = TRUE; - } - - // Throw away IXD_FIXUPs - - if (pDb->pIxdFixups) - { - IXD_FIXUP * pIxdFixup; - IXD_FIXUP * pDeleteIxdFixup; - - pIxdFixup = pDb->pIxdFixups; - while (pIxdFixup) - { - pDeleteIxdFixup = pIxdFixup; - pIxdFixup = pIxdFixup->pNext; - f_free( &pDeleteIxdFixup); - } - pDb->pIxdFixups = NULL; - } - - if (uiTransType != FLM_READ_TRANS && - gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) - { - flmTransEventCallback( F_EVENT_ABORT_TRANS, (HFDB)pDb, rc, - uiTransId); - } - -Unlink_From_Trans: - - bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE; - if (pDb->uiFlags & FDB_HAS_WRITE_LOCK) - { - RCODE tmpRc; - - if (RC_BAD( tmpRc = pFile->pRfl->completeTransWrites( pDb, FALSE, FALSE))) - { - if (RC_OK( rc)) - { - rc = tmpRc; - } - } - } - - // Unlink the database from the transaction - // structure as well as from the FLDICT structure. - - flmUnlinkDbFromTrans( pDb, FALSE); - - if (pDbStats) - { - FLMUINT64 ui64ElapMilli = 0; - - flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli); - pDbStats->bHaveStats = TRUE; - if (uiTransType == FLM_READ_TRANS) - { - pDbStats->ReadTransStats.AbortedTrans.ui64Count++; - pDbStats->ReadTransStats.AbortedTrans.ui64ElapMilli += - ui64ElapMilli; - if (bInvisibleTrans) - { - pDbStats->ReadTransStats.InvisibleTrans.ui64Count++; - pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli += - ui64ElapMilli; - } - } - else - { - pDbStats->UpdateTransStats.AbortedTrans.ui64Count++; - pDbStats->UpdateTransStats.AbortedTrans.ui64ElapMilli += - ui64ElapMilli; - } - } - - if (pDb->pStats) - { - (void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats); - } - - -Exit: - - return( rc); -} - -/*API~*********************************************************************** -Desc : Aborts an active transaction. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbTransAbort( - HFDB hDb - ) -{ - RCODE rc; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - FCL_WIRE Wire( pDb->pCSContext, pDb); - if (!pDb->pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - } - else - { - rc = Wire.doTransOp( FCS_OP_TRANSACTION_ABORT, 0, 0, 0); - } - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK | FDB_CLOSING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // If there is an invisible transaction going, it should not be - // abortable by an application. - - if ((pDb->uiTransType == FLM_NO_TRANS) || - (pDb->uiFlags & FDB_INVISIBLE_TRANS)) - { - rc = RC_SET( FERR_NO_TRANS_ACTIVE); - goto Exit; - } - rc = flmAbortDbTrans( pDb); - -Exit: - - if( RC_OK( rc)) - { - rc = flmCheckDatabaseState( pDb); - } - - flmExit( FLM_DB_TRANS_ABORT, pDb, rc); - return( rc); -} diff --git a/flaim/src/fltrbeg.cpp b/flaim/src/fltrbeg.cpp deleted file mode 100644 index 6b26230..0000000 --- a/flaim/src/fltrbeg.cpp +++ /dev/null @@ -1,1043 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Begin transaction -// Tabs: 3 -// -// Copyright (c) 1991,1994-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fltrbeg.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE flmReadDictionary( - FDB * pDb); - -/**************************************************************************** -Desc: This routine unlinks an FDB from a transaction's list of FDBs. -****************************************************************************/ -void flmUnlinkDbFromTrans( - FDB * pDb, - FLMBOOL bCommitting) -{ - FFILE * pFile = pDb->pFile; - - flmAssert( pDb->pIxdFixups == NULL); - if( pDb->uiTransType != FLM_NO_TRANS) - { - if (pDb->uiFlags & FDB_HAS_WRITE_LOCK) - { - - // If this is a commit operation and we have a commit callback, - // call the callback function before unlocking the DIB. - - if( bCommitting && pDb->fnCommit) - { - FLMBOOL bSavedInvisTrans; - - CB_ENTER( pDb, &bSavedInvisTrans); - pDb->fnCommit( (HFDB)pDb, pDb->pvCommitData); - CB_EXIT( pDb, bSavedInvisTrans); - } - - dbUnlock( pDb); - } - - f_mutexLock( gv_FlmSysData.hShareMutex); - if (pDb->pDict) - { - flmUnlinkFdbFromDict( pDb); - } - - /* - Unlink the transaction from the FFILE if it is a read - transaction. - */ - - if( pDb->uiTransType == FLM_READ_TRANS) - { - if (pDb->pNextReadTrans) - { - pDb->pNextReadTrans->pPrevReadTrans = pDb->pPrevReadTrans; - } - else if (!pDb->uiKilledTime) - { - pFile->pLastReadTrans = pDb->pPrevReadTrans; - } - if (pDb->pPrevReadTrans) - { - pDb->pPrevReadTrans->pNextReadTrans = pDb->pNextReadTrans; - } - else if (pDb->uiKilledTime) - { - pFile->pFirstKilledTrans = pDb->pNextReadTrans; - } - else - { - pFile->pFirstReadTrans = pDb->pNextReadTrans; - } - - // Zero out so it will be zero for next transaction begin. - - pDb->uiKilledTime = 0; - } - else - { - // Reset to NULL or zero for next update transaction. - - pDb->pBlobList = NULL; - pDb->pIxStartList = pDb->pIxStopList = NULL; - flmAssert( pDb->pIxdFixups == NULL); - } - - f_mutexUnlock( gv_FlmSysData.hShareMutex); - pDb->uiTransType = FLM_NO_TRANS; - pDb->uiFlags &= (~(FDB_UPDATED_DICTIONARY | - FDB_INVISIBLE_TRANS | - FDB_DONT_KILL_TRANS | - FDB_DONT_POISON_CACHE)); - } -} - -/**************************************************************************** -Desc: This routine reads a file's local dictionary. This is called only - when we did not have a dictionary off of the FFILE - which will be - the first transaction after a database is opened. -****************************************************************************/ -FSTATIC RCODE flmReadDictionary( - FDB * pDb) -{ - RCODE rc = FERR_OK; - - // We better still be opening the database for the first time - - flmAssert( pDb->pFile->uiFlags & DBF_BEING_OPENED); - - if (RC_BAD( rc = fdictRebuild( pDb))) - { - goto Exit; - } - - f_mutexLock( gv_FlmSysData.hShareMutex); - - // At this point, we will not yet have opened the database for - // general use, so there is no way that any other thread can have - // created a dictionary yet. - - flmAssert( pDb->pFile->pDictList == NULL); - - // Link the new local dictionary to its file structure. - - flmLinkDictToFile( pDb->pFile, pDb->pDict); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - -Exit: - if (RC_BAD( rc) && pDb->pDict) - { - flmFreeDict( pDb->pDict); - pDb->pDict = NULL; - } - return( rc); -} - -/**************************************************************************** -Desc: This routine starts a transaction for the specified database. The - transaction may be part of an overall larger transaction. -Ret: SUCCESS - Indicates the transaction has been started for the desired - database. - FERR_NO_TRANS_ACTIVE - No global transaction has begun. This means that someone is - trying to do some modifications outside of a transaction. - other FLAIM error codes -****************************************************************************/ -RCODE flmBeginDbTrans( - FDB * pDb, - FLMUINT uiTransType, /* Type of transaction to start, if one - has not been started. */ - FLMUINT uiMaxLockWait, /* Maximum number of seconds to wait for - lock requests - if we have to create a - transaction. */ - FLMUINT uiFlags, /* Transaction flags */ - FLMBYTE * pucLogHdr - ) -{ - RCODE rc = FERR_OK; - FFILE * pFile = pDb->pFile; - FLMBOOL bMutexLocked = FALSE; - FLMBYTE * pucLastCommittedLogHdr; - DB_STATS * pDbStats = pDb->pDbStats; - - if( RC_BAD( rc = flmCheckDatabaseState( pDb))) - { - goto Exit; - } - - // Initialize a few things - as few as is necessary to avoid - // unnecessary overhead. - - pDb->eAbortFuncId = FLM_UNKNOWN_FUNC; - pDb->AbortRc = FERR_OK; - pucLastCommittedLogHdr = &pFile->ucLastCommittedLogHdr [0]; - pDb->KrefCntrl.bKrefSetup = FALSE; - pDb->uiTransType = uiTransType; - pDb->uiThreadId = (FLMUINT)f_threadId(); - pDb->uiTransCount++; - - /* - Link the FDB to the file's most current FDICT structure, - if there is one. - Also, if it is a read transaction, link the FDB - into the list of read transactions off of - the FFILE structure. - */ - - // Lock the mutex. - - f_mutexLock( gv_FlmSysData.hShareMutex); - bMutexLocked = TRUE; - if (pFile->pDictList) - { - - // Link the FDB to the FDICT. - - flmLinkFdbToDict( pDb, pFile->pDictList); - } - - /* - If it is a read transaction, link into the list of - read transactions off of the FFILE structure. Until we - get the log header transaction ID below, we set uiCurrTransID - to zero and link this transaction in at the beginning of the - list. - */ - - if (uiTransType == FLM_READ_TRANS) - { - flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); - - // Link in at the end of the transaction list. - - pDb->pNextReadTrans = NULL; - if ((pDb->pPrevReadTrans = pFile->pLastReadTrans) != NULL) - { - - // Make sure transaction IDs are always in ascending order. They - // should be at this point. - - flmAssert( pFile->pLastReadTrans->LogHdr.uiCurrTransID <= - pDb->LogHdr.uiCurrTransID); - pFile->pLastReadTrans->pNextReadTrans = pDb; - } - else - { - pFile->pFirstReadTrans = pDb; - } - pFile->pLastReadTrans = pDb; - pDb->uiInactiveTime = 0; - - if( uiFlags & FLM_DONT_KILL_TRANS) - { - pDb->uiFlags |= FDB_DONT_KILL_TRANS; - } - else - { - pDb->uiFlags &= ~FDB_DONT_KILL_TRANS; - } - if (pucLogHdr) - { - f_memcpy( pucLogHdr, &pDb->pFile->ucLastCommittedLogHdr[0], - LOG_HEADER_SIZE); - } - } - - f_mutexUnlock( gv_FlmSysData.hShareMutex); - bMutexLocked = FALSE; - - if( uiFlags & FLM_DONT_POISON_CACHE) - { - pDb->uiFlags |= FDB_DONT_POISON_CACHE; - } - else - { - pDb->uiFlags &= ~FDB_DONT_POISON_CACHE; - } - - /* - Put an exclusive lock on the database if we are not in a read - transaction. Read transactions require no lock. - */ - - if (uiTransType != FLM_READ_TRANS) - { - flmAssert( pDb->pIxStats == NULL); - - // Set the bHadUpdOper to TRUE for all transactions to begin with. - // Many calls to flmBeginDbTrans are internal, and we WANT the - // normal behavior at the end of the transaction when it is - // committed or aborted. The only time this flag will be set - // to FALSE is when the application starts the transaction as - // opposed to an internal starting of the transaction. - - pDb->bHadUpdOper = TRUE; - - // Initialize the count of blocks changed to be 0 - - pDb->uiBlkChangeCnt = 0; - - if (RC_BAD( rc = dbLock( pDb, uiMaxLockWait))) - { - goto Exit; - } - - // If there was a problem with the RFL volume, we must wait - // for a checkpoint to be completed before continuing. - // The checkpoint thread looks at this same flag and forces - // a checkpoint. If it completes one successfully, it will - // reset this flag. - // - // Also, if the last forced checkpoint had a problem - // (pFile->CheckpointRc != FERR_OK), we don't want to - // start up a new update transaction until it is resolved. - - if (!pFile->pRfl->seeIfRflVolumeOk() || - RC_BAD( pFile->CheckpointRc)) - { - rc = RC_SET( FERR_MUST_WAIT_CHECKPOINT); - goto Exit; - } - - // Set the first log block address to zero. - - pFile->uiFirstLogBlkAddress = 0; - - // Header must be read before opening roll forward log file to make - // sure we have the most current log file and log options. - - f_memcpy( pFile->ucUncommittedLogHdr, pucLastCommittedLogHdr, - LOG_HEADER_SIZE); - flmGetLogHdrInfo( pucLastCommittedLogHdr, &pDb->LogHdr); - - /* - Need to increment the current checkpoint for update transactions - so that it will be correct when we go to mark cache blocks. - */ - - if (pDb->uiFlags & FDB_REPLAYING_RFL) - { - // During recovery we need to set the transaction ID to the - // transaction ID that was logged. - - pDb->LogHdr.uiCurrTransID = pFile->pRfl->getCurrTransID(); - } - else - { - pDb->LogHdr.uiCurrTransID++; - } - f_mutexLock( gv_FlmSysData.hShareMutex); - - // Link FDB to the most current local dictionary, if there - // is one. - - if (pFile->pDictList != pDb->pDict && pFile->pDictList) - { - flmLinkFdbToDict( pDb, pFile->pDictList); - } - pFile->uiUpdateTransID = pDb->LogHdr.uiCurrTransID; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - // Set the transaction EOF to the current file EOF - - pDb->uiTransEOF = pDb->LogHdr.uiLogicalEOF; - - // Put the transaction ID into the uncommitted log header. - - UD2FBA( (FLMUINT32)pDb->LogHdr.uiCurrTransID, - &pFile->ucUncommittedLogHdr [LOG_CURR_TRANS_ID]); - - if (pucLogHdr) - { - f_memcpy( pucLogHdr, &pDb->pFile->ucUncommittedLogHdr [0], - LOG_HEADER_SIZE); - } - } - - if (pDbStats) - { - f_timeGetTimeStamp( &pDb->TransStartTime); - } - - // If we do not have a dictionary, read it in from disk. - // NOTE: This should only happen when we are first opening - // the database. - - if (!pDb->pDict) - { - if (RC_BAD( rc = flmReadDictionary( pDb))) - { - goto Exit; - } - } - -Exit: - - if( bMutexLocked) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - } - - if (uiTransType != FLM_READ_TRANS) - { - if (RC_OK( rc)) - { - rc = pFile->pRfl->logBeginTransaction( pDb); - } -#ifdef FLM_DBG_LOG - flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, - 0, 0, rc, "TBeg"); -#endif - } - - if( uiTransType == FLM_UPDATE_TRANS && - gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) - { - flmTransEventCallback( F_EVENT_BEGIN_TRANS, (HFDB)pDb, rc, - (FLMUINT)(RC_OK( rc) - ? pDb->LogHdr.uiCurrTransID - : (FLMUINT)0)); - } - - if (RC_BAD( rc)) - { - // If there was an error, unlink the database from the transaction - // structure as well as from the FDICT structure. - - flmUnlinkDbFromTrans( pDb, FALSE); - - if (pDb->pStats) - { - (void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats); - } - } - - return( rc); -} - -/*API~*********************************************************************** -Desc : Starts a transaction. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbTransBegin( - HFDB hDb, - FLMUINT uiTransType, - FLMUINT uiMaxLockWait, - FLMBYTE * pucHeader - ) -{ - RCODE rc = FERR_OK; - FLMBOOL bIgnore; - FLMUINT uiFlags = FLM_GET_TRANS_FLAGS( uiTransType); - FDB * pDb = (FDB *)hDb; - - uiTransType = FLM_GET_TRANS_TYPE( uiTransType); - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - FCL_WIRE Wire( pDb->pCSContext, pDb); - - if (!pDb->pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - } - else - { - if( RC_BAD( rc = Wire.doTransOp( - FCS_OP_TRANSACTION_BEGIN, uiTransType, uiFlags, - uiMaxLockWait, pucHeader))) - { - goto Exit; - } - } - - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // Verify the transaction type. - - if (( uiTransType != FLM_UPDATE_TRANS) && - ( uiTransType != FLM_READ_TRANS)) - { - rc = RC_SET( FERR_ILLEGAL_TRANS); - goto Exit; - } - - // Verify the transaction flags - - if( (uiFlags & FLM_DONT_KILL_TRANS) && uiTransType != FLM_READ_TRANS) - { - rc = RC_SET( FERR_ILLEGAL_TRANS); - goto Exit; - } - - // Can't start an update transaction on a database that - // is locked in shared mode. - - if ((uiTransType == FLM_UPDATE_TRANS) && - (pDb->uiFlags & FDB_FILE_LOCK_SHARED)) - { - rc = RC_SET( FERR_PERMISSION); - goto Exit; - } - - // If the database has an invisible transaction going, abort it - // before going any further - we don't want application transactions - // to be nested under invisible transactions. Application transactions - // take precedence over invisible transactions. - - if ((pDb->uiTransType != FLM_NO_TRANS) && - (pDb->uiFlags & FDB_INVISIBLE_TRANS)) - { - if (RC_BAD( rc = flmAbortDbTrans( pDb))) - { - goto Exit; - } - } - - // If the database is not running a transaction, start one. - // Otherwise, start a nested transaction - first verifying that - // the transation type matches. - - if (pDb->uiTransType == FLM_NO_TRANS) - { - FLMUINT uiBytesRead; - - if( pucHeader) - { - if( RC_BAD( rc = pDb->pSFileHdl->ReadHeader( - 0, 2048, pucHeader, &uiBytesRead))) - { - goto Exit; - } - } - - if (RC_BAD( rc = flmBeginDbTrans( pDb, uiTransType, - uiMaxLockWait, uiFlags, - pucHeader ? &pucHeader [16] : NULL))) - { - goto Exit; - } - pDb->bHadUpdOper = FALSE; - } - else - { - // Cannot nest transactions. - - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - -Exit: - - flmExit( FLM_DB_TRANS_BEGIN, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Returns the type of the current database transaction. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetTransType( - HFDB hDb, - FLMUINT * puiTransTypeRV - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT * pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pDb->pCSContext, pDb); - - // Send a request to get the transaction type. - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_TRANS, FCS_OP_TRANSACTION_GET_TYPE))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response. - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - *puiTransTypeRV = Wire.getTransType(); - rc = Wire.getRCode(); - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if (!pDb) - { - rc = RC_SET( FERR_BAD_HDL); - goto Exit; - } - - fdbUseCheck( pDb); - pDb->uiInitNestLevel++; - (void)flmResetDiag( pDb); - - // If the transaction is an internal transaction that is invisible to - // the application, return FLM_NO_TRANS. Application is not supposed - // see invisible transactions. - - *puiTransTypeRV = (FLMUINT)(((pDb->uiTransType == FLM_NO_TRANS) || - (pDb->uiFlags & FDB_INVISIBLE_TRANS)) - ? (FLMUINT)FLM_NO_TRANS - : pDb->uiTransType); - - // See if the database is being forced to close - - if( RC_BAD( rc = flmCheckDatabaseState( pDb))) - { - goto Exit; - } - -Exit: - - flmExit( FLM_DB_GET_TRANS_TYPE, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Obtains a a lock on the database. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbLock( - HFDB hDb, - FLOCK_TYPE eLockType, - FLMINT iPriority, - FLMUINT uiTimeout - ) -{ - RCODE rc = FERR_OK; - FLMBOOL bIgnore; - FDB * pDb = (FDB *)hDb; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_LOCK))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, - (FLMUINT)eLockType))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_SIGNED_NUMBER, - 0, iPriority))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiTimeout))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // eLockType better be exclusive or shared - - if ((eLockType != FLM_LOCK_EXCLUSIVE) && (eLockType != FLM_LOCK_SHARED)) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Nesting of locks is not allowed - this test also keeps this call from - // being executed inside an update transaction that implicitly acquired - // the lock. - - if (pDb->uiFlags & - (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED | FDB_FILE_LOCK_IMPLICIT)) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Attempt to acquire the lock. - - if (RC_BAD( rc = pDb->pFile->pFileLockObj->Lock( TRUE, pDb, FALSE, - (FLMBOOL)((eLockType == FLM_LOCK_EXCLUSIVE) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE), - uiTimeout, iPriority, - pDb->pDbStats))) - { - goto Exit; - } - pDb->uiFlags |= FDB_HAS_FILE_LOCK; - if (eLockType == FLM_LOCK_SHARED) - { - pDb->uiFlags |= FDB_FILE_LOCK_SHARED; - } - -Exit: - - flmExit( FLM_DB_LOCK, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Releases a lock on the database -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbUnlock( - HFDB hDb - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_UNLOCK))) - { - goto Exit; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK | FDB_CLOSING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // If we don't have an explicit lock, can't do the unlock. It is - // also illegal to do the unlock during an update transaction. - - if (!(pDb->uiFlags & FDB_HAS_FILE_LOCK) || - (pDb->uiFlags & FDB_FILE_LOCK_IMPLICIT) || - (pDb->uiTransType == FLM_UPDATE_TRANS)) - { - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Unlock the file. - - if (RC_BAD( rc = pDb->pFile->pFileLockObj->Unlock( TRUE, pDb))) - { - goto Exit; - } - - // Unset the flags that indicated the file was explicitly locked. - - pDb->uiFlags &= (~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED)); - -Exit: - - if( RC_OK( rc)) - { - rc = flmCheckDatabaseState( pDb); - } - - flmExit( FLM_DB_UNLOCK, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Returns information about current and pending locks on the - database. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetLockInfo( - HFDB hDb, - FLMINT iPriority, - FLOCK_INFO * pLockInfo - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = NULL; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - pDb = (FDB *)hDb; - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - pDb->pFile->pFileLockObj->GetLockInfo( iPriority, pLockInfo); - -Exit: - - flmExit( FLM_DB_GET_LOCK_INFO, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Returns information about the lock held by the specified database - handle. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetLockType( - HFDB hDb, - FLOCK_TYPE * peLockType, - FLMBOOL * pbImplicit) -{ - RCODE rc = FERR_OK; - FDB * pDb = NULL; - FLMBOOL bIgnore; - - if( peLockType) - { - *peLockType = FLM_LOCK_NONE; - } - - if( pbImplicit) - { - *pbImplicit = FALSE; - } - - if (IsInCSMode( hDb)) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - pDb = (FDB *)hDb; - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - if( pDb->uiFlags & FDB_HAS_FILE_LOCK) - { - if( peLockType) - { - if( pDb->uiFlags & FDB_FILE_LOCK_SHARED) - { - *peLockType = FLM_LOCK_SHARED; - } - else - { - *peLockType = FLM_LOCK_EXCLUSIVE; - } - } - - if( pbImplicit) - { - *pbImplicit = (pDb->uiFlags & FDB_FILE_LOCK_IMPLICIT) - ? TRUE - : FALSE; - } - } - -Exit: - - flmExit( FLM_DB_GET_LOCK_TYPE, pDb, rc); - return( rc); -} - -/*API~*********************************************************************** -Desc : Forces a checkpoint on the database. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbCheckpoint( - HFDB hDb, - FLMUINT uiTimeout - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bStartedTrans; - - bStartedTrans = FALSE; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_CHECKPOINT))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiTimeout))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - goto Exit; - } - - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - // Start an update transaction. Must not already be one going. - - if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - 0, uiTimeout | FLM_AUTO_TRANS, &bStartedTrans))) - { - goto Exit; - } - - // Commit the transaction, forcing it to be checkpointed. - - bStartedTrans = FALSE; - pDb->bHadUpdOper = FALSE; - if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE))) - { - goto Exit; - } -Exit: - if (bStartedTrans) - { - (void)flmAbortDbTrans( pDb); - } - - flmExit( FLM_DB_CHECKPOINT, pDb, rc); - return( rc); -} diff --git a/flaim/src/fltrcmit.cpp b/flaim/src/fltrcmit.cpp deleted file mode 100644 index bb4d473..0000000 --- a/flaim/src/fltrcmit.cpp +++ /dev/null @@ -1,581 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Commit transaction -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fltrcmit.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: This routine commits an active transaction for a particular - database. If the database is open via a server, a message is - sent to the server to commit the transaction. Otherwise, the - transaction is committed locally. -****************************************************************************/ -RCODE flmCommitDbTrans( - FDB * pDb, - FLMUINT uiNewLogicalEOF, // New logical end-of-file. This is only - // set by the FlmDbReduceSize function when - // it is truncating the file. - FLMBOOL bForceCheckpoint, // Force a checkpoint? - FLMBOOL * pbEmpty // May be NULL - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucUncommittedLogHdr; - FFILE * pFile = pDb->pFile; - FLMUINT uiCPFileNum = 0; - FLMUINT uiCPOffset = 0; - FLMUINT uiTransId = 0; - FLMBOOL bTransEndLogged; - FLMBOOL bForceCloseOnError = FALSE; - FLMBOOL bOkToLogAbort = TRUE; - DB_STATS * pDbStats = pDb->pDbStats; - FLMUINT uiTransType; - FLMBOOL bInvisibleTrans = FALSE; - FLMBOOL bIndexAfterCommit = FALSE; - - pDb->uiFlags |= FDB_COMMITTING_TRANS; - - // See if we even have a transaction going. - - if ((uiTransType = pDb->uiTransType) == FLM_NO_TRANS) - { - goto Exit; // Will return FERR_OK. - } - - // See if we have a transaction going which should be aborted. - - if (flmCheckBadTrans( pDb)) - { - rc = RC_SET( FERR_ABORT_TRANS); - goto Exit; - } - - // If we are in a read transaction we can skip most of the stuff - // below because no updates would have occurred. This will help - // improve performance. - - if (uiTransType == FLM_READ_TRANS) - { - - if( pDb->KrefCntrl.bKrefSetup) - { - // KrefCntrlFree could be called w/o checking bKrefSetup because - // it checks the flag, but it is more optimal to check the - // flag before making the call because most of the time it will - // be false. - - KrefCntrlFree( pDb); - } - goto Exit1; - } - - // At this point, we know we have an update transaction. - - pFile->pRfl->clearLogHdrs(); - -#ifdef FLM_DBG_LOG - flmDbgLogUpdate( pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, - 0, 0, FERR_OK, "TCmit"); -#endif - uiTransId = pDb->LogHdr.uiCurrTransID; - - // If the transaction had no update operations, restore it - // to its pre-transaction state - make it appear that no - // transaction ever happened. - - if (!pDb->bHadUpdOper) - { - bOkToLogAbort = FALSE; - rc = pFile->pRfl->logEndTransaction( RFL_TRNS_COMMIT_PACKET, TRUE); - - // Even though we didn't have any update operations, there may have - // been operations during the transaction (i.e., query operations) - // that initialized the KREF in order to generate keys. - - KrefCntrlFree( pDb); - - // Restore everything as if the transaction never happened. - - f_mutexLock( gv_FlmSysData.hShareMutex); - pFile->uiUpdateTransID = 0; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - if (pbEmpty) - { - *pbEmpty = TRUE; - } - goto Exit1; - } - - // Log commit record to roll-forward log - - bOkToLogAbort = FALSE; - if (RC_BAD( rc = pFile->pRfl->logEndTransaction( - RFL_TRNS_COMMIT_PACKET, FALSE, &bTransEndLogged))) - { - goto Exit1; - } - bForceCloseOnError = TRUE; - - // Commit any keys in the KREF buffers. - - if (RC_BAD( rc = KYKeysCommit( pDb, TRUE))) - { - flmLogError( rc, "calling KYKeysCommit from flmCommitDbTrans"); - goto Exit1; - } - - if (RC_BAD( rc = FSCommitIxCounts( pDb))) - { - flmLogError( rc, "calling FSCommitIxCounts from flmCommitDbTrans"); - goto Exit1; - } - - // Reinitialize the log header. If the local dictionary was updated - // during the transaction, increment the local dictionary ID so that - // other concurrent users will know that it has been modified and - // that they need to re-read it into memory. - - // If we are in recovery mode, see if we need to force - // a checkpoint with what we have so far. We force a - // checkpoint on one of two conditions: - - // 1. If it appears that we have a buildup of dirty cache - // blocks. We force a checkpoint on this condition - // because it will be more efficient than replacing - // cache blocks one at a time. - // We check for this condition by looking to see if - // our LRU block is not used and it is dirty. That is - // a pretty good indicator that we have a buildup - // of dirty cache blocks. - // 2. We are at the end of the roll-forward log. We - // want to force a checkpoint here to complete the - // recovery phase. - - if ( pDb->uiFlags & FDB_REPLAYING_RFL) - { - // If we are in the middle of upgrading, and are forcing - // a checkpoint, use the file number and offset that were - // set in the FDB. - - if ((pDb->uiFlags & FDB_UPGRADING) && bForceCheckpoint) - { - uiCPFileNum = pDb->uiUpgradeCPFileNum; - uiCPOffset = pDb->uiUpgradeCPOffset; - } - else - { - SCACHE * pTmpSCache; - F_Rfl * pRfl = pFile->pRfl; - - f_mutexLock( gv_FlmSysData.hShareMutex); - pTmpSCache = gv_FlmSysData.SCacheMgr.pLRUCache; - - // Test for buildup of dirty cache blocks. - - if (((pTmpSCache) && - (!pTmpSCache->uiUseCount) && - (pTmpSCache->ui16Flags & - (CA_DIRTY | CA_LOG_FOR_CP | CA_WRITE_TO_LOG))) - - || // Test for end of roll-forward log. - - pRfl->atEndOfLog() - || - bForceCheckpoint) - { - bForceCheckpoint = TRUE; - uiCPFileNum = pRfl->getCurrFileNum(); - uiCPOffset = pRfl->getCurrReadOffset(); - } - f_mutexUnlock( gv_FlmSysData.hShareMutex); - } - } - - // Move information collected in the pDb->LogHdr into the - // uncommitted log header. Other things that need to be - // set have already been set in the uncommitted log header - // at various places in the code. - - // Mutex does not have to be locked while we do this because - // the update transaction is the only one that ever accesses - // the uncommitted log header buffer. - - pucUncommittedLogHdr = &pFile->ucUncommittedLogHdr [0]; - - // Set the new logical EOF if passed in. - - if (uiNewLogicalEOF) - { - pDb->LogHdr.uiLogicalEOF = uiNewLogicalEOF; - } - UD2FBA( (FLMUINT32)pDb->LogHdr.uiLogicalEOF, - &pucUncommittedLogHdr [LOG_LOGICAL_EOF]); - - // Increment the commit counter. - - flmIncrUint( &pucUncommittedLogHdr [LOG_COMMIT_COUNT], 1); - - // Set the last committed transaction ID - - if( (bTransEndLogged || (pDb->uiFlags & FDB_REPLAYING_COMMIT)) && - pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_31) - { - UD2FBA( (FLMUINT32)uiTransId, - &pucUncommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]); - } - - // Write the header - - pFile->pRfl->commitLogHdrs( pucUncommittedLogHdr, - pFile->ucCheckpointLogHdr); - - // Commit any record cache. - - flmRcaCommitTrans( pDb); - - // Push the IXD_FIXUP values back into the IXD - - if (pDb->pIxdFixups) - { - IXD_FIXUP * pIxdFixup; - IXD_FIXUP * pDeleteIxdFixup; - IXD * pIxd; - - pIxdFixup = pDb->pIxdFixups; - while (pIxdFixup) - { - if( RC_BAD( fdictGetIndex( - pDb->pDict, pDb->pFile->bInLimitedMode, - pIxdFixup->uiIndexNum, NULL, &pIxd, TRUE))) - { - flmAssert( 0); - pIxd = NULL; - } - - if( pIxd) - { - pIxd->uiLastContainerIndexed = pIxdFixup->uiLastContainerIndexed; - pIxd->uiLastDrnIndexed = pIxdFixup->uiLastDrnIndexed; - } - pDeleteIxdFixup = pIxdFixup; - pIxdFixup = pIxdFixup->pNext; - f_free( &pDeleteIxdFixup); - } - pDb->pIxdFixups = NULL; - } - - // Set the update transaction ID back to zero only - // AFTER we know the transaction has safely committed. - - f_mutexLock( gv_FlmSysData.hShareMutex); - f_memcpy( pFile->ucLastCommittedLogHdr, pucUncommittedLogHdr, - LOG_HEADER_SIZE); - pFile->uiUpdateTransID = 0; - ScaReleaseLogBlocks( pFile); - if (pDb->uiFlags & FDB_UPDATED_DICTIONARY) - { - // Link the new local dictionary to its file. - // Since the new local dictionary will be linked at the head - // of the list of FDICT structures, see if the FDICT currently - // at the head of the list is unused and can be unlinked. - - if ((pFile->pDictList) && (!pFile->pDictList->uiUseCount)) - { - flmUnlinkDict( pFile->pDictList); - } - flmLinkDictToFile( pFile, pDb->pDict); - } - - f_mutexUnlock( gv_FlmSysData.hShareMutex); - -Exit1: - - // If the local dictionary was updated during this transaction, - // link the new local dictionary structures to their file - or free - // them if there was an error. - - if (pDb->uiFlags & FDB_UPDATED_DICTIONARY) - { - if( RC_BAD( rc) && pDb->pDict) - { - // Unlink the FDB from the FDICT. - Shouldn't have - // to lock semaphore, because the DICT is NOT linked - // to the FFILE. - - flmAssert( pDb->pDict->pFile == NULL); - flmUnlinkFdbFromDict( pDb); - } - } - - if (RC_BAD( rc)) - { - - // Since we failed to commit, do an abort. We are purposely not - // checking the return code from flmAbortDbTrans because we already - // have an error return code. If we attempted to log the transaction - // to the RFL and failed, we don't want to try to log an abort packet. - // The RFL code has already reset the log back to the starting point - // of the transaction, thereby discarding all operations. - - pDb->uiFlags &= ~FDB_COMMITTING_TRANS; - (void)flmAbortDbTrans( pDb, bOkToLogAbort); - uiTransType = FLM_NO_TRANS; - - // Do we need to force all handles to close? - - if( bForceCloseOnError) - { - - // Since the commit packet has already been logged to the RFL, - // we must have failed when trying to write the log header. The - // database is in a bad state and must be closed. - - // Set the "must close" flag on all FDBs linked to the FFILE - // and set the FFILE's "must close" flag. This will cause any - // subsequent operations on the database to fail until all - // handles have been closed. - - flmSetMustCloseFlags( pFile, rc, FALSE); - } - } - else - { - bInvisibleTrans = (pDb->uiFlags & FDB_INVISIBLE_TRANS) ? TRUE : FALSE; - if (uiTransType == FLM_UPDATE_TRANS) - { - if (gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) - { - flmTransEventCallback( F_EVENT_COMMIT_TRANS, (HFDB)pDb, rc, - uiTransId); - } - - // Do the BLOB and indexing work before we unlock the db. - - FBListAfterCommit( pDb); - - if (pDb->pIxStopList || pDb->pIxStartList) - { - - // Must not call flmIndexingAfterCommit until after - // completeTransWrites. Otherwise, there is a potential - // deadlock condition where flmIndexingAfterCommit is - // waiting on an indexing thread to quit, but that - // thread is waiting to be signaled by this thread that - // writes are completed. However, flmIndexingAfterCommit - // also must only be called while the database is still - // locked. If we were to leave the database locked for - // every call to completeTransWrites, however, we would - // lose the group commit capability. Hence, we opt to - // only lose it when there are actual indexing operations - // to start or stop - which should be very few transactions. - // That is what the bIndexAfterCommit flag is for. - - bIndexAfterCommit = TRUE; - } - } - } - - // Unlock the database, if the update transaction is still going. - // NOTE: We check uiTransType because it may have been reset - // to FLM_NO_TRANS up above if flmAbortDbTrans was called. - - if (uiTransType == FLM_UPDATE_TRANS) - { - if (RC_BAD( rc)) - { - - // SHOULD NEVER HAPPEN - because it would have been taken - // care of above - flmAbortDbTrans would have been called and - // uiTransType would no longer be FLM_UPDATE_TRANS. - - flmAssert( 0); - (void)pFile->pRfl->completeTransWrites( pDb, FALSE, TRUE); - } - else if (!bForceCheckpoint) - { - if (bIndexAfterCommit) - { - rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE); - flmIndexingAfterCommit( pDb); - flmUnlinkDbFromTrans( pDb, TRUE); - } - else - { - rc = pFile->pRfl->completeTransWrites( pDb, TRUE, TRUE); - } - } - else - { - - // Do checkpoint, if forcing. Before doing the checkpoint - // we have to make sure the roll-forward log writes - // complete. We don't want to unlock the DB while the - // writes are happening in this case - thus, the FALSE - // parameter to completeTransWrites. - - if (RC_OK( rc = pFile->pRfl->completeTransWrites( pDb, TRUE, FALSE))) - { - bForceCloseOnError = FALSE; - rc = ScaDoCheckpoint( pDbStats, pDb->pSFileHdl, pFile, - (pDb->uiFlags & FDB_DO_TRUNCATE) ? TRUE : FALSE, - TRUE, CP_TIME_INTERVAL_REASON, - uiCPFileNum, uiCPOffset); - } - if (bIndexAfterCommit) - { - flmIndexingAfterCommit( pDb); - } - flmUnlinkDbFromTrans( pDb, TRUE); - } - - if (RC_BAD( rc) && bForceCloseOnError) - { - - // Since the commit packet has already been logged to the RFL, - // we must have failed when trying to write the log header. The - // database is in a bad state and must be closed. - - // Set the "must close" flag on all FDBs linked to the FFILE - // and set the FFILE's "must close" flag. This will cause any - // subsequent operations on the database to fail until all - // handles have been closed. - - flmSetMustCloseFlags( pFile, rc, FALSE); - } - } - else - { - - // Unlink the database from the transaction - // structure as well as from the FDICT structure. - - flmUnlinkDbFromTrans( pDb, FALSE); - } - - if (pDbStats && uiTransType != FLM_NO_TRANS) - { - FLMUINT64 ui64ElapMilli = 0; - - flmAddElapTime( &pDb->TransStartTime, &ui64ElapMilli); - pDbStats->bHaveStats = TRUE; - if (uiTransType == FLM_READ_TRANS) - { - pDbStats->ReadTransStats.CommittedTrans.ui64Count++; - pDbStats->ReadTransStats.CommittedTrans.ui64ElapMilli += - ui64ElapMilli; - if (bInvisibleTrans) - { - pDbStats->ReadTransStats.InvisibleTrans.ui64Count++; - pDbStats->ReadTransStats.InvisibleTrans.ui64ElapMilli += - ui64ElapMilli; - } - } - else - { - pDbStats->UpdateTransStats.CommittedTrans.ui64Count++; - pDbStats->UpdateTransStats.CommittedTrans.ui64ElapMilli += - ui64ElapMilli; - } - } - - // Update stats - - if (pDb->pStats) - { - (void)flmStatUpdate( &gv_FlmSysData.Stats, &pDb->Stats); - } - -Exit: - - pDb->uiFlags &= ~FDB_COMMITTING_TRANS; - return( rc); -} - -/*API~*********************************************************************** -Desc : Commits an active transaction. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbTransCommit( - HFDB hDb, - FLMBOOL * pbEmpty // May be NULL - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - FCL_WIRE Wire( pDb->pCSContext, pDb); - - if (!pDb->pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - } - else - { - rc = Wire.doTransOp( FCS_OP_TRANSACTION_COMMIT, 0, 0, 0); - } - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK | FDB_CLOSING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // If there is an invisible transaction going, it should not be - // commitable by an application. - - if ((pDb->uiTransType == FLM_NO_TRANS) || - (pDb->uiFlags & FDB_INVISIBLE_TRANS)) - { - rc = RC_SET( FERR_NO_TRANS_ACTIVE); - goto Exit; - } - - // See if we have a transaction going which should be aborted. - - if( RC_BAD( pDb->AbortRc)) - { - rc = RC_SET( FERR_ABORT_TRANS); - goto Exit; - } - - if (pbEmpty) - { - *pbEmpty = FALSE; - } - rc = flmCommitDbTrans( pDb, 0, FALSE, pbEmpty); - -Exit: - - if( RC_OK( rc)) - { - rc = flmCheckDatabaseState( pDb); - } - - flmExit( FLM_DB_TRANS_COMMIT, pDb, rc); - return( rc); -} diff --git a/flaim/src/fltrnum.cpp b/flaim/src/fltrnum.cpp deleted file mode 100644 index 857f86a..0000000 --- a/flaim/src/fltrnum.cpp +++ /dev/null @@ -1,173 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Retrieve current transaction number and commit count. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fltrnum.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Desc : Retrieves the current transaction number of a database -Notes: This routine should only be called only from within an update - transaction since read transactions are not assigned a transaction - number. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetTransId( - HFDB hDb, - FLMUINT * puiTrNumRV - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - // Send a request to get the transaction ID. - - if (RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_GET_TRANS_ID))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - *puiTrNumRV = Wire.getTransId(); - - rc = Wire.getRCode(); - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - *puiTrNumRV = pDb->LogHdr.uiCurrTransID; - -Exit: - - flmExit( FLM_DB_GET_TRANS_ID, pDb, rc); - return( rc); -} - - -/*API~*********************************************************************** -Desc : Retrieves the last commit sequence number of a database. -Notes: Whenever a transaction is committed, FLAIM increments the commit - sequence number to indicate that the database has been modified. - An application may use this routine to determine if the database - has been modified. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetCommitCnt( - HFDB hDb, - FLMUINT * puiCommitCount - ) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - - if (IsInCSMode( hDb)) - { - fdbInitCS( pDb); - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - /* Send a request to get the commit count. */ - - if (RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_GET_COMMIT_CNT))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - // Read the response. - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - *puiCommitCount = (FLMUINT)Wire.getCount(); - - rc = Wire.getRCode(); - goto ExitCS; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto ExitCS; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - // See if we have a transaction going which should be aborted. - - if (pDb->uiTransType != FLM_NO_TRANS) - { - if (flmCheckBadTrans( pDb)) - { - rc = RC_SET( FERR_ABORT_TRANS); - goto Exit; - } - } - - f_mutexLock( gv_FlmSysData.hShareMutex); - *puiCommitCount = (FLMUINT)FB2UD( - &pDb->pFile->ucLastCommittedLogHdr [LOG_COMMIT_COUNT]); - f_mutexUnlock( gv_FlmSysData.hShareMutex); - -Exit: - -ExitCS: - - flmExit( FLM_DB_GET_COMMIT_CNT, pDb, rc); - return( rc); -} diff --git a/flaim/src/flupdate.cpp b/flaim/src/flupdate.cpp index 61a3b99..77e88d8 100644 --- a/flaim/src/flupdate.cpp +++ b/flaim/src/flupdate.cpp @@ -144,7 +144,7 @@ void flmUpdEventCallback( flmDoEventCallback( F_EVENT_UPDATES, eEventType, &UpdEvent, NULL); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Adds a record to a container. Notes: If an index definition record is added to the dictionary container, the index will be built automatically when the transaction commits. @@ -154,16 +154,16 @@ Notes: If an index definition record is added to the dictionary container, commits and the index is actually built. If FLAIM discovers that the keys in an index are not unique, the transaction commit will fail and return an error. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmRecordAdd( HFDB hDb, FLMUINT uiContainer, FLMUINT * puiDrn, FlmRecord * pRecord, - FLMUINT uiAutoTrans - ) + FLMUINT uiAutoTrans) { RCODE rc = FERR_OK; + FLMUINT uiDrn = 0; FDB * pDb = (FDB *)hDb; LFILE * pLFile; FLMBOOL bStartedAutoTrans = FALSE; @@ -171,6 +171,11 @@ FLMEXP RCODE FLMAPI FlmRecordAdd( DB_STATS * pDbStats = NULL; F_TMSTAMP StartTime; + if( puiDrn) + { + uiDrn = *puiDrn; + } + if( uiContainer == FLM_TRACKER_CONTAINER) { rc = RC_SET( FERR_ILLEGAL_OP); @@ -181,7 +186,7 @@ FLMEXP RCODE FLMAPI FlmRecordAdd( { fdbInitCS( pDb); rc = flmDoUpdateCS( pDb, FCS_OP_RECORD_ADD, uiContainer, - puiDrn, pRecord, uiAutoTrans); + &uiDrn, pRecord, uiAutoTrans); goto ExitCS; } @@ -220,7 +225,7 @@ FLMEXP RCODE FLMAPI FlmRecordAdd( goto Exit; } - rc = flmAddRecord( pDb, pLFile, puiDrn, pRecord, FALSE, + rc = flmAddRecord( pDb, pLFile, &uiDrn, pRecord, FALSE, (uiAutoTrans & FLM_DO_IN_BACKGROUND) ? TRUE : FALSE, (uiAutoTrans & FLM_SUSPENDED) ? TRUE : FALSE, (FLMBOOL)((uiAutoTrans & FLM_DONT_INSERT_IN_CACHE) ? FALSE : TRUE), @@ -232,15 +237,15 @@ Exit: if( RC_OK( rc)) { if( RC_OK( rc = pDb->pFile->pRfl->logUpdate( - uiContainer, *puiDrn, uiAutoTrans, NULL, pRecord)) && + uiContainer, uiDrn, uiAutoTrans, NULL, pRecord)) && bLogCompleteIndexSet && - pDb->pFile->FileHdr.uiVersionNum <= FLM_VER_4_51) + pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51) { // Log the fact that we indexed everything so the redo will also // index all data records in the container. - rc = pDb->pFile->pRfl->logIndexSet( *puiDrn, 0, 1, 0xFFFFFFFF); + rc = pDb->pFile->pRfl->logIndexSet( uiDrn, 0, 1, 0xFFFFFFFF); } } @@ -251,9 +256,9 @@ Exit: pDbStats->bHaveStats = TRUE; } - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { - flmUpdEventCallback( pDb, F_EVENT_ADD_RECORD, hDb, rc, *puiDrn, + flmUpdEventCallback( pDb, F_EVENT_ADD_RECORD, hDb, rc, uiDrn, uiContainer, pRecord, NULL); } @@ -266,6 +271,11 @@ Exit: ExitCS: + if( puiDrn) + { + *puiDrn = uiDrn; + } + flmExit( FLM_RECORD_ADD, pDb, rc); return( rc); } @@ -287,12 +297,17 @@ RCODE flmAddRecord( FLMBOOL * pbLogCompleteIndexSet) { RCODE rc = FERR_OK; - FLMUINT uiDrn = *puiDrn; + FLMUINT uiDrn = 0; FLMBOOL bProcessedKeys = FALSE; FLMUINT uiLfNum = pLFile->uiLfNum; FLMUINT uiAddAppendFlags = REC_UPD_ADD; FLMBOOL bHadUniqueKeys; + if( puiDrn) + { + uiDrn = *puiDrn; + } + if( pDb->uiFlags & FDB_COMMITTING_TRANS) { flmAssert( 0); @@ -325,9 +340,13 @@ RCODE flmAddRecord( pRecord, NULL, bDoInBackground, bCreateSuspended, pbLogCompleteIndexSet))) { - *puiDrn = uiDrn; // Set return value + if( puiDrn) + { + *puiDrn = uiDrn; + } } - goto Exit; // all done. + + goto Exit; } else { @@ -379,7 +398,11 @@ RCODE flmAddRecord( { goto Exit; } - *puiDrn = uiDrn; // Set return value. + + if( puiDrn) + { + *puiDrn = uiDrn; + } // Sort and check keys for uniqueness. @@ -430,7 +453,7 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Modifies a record within a container. Notes: If an index definition record is modified in the dictionary container, the index B-TREE will be deleted and rebuilt automatically when the @@ -456,7 +479,7 @@ Notes: If an index definition record is modified in the dictionary container, Changing a field type or changing a field definition record into an index definition record is not allowed. For information on changing the state of a field, see the Dictionary Syntax document. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmRecordModify( HFDB hDb, FLMUINT uiContainer, @@ -694,7 +717,7 @@ Exit: if( RC_OK( rc = pDb->pFile->pRfl->logUpdate( uiContainer, uiDrn, uiAutoTrans, pOldRecord, pRecord)) && bLogCompleteIndexSet && - pDb->pFile->FileHdr.uiVersionNum <= FLM_VER_4_51) + pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51) { // Log the fact that we indexed everything so the redo will also // index all data records in the container. @@ -710,7 +733,7 @@ Exit: pDbStats->bHaveStats = TRUE; } - if( gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmUpdEventCallback( pDb, F_EVENT_MODIFY_RECORD, hDb, rc, uiDrn, uiContainer, pRecord, pOldRecord); @@ -740,7 +763,7 @@ ExitCS: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Deletes a record from a container. Notes: If an index definition record or a container definition record is deleted from the dictionary container, the index B-TREE container or @@ -749,7 +772,7 @@ Notes: If an index definition record or a container definition record is dictionary using this routine if the field is not in use. For more information on deletion of field definitions, see the Dictionary Syntax document. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmRecordDelete( HFDB hDb, FLMUINT uiContainer, @@ -806,10 +829,11 @@ FLMEXP RCODE FLMAPI FlmRecordDelete( goto Exit; } - if( gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { // Do not have flmDeleteRecord fetch the old version of the record // unless an event callback is registered. + ppOldRecord = &pOldRecord; } @@ -836,7 +860,7 @@ Exit: pDbStats->bHaveStats = TRUE; } - if( gv_FlmSysData.EventHdrs [F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmUpdEventCallback( pDb, F_EVENT_DELETE_RECORD, hDb, rc, uiDrn, uiContainer, NULL, pOldRecord); @@ -995,3 +1019,186 @@ Exit: rc = FB_OperationEnd( pDb, rc); return( rc); } + +/**************************************************************************** +Desc: Returns the next DRN that record ADD would return. The database + must be in an existing update transaction. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmReserveNextDrn( + HFDB hDb, + FLMUINT uiContainer, + FLMUINT * puiDrnRV) +{ + RCODE rc; + FDB * pDb = (FDB *)hDb; + LFILE * pLFile; + FLMBOOL bIgnore; + FLMUINT uiDrn = 0; + + if (IsInCSMode( hDb)) + { + fdbInitCS( pDb); + + CS_CONTEXT * pCSContext = pDb->pCSContext; + FCL_WIRE Wire( pCSContext, pDb); + + // Send the request + + if( RC_BAD( rc = Wire.sendOp( + FCS_OPCLASS_RECORD, FCS_OP_RESERVE_NEXT_DRN))) + { + goto ExitCS; + } + + if( uiContainer) + { + if (RC_BAD( rc = Wire.sendNumber( + WIRE_VALUE_CONTAINER_ID, uiContainer))) + { + goto Transmission_Error; + } + } + + if( RC_BAD( rc = Wire.sendTerminate())) + { + goto Transmission_Error; + } + + // Read the response + + if( RC_BAD( rc = Wire.read())) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.getRCode())) + { + goto ExitCS; + } + + *puiDrnRV = Wire.getDrn(); + goto ExitCS; + +Transmission_Error: + pCSContext->bConnectionGood = FALSE; + goto ExitCS; + } + + bIgnore = FALSE; // Set to shut up compiler. + + if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, + FDB_TRANS_GOING_OK, // byFlags + 0, // wAutoTrans + &bIgnore))) // bStartedAutoTrans + { + goto Exit; + } + + if( pDb->uiFlags & FDB_COMMITTING_TRANS) + { + flmAssert( 0); + rc = RC_SET( FERR_ILLEGAL_TRANS_OP); + goto Exit; + } + + if( RC_BAD( fdictGetContainer( pDb->pDict, uiContainer, &pLFile))) + { +#ifdef FLM_DBG_LOG + uiDrn = 0; +#endif + goto Exit; + } + uiDrn = (FLMUINT) 0; // Must initialize before call. + if( RC_BAD( rc = FSGetNextDrn( pDb, pLFile, TRUE, &uiDrn))) + { +#ifdef FLM_DBG_LOG + uiDrn = 0; +#endif + goto Exit; + } + + *puiDrnRV = uiDrn; // Set return value. + +Exit: + + if (RC_OK( rc)) + { + rc = pDb->pFile->pRfl->logUpdatePacket( + RFL_RESERVE_DRN_PACKET, uiContainer, *puiDrnRV, 0); + } + + if( gv_FlmSysData.UpdateEvents.pEventCBList) + { + flmUpdEventCallback( pDb, F_EVENT_RESERVE_DRN, hDb, rc, *puiDrnRV, + uiContainer, NULL, NULL); + } + +#ifdef FLM_DBG_LOG + flmDbgLogUpdate( pDb->pFile->uiFFileId, pDb->LogHdr.uiCurrTransID, + uiContainer, uiDrn, rc, "RDrn"); +#endif + +ExitCS: + + flmExit( FLM_RESERVE_NEXT_DRN, pDb, rc); + + return( rc); +} + +/**************************************************************************** +Desc: Searches for an available DRN in the dictionary container. + Differs from FlmReserveNextDrn in that it will attempt to reuse + dictionary DRNS. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmFindUnusedDictDrn( + HFDB hDb, + FLMUINT uiStartDrn, + FLMUINT uiEndDrn, + FLMUINT * puiDrnRV) +{ + RCODE rc; + FDB * pDb = (FDB *)hDb; + FLMBOOL bIgnore = FALSE; + FDICT * pDict; + FLMUINT uiCurrDrn; + FLMUINT uiStopSearch; + + if( RC_BAD( rc = fdbInit( pDb, FLM_UPDATE_TRANS, FDB_TRANS_GOING_OK, + 0, &bIgnore))) + { + *puiDrnRV = (FLMUINT)-1; + goto Exit; + } + + // Search through the ITT table looking for the first occurance + // of ITT_EMPTY_SLOT + + pDict = pDb->pDict; + uiCurrDrn = f_max( uiStartDrn, 1); + uiStopSearch = f_min( uiEndDrn, pDict->uiIttCnt - 1); + + while (uiCurrDrn <= uiStopSearch) + { + if (pDict->pIttTbl[ uiCurrDrn].uiType == ITT_EMPTY_SLOT) + { + break; + } + else + { + uiCurrDrn++; + } + } + + if (uiCurrDrn > uiEndDrn) + { + rc = RC_SET( FERR_NO_MORE_DRNS); + goto Exit; + } + + *puiDrnRV = uiCurrDrn; + +Exit: + + fdbExit( pDb); + return( rc); +} diff --git a/flaim/src/flverify.cpp b/flaim/src/flverify.cpp index da1c829..a9c800d 100644 --- a/flaim/src/flverify.cpp +++ b/flaim/src/flverify.cpp @@ -22,73 +22,72 @@ // $Id: flverify.cpp 12266 2006-01-19 14:45:33 -0700 (Thu, 19 Jan 2006) dsanders $ //------------------------------------------------------------------------- + #include "flaimsys.h" -extern FLMBYTE gnDaysInMonth[]; - -extern FLMBYTE SENLenArray[]; - -/* Local function prototypes */ +extern FLMBYTE gnDaysInMonth[]; +extern FLMBYTE SENLenArray[]; +extern FLMBYTE flm_c60_max[]; FSTATIC eCorruptionType flmVerifyBlobField( - FLMBYTE * pBlobHdr, - FLMUINT uiBlobHdrLen); + FLMBYTE * pBlobHdr, + FLMUINT uiBlobHdrLen); FSTATIC eCorruptionType flmVerifyTextKey( - IFD * pIfd, - FLMBOOL bIxAsia, - FLMBOOL bIxArab, - FLMBYTE * pKey, - FLMUINT uiKeyLen, - FLMUINT * puiOffsetRV, - FLMUINT * puiCollateCountRV - ); + IFD * pIfd, + FLMBOOL bIxAsia, + FLMBOOL bIxArab, + FLMBYTE * pKey, + FLMUINT uiKeyLen, + FLMUINT * puiOffsetRV, + FLMUINT * puiCollateCountRV); FSTATIC eCorruptionType flmVerifyNumberKey( - FLMBYTE * pKey, - FLMUINT uiKeyLen, - FLMUINT * puiOffset - ); + FLMBYTE * pKey, + FLMUINT uiKeyLen, + FLMUINT * puiOffset); FSTATIC FLMBOOL flmGetSEN( - FLMBYTE * pTmpElmRec, - FLMUINT * puiDrnRV, - FLMUINT * puiNumBytesRV - ); - -/******************************************************************** -Desc: Verifies that a WordPerfect character is a legal character. -*********************************************************************/ + FLMBYTE * pTmpElmRec, + FLMUINT * puiDrnRV, + FLMUINT * puiNumBytesRV); + +/**************************************************************************** +Desc: Verifies that a WordPerfect character is a legal character. +****************************************************************************/ eCorruptionType flmVerifyWPChar( - FLMUINT uiCharSet, /* Character set to be verified. */ - FLMUINT uiChar /* Character to be verified. */ - ) + FLMUINT uiCharSet, + FLMUINT uiChar) { if (uiCharSet < NCHSETS) { - if (uiChar >= (FLMUINT)fwp_c60_max[ uiCharSet]) - return( FLM_BAD_CHAR); + if (uiChar >= (FLMUINT) flm_c60_max[uiCharSet]) + { + return (FLM_BAD_CHAR); + } } else if ((uiCharSet >= ACHSMIN) && (uiCharSet < ACHSETS)) { if (uiChar > ACHCMAX) - return( FLM_BAD_ASIAN_CHAR); + { + return (FLM_BAD_ASIAN_CHAR); + } } else { - return( FLM_BAD_CHAR_SET); + return (FLM_BAD_CHAR_SET); } - return( FLM_NO_CORRUPTION); + return (FLM_NO_CORRUPTION); } -/******************************************************************** -Desc: This routine verifies a text field. It makes sure that all of - the characters, formatting codes, etc. are valid. -*********************************************************************/ +/**************************************************************************** +Desc: This routine verifies a text field. It makes sure that all of the + characters, formatting codes, etc. are valid. +****************************************************************************/ eCorruptionType flmVerifyTextField( - FLMBYTE * pText, /* Pointer to place where text field begins. */ - FLMUINT uiTextLen) /* Byte length of text field. */ + FLMBYTE * pText, + FLMUINT uiTextLen) { FLMUINT uiChar1; FLMUINT uiBytesProcessed; @@ -101,261 +100,294 @@ eCorruptionType flmVerifyTextField( if (!uiTextLen) { - return( FLM_NO_CORRUPTION); + return (FLM_NO_CORRUPTION); } - /* - Parse through the data, verifying that it is consistent with - the internal TEXT format. - */ + // Parse through the data, verifying that it is consistent with the + // internal TEXT format. uiBytesProcessed = 0; while (uiBytesProcessed < uiTextLen) { - /* Determine what we are pointing at. */ - uiChar1 = (FLMUINT)*pText; - uiObjType = (FLMUINT)(GedTextObjType( uiChar1)); + // Determine what we are pointing at + + uiChar1 = (FLMUINT) * pText; + uiObjType = (FLMUINT) (flmTextObjType( uiChar1)); + switch (uiObjType) { case ASCII_CHAR_CODE: + { uiObjLen = 1; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - /* There should NEVER be a character less than 32. */ + // There should NEVER be a character less than 32. if (uiChar1 < 32) - return( FLM_BAD_CHAR); + { + return (FLM_BAD_CHAR); + } + break; + } + case CHAR_SET_CODE: + { uiObjLen = 2; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - /* - If the character set is zero, it had better be a valid - character. - */ + // If the character set is zero, it had better be a valid + // character. uiChar = *(pText + 1); - if ((uiCharSet = (FLMUINT)(uiChar1 & (~uiObjType))) == 0) + if ((uiCharSet = (FLMUINT) (uiChar1 & (~uiObjType))) == 0) { if ((uiChar < 32) || (uiChar > 127)) - return( FLM_BAD_CHAR); + { + return (FLM_BAD_CHAR); + } } else { - /* Make sure we have a valid WordPerfect character. */ + // Make sure we have a valid WordPerfect character. - if ((eCorruptionCode = flmVerifyWPChar( uiCharSet, uiChar)) != FLM_NO_CORRUPTION) - return( eCorruptionCode); + if ((eCorruptionCode = + flmVerifyWPChar( uiCharSet, uiChar)) != FLM_NO_CORRUPTION) + { + return (eCorruptionCode); + } } + break; + } + case WHITE_SPACE_CODE: + { uiObjLen = 1; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - + break; - - case UNICODE_CODE: /* Unconvertable UNICODE code */ + } + + case UNICODE_CODE: + { uiObjLen = 3; - + if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - - // Anything is valid except 0xFFFF or 0xFFFE. + + // Anything is valid except 0xFFFF or 0xFFFE. + break; + } + case UNK_GT_255_CODE: case UNK_LE_255_CODE: + { if (uiObjType == UNK_GT_255_CODE) { - uiObjLen = 1 + sizeof( FLMUINT16); + uiObjLen = 1 + sizeof(FLMUINT16); - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not + // going to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - uiLength = (FLMUINT)FB2UW( pText + 1); + uiLength = (FLMUINT) FB2UW( pText + 1); } else { uiObjLen = 2; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not + // going to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - uiLength = (FLMUINT)*(pText + 1); + uiLength = (FLMUINT) * (pText + 1); } if (uiLength > 65535 - uiObjLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } uiObjLen += uiLength; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) { - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); } - /* Make sure it is one of our valid types. */ + // Make sure it is one of our valid types. if (((uiChar1 & (~uiObjType)) != WP60_TYPE) && ((uiChar1 & (~uiObjType)) != NATIVE_TYPE)) - return( FLM_BAD_TEXT_FIELD); + { + return (FLM_BAD_TEXT_FIELD); + } break; + } + case UNK_EQ_1_CODE: + { uiObjLen = 2; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) - return( FLM_BAD_TEXT_FIELD); + { + return (FLM_BAD_TEXT_FIELD); + } - /* Make sure it is one of our valid types. */ + // Make sure it is one of our valid types. if (((uiChar1 & (~uiObjType)) != WP60_TYPE) && ((uiChar1 & (~uiObjType)) != NATIVE_TYPE)) - return( FLM_BAD_TEXT_FIELD); + { + return (FLM_BAD_TEXT_FIELD); + } + break; + } + case EXT_CHAR_CODE: + { uiObjLen = 3; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) - return( FLM_BAD_TEXT_FIELD); + { + return (FLM_BAD_TEXT_FIELD); + } - /* - If the character set is zero, the character had better - be between 32 and 127. - */ + // If the character set is zero, the character had better be + // between 32 and 127. - uiChar = (FLMUINT)(*(pText + 2)); - if ((uiCharSet = (FLMUINT)(*(pText + 1))) == 0) + uiChar = (FLMUINT) (*(pText + 2)); + if ((uiCharSet = (FLMUINT) (*(pText + 1))) == 0) { if ((uiChar < 32) || (uiChar > 127)) - return( FLM_BAD_CHAR); + { + return (FLM_BAD_CHAR); + } } else { - /* Make sure we have a valid WordPerfect character. */ + // Make sure we have a valid WordPerfect character. - if ((eCorruptionCode = flmVerifyWPChar( uiCharSet, uiChar)) != FLM_NO_CORRUPTION) - return( eCorruptionCode); + if ((eCorruptionCode = + flmVerifyWPChar( uiCharSet, uiChar)) != FLM_NO_CORRUPTION) + { + return (eCorruptionCode); + } } + break; + } + case OEM_CODE: + { uiObjLen = 2; - /* - Before testing anything else, make sure that we are not going - to access something beyond the end of the buffer. - */ + // Before testing anything else, make sure that we are not going + // to access something beyond the end of the buffer. if (uiBytesProcessed + uiObjLen > uiTextLen) - return( FLM_BAD_TEXT_FIELD); + { + return (FLM_BAD_TEXT_FIELD); + } - /* OEM characters must be > 127. */ + // OEM characters must be > 127. if (*(pText + 1) <= 127) - return( FLM_BAD_CHAR); + { + return (FLM_BAD_CHAR); + } break; + } + default: + { - /* These codes should NEVER HAPPEN. */ + // These codes should NEVER HAPPEN. - return( FLM_BAD_TEXT_FIELD); + return (FLM_BAD_TEXT_FIELD); + } } + pText += uiObjLen; uiBytesProcessed += uiObjLen; } - return( FLM_NO_CORRUPTION); + return (FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: This routine verifies a number field. -*********************************************************************/ +/**************************************************************************** +Desc: This routine verifies a number field. +****************************************************************************/ eCorruptionType flmVerifyNumberField( - FLMBYTE * pNumber, /* Pointer to number to be verified. */ - FLMUINT uiNumberLen /* Length of number to be verified. */ - ) + FLMBYTE * pNumber, + FLMUINT uiNumberLen) { - FLMUINT uiChar; - FLMBOOL bFirstNibble; - FLMUINT uiNibbleCount; - FLMBOOL bHitExponent; /* Set when 'E' (exponent) parsed */ - FLMBOOL bRealNumberFlag; /* Set if 'E' found at all */ - - bHitExponent = bRealNumberFlag = FALSE; + FLMUINT uiChar; + FLMBOOL bFirstNibble; + FLMUINT uiNibbleCount; + FLMBOOL bHitExponent = FALSE; + FLMBOOL bRealNumberFlag = FALSE; if (!uiNumberLen) - return( FLM_NO_CORRUPTION); + { + return (FLM_NO_CORRUPTION); + } + bFirstNibble = TRUE; uiNibbleCount = 0; + for (;;) { - /* Determine what we are pointing at. */ + // Determine what we are pointing at - uiChar = (FLMUINT)(*pNumber); + uiChar = (FLMUINT) (*pNumber); if (bFirstNibble) { uiChar >>= 4; @@ -373,230 +405,297 @@ eCorruptionType flmVerifyNumberField( switch (uiChar) { case 0x0A: + { + + // Periods are currently NOT supported. - /* Periods are currently NOT supported. */ - - return( FLM_BAD_NUMBER_FIELD); + return (FLM_BAD_NUMBER_FIELD); + } + case 0x0B: + { - /* The minus had better be the very FIRST character except E-xF. */ + // The minus had better be the very FIRST character except E-xF. if (uiNibbleCount > 1 && !bHitExponent) - return( FLM_BAD_NUMBER_FIELD); + { + return (FLM_BAD_NUMBER_FIELD); + } break; - case 0x0C: /* Imaginary numbers not implemented */ - case 0x0D: /* DIVIDE not yet implemented */ - return( FLM_BAD_NUMBER_FIELD); - case 0x0E: /* EXPONENT */ - - /* - 'E' should be in the first or second position, but the format - has the ability to change at a later time. - */ + } + + case 0x0C: + case 0x0D: + { + return (FLM_BAD_NUMBER_FIELD); + } + + case 0x0E: + { + + // 'E' should be in the first or second position, but the format + // has the ability to change at a later time. if (bRealNumberFlag) { - return( FLM_BAD_NUMBER_FIELD); /* Hit 2 "E's" */ + return (FLM_BAD_NUMBER_FIELD); } - bRealNumberFlag = + + bRealNumberFlag = TRUE; bHitExponent = TRUE; break; + } + case 0x0F: - if (bHitExponent) /* Set during parse of exponent */ + { + if (bHitExponent) { - bHitExponent = FALSE; /* Reset back to FALSE */ + bHitExponent = FALSE; break; } - /* If we didn't end right on the last byte, we have a problem. */ + // If we didn't end right on the last byte, we have a problem. if ((uiNibbleCount + 1) / 2 < uiNumberLen) - return( FLM_BAD_NUMBER_FIELD); + { + return (FLM_BAD_NUMBER_FIELD); + } else - return( FLM_NO_CORRUPTION); + { + return (FLM_NO_CORRUPTION); + } + } + default: + { break; + } } - /* - If we are at the last byte, but have not encountered a 0x0F - we have a corrupted number. - */ + // If we are at the last byte, but have not encountered a 0x0F we + // have a corrupted number. if (uiNibbleCount / 2 == uiNumberLen) - return( FLM_BAD_NUMBER_FIELD); + { + return (FLM_BAD_NUMBER_FIELD); + } - /* Numbers greater than 11 digits not yet supported. */ + // Numbers greater than 11 digits not yet supported. if (!bRealNumberFlag && (uiNibbleCount > 11)) - return( FLM_BAD_NUMBER_FIELD); + { + return (FLM_BAD_NUMBER_FIELD); + } } } - -/******************************************************************** -Desc: ? -*********************************************************************/ -FSTATIC eCorruptionType flmVerifyBlobField( - FLMBYTE * pBlobHdr, /* Pointer to blob header field. */ - FLMUINT uiBlobHdrLen /* Length of the blob header field. */ - ) +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC eCorruptionType flmVerifyBlobField( + FLMBYTE * pBlobHdr, + FLMUINT uiBlobHdrLen) { FLMUINT uiSubType; FLMUINT uiPathLen; FLMUINT uiCharLen = 1; FLMBYTE * pPath; -#define BLOB_ALIGNMENT_FUDGE 8 - if (!uiBlobHdrLen) /* Valid */ - return( FLM_NO_CORRUPTION); +#define BLOB_ALIGNMENT_FUDGE 8 + + if (!uiBlobHdrLen) + { + return (FLM_NO_CORRUPTION); + } // Definitions taken from fblob.cpp -#define BLOB_H_VERSION_LEN_POS 0 // 1 - version is also where _H_ ends -#define BLOB_CODE_VERSION 28 // BLOB Version 2.8 ends on offset 28 -#define BLOB_H_STORAGE_TYPE_POS 1 // 1 - see byStorageType -#define BLOB_H_FLAGS_POS 2 // 2 - owned, referenced, ... -#define BLOB_H_TYPE_POS 4 // 2 - user defined type - // Type of DATA or 0 if unknown -#define BLOB_H_FUTURE2 6 // ZERO for now -#define BLOB_H_RAW_SIZE_POS 8 // 4 - for large internals -#define BLOB_H_STORAGE_SIZE_POS 12 // 4 - for large internals -#define BLOB_H_MATCH_STAMP_POS 16 // 8 - match this with BLOB header -#define BLOB_MATCH_STAMP_SIZE 8 -#define BLOB_H_RIGHT_KEY_POS 24 // 4 - right part of encryption key - /* Non-portable Reference BLOB Field Layout */ -#define BLOB_R_CHARSET_POS 28 // 1=ANSI,2=UNICODE,... -#define BLOB_R_STRLENGTH_POS 29 // Char Length of reference path -#define BLOB_R_PATH_POS 30 // variable + #define BLOB_H_VERSION_LEN_POS 0 + #define BLOB_CODE_VERSION 28 + #define BLOB_H_STORAGE_TYPE_POS 1 + #define BLOB_H_FLAGS_POS 2 + #define BLOB_H_TYPE_POS 4 - /* Must be at least as big as the smallest header. */ - - if (pBlobHdr[ BLOB_H_VERSION_LEN_POS ] != BLOB_CODE_VERSION ) - return( FLM_BAD_BLOB_FIELD); - - uiSubType = (FLMUINT)(pBlobHdr[ BLOB_H_STORAGE_TYPE_POS ] & 0x0F); - - if (uiSubType == BLOB_REFERENCE_TYPE ) + // Type of DATA or 0 if unknown + + #define BLOB_H_FUTURE2 6 + #define BLOB_H_RAW_SIZE_POS 8 + #define BLOB_H_STORAGE_SIZE_POS 12 + #define BLOB_H_MATCH_STAMP_POS 16 + #define BLOB_MATCH_STAMP_SIZE 8 + #define BLOB_H_RIGHT_KEY_POS 24 + + // Non-portable Reference BLOB Field Layout + + #define BLOB_R_CHARSET_POS 28 + #define BLOB_R_STRLENGTH_POS 29 + #define BLOB_R_PATH_POS 30 + + // Must be at least as big as the smallest header. + + if (pBlobHdr[BLOB_H_VERSION_LEN_POS] != BLOB_CODE_VERSION) { - if (uiBlobHdrLen < BLOB_R_PATH_POS ) - return( FLM_BAD_BLOB_FIELD); - - if (pBlobHdr[ BLOB_R_CHARSET_POS ] == 1 ) // ANSI + return (FLM_BAD_BLOB_FIELD); + } + + uiSubType = (FLMUINT) (pBlobHdr[BLOB_H_STORAGE_TYPE_POS] & 0x0F); + + if (uiSubType == BLOB_REFERENCE_TYPE) + { + if (uiBlobHdrLen < BLOB_R_PATH_POS) { - uiPathLen = pBlobHdr[ BLOB_R_STRLENGTH_POS ]; + return (FLM_BAD_BLOB_FIELD); } - else if (pBlobHdr[ BLOB_R_CHARSET_POS ] == 2 ) // UNICODE + + if (pBlobHdr[BLOB_R_CHARSET_POS] == 1) // ANSI { - uiPathLen = (FLMUINT)(pBlobHdr[ BLOB_R_STRLENGTH_POS ] * 2); + uiPathLen = pBlobHdr[BLOB_R_STRLENGTH_POS]; + } + else if (pBlobHdr[BLOB_R_CHARSET_POS] == 2) // UNICODE + { + uiPathLen = (FLMUINT) (pBlobHdr[BLOB_R_STRLENGTH_POS] * 2); uiCharLen = 2; } else - return( FLM_BAD_BLOB_FIELD); - - /* uiPathLen will include the NULL byte(s). */ - - if( uiBlobHdrLen < BLOB_R_PATH_POS + uiPathLen ) - return( FLM_BAD_BLOB_FIELD); - /* - Comment out until fix in attach() trims the length. - if( uiBlobHdrLen > BLOB_R_PATH_POS + BLOB_ALIGNMENT_FUDGE + uiPathLen ) - return( FLM_BAD_BLOB_FIELD); - */ - pPath = pBlobHdr + BLOB_R_PATH_POS; + { + return (FLM_BAD_BLOB_FIELD); + } + + // uiPathLen will include the NULL byte(s). + + if (uiBlobHdrLen < BLOB_R_PATH_POS + uiPathLen) + { + return (FLM_BAD_BLOB_FIELD); + } + + pPath = pBlobHdr + BLOB_R_PATH_POS; } else { - return( FLM_BAD_BLOB_FIELD); + return (FLM_BAD_BLOB_FIELD); } - /* - Verify FILENAME that no characters are less than 0x20 and zero terminates. - uiPathLen includes the NULL byte/word so pre-decrement. - Zero or one path length is invalid. - EXTERNAL and REFERENCE BLOBS ONLY! - */ - - if( uiPathLen <= 1) - return( FLM_BAD_BLOB_FIELD); - - for( ; --uiPathLen; ) + + // Verify FILENAME that no characters are less than 0x20 and zero + // terminates. uiPathLen includes the NULL byte/word so pre-decrement. + // Zero or one path length is invalid. EXTERNAL and REFERENCE BLOBS + // ONLY! + + if (uiPathLen <= 1) { - if( uiCharLen == 1) + return (FLM_BAD_BLOB_FIELD); + } + + for (; --uiPathLen;) + { + if (uiCharLen == 1) { - if( *pPath++ < 0x20 ) - return( FLM_BAD_BLOB_FIELD); + if (*pPath++ < 0x20) + { + return (FLM_BAD_BLOB_FIELD); + } } else { - if( FB2UW( pPath ) < 0x20 ) - return( FLM_BAD_BLOB_FIELD); + if (FB2UW( pPath) < 0x20) + { + return (FLM_BAD_BLOB_FIELD); + } + pPath += 2; } } - if( uiCharLen == 1) + + if (uiCharLen == 1) { - if( *pPath++ != 0) - return( FLM_BAD_BLOB_FIELD); + if (*pPath++ != 0) + { + return (FLM_BAD_BLOB_FIELD); + } } else { - if( FB2UW( pPath ) != 0 ) - return( FLM_BAD_BLOB_FIELD); + if (FB2UW( pPath) != 0) + { + return (FLM_BAD_BLOB_FIELD); + } + pPath += 2; } - return( FLM_NO_CORRUPTION); + + return (FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: ? -*********************************************************************/ +/**************************************************************************** +Desc: +****************************************************************************/ eCorruptionType flmVerifyField( - FLMBYTE * pField, + FLMBYTE* pField, FLMUINT uiFieldLen, FLMUINT uiFieldType) { - if( ((uiFieldLen) && (!pField)) || ((!uiFieldLen) && (pField))) - return( FLM_BAD_FIELD_PTR); + if (((uiFieldLen) && (!pField)) || ((!uiFieldLen) && (pField))) + { + return (FLM_BAD_FIELD_PTR); + } - switch( uiFieldType) + switch (uiFieldType) { case FLM_TEXT_TYPE: - return( flmVerifyTextField( pField, uiFieldLen)); + { + return (flmVerifyTextField( pField, uiFieldLen)); + } + case FLM_NUMBER_TYPE: - return( flmVerifyNumberField( pField, uiFieldLen)); + { + return (flmVerifyNumberField( pField, uiFieldLen)); + } + case FLM_BINARY_TYPE: + { break; + } + case FLM_BLOB_TYPE: - return( flmVerifyBlobField( pField, uiFieldLen)); + { + return (flmVerifyBlobField( pField, uiFieldLen)); + } + case FLM_CONTEXT_TYPE: - /* Length must be zero or four in context fields. */ + { + + // Length must be zero or four in context fields. if ((uiFieldLen != 0) && (uiFieldLen != 4)) - return( FLM_BAD_CONTEXT_FIELD); + { + return (FLM_BAD_CONTEXT_FIELD); + } break; + } + default: - /* Unknown type. */ - return( FLM_BAD_FIELD_TYPE); + { + + // Unknown type. + + return (FLM_BAD_FIELD_TYPE); + } } - return( FLM_NO_CORRUPTION); + + return (FLM_NO_CORRUPTION); } -/******************************************************************** -Desc: Verifies a text field within a key - compound or single. -*********************************************************************/ +/**************************************************************************** +Desc: Verifies a text field within a key - compound or single. +****************************************************************************/ FSTATIC eCorruptionType flmVerifyTextKey( - IFD * pIfd, /* Pointer to index field definition - structure. */ - FLMBOOL bIxAsia, /* Is this one of the ASIAN indexes? */ - FLMBOOL bIxArab, /* Is this one of the ARAB indexes? */ - FLMBYTE * pKey, /* Pointer to beginning of key. */ - FLMUINT uiKeyLen, /* Byte length of entire key. */ - FLMUINT * puiOffsetRV, /* Offset in key where text key begins. - Returns offset where text key ends. */ - FLMUINT * puiCollateCountRV /* Returns the number of collation - characters. */ - ) + IFD * pIfd, // Pointer to index field definition structure. + FLMBOOL bIxAsia, // Is this one of the ASIAN indexes? + FLMBOOL bIxArab, // Is this one of the ARAB indexes? + FLMBYTE * pKey, // Pointer to beginning of key. + FLMUINT uiKeyLen, // Byte length of entire key. + FLMUINT * puiOffsetRV, // Offset in key where text key begins. + // Returns offset where text key ends. + FLMUINT* puiCollateCountRV) // Returns the number of collation characters. { FLMUINT uiCntJ = *puiOffsetRV; FLMUINT uiTextCollateCount = 0; @@ -608,20 +707,21 @@ FSTATIC eCorruptionType flmVerifyTextKey( FLMUINT uiNextChar = 0; FLMUINT uiCaseBits; - /* - See how many collated values there are - go until we hit - 0x07, 0x02, 0x04, 0x05, 0x06, 0x01, or end of key. - */ + // See how many collated values there are - go until we hit 0x07, 0x02, + // 0x04, 0x05, 0x06, 0x01, or end of key. while (uiCntJ < uiKeyLen) { - uiNextChar = (FLMUINT)pKey [uiCntJ]; + uiNextChar = (FLMUINT) pKey[uiCntJ]; if (bIxAsia) { if (uiCntJ + 1 >= uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiNextChar <<= 8; - uiNextChar += pKey [uiCntJ + 1]; + uiNextChar += pKey[uiCntJ + 1]; } if ((uiNextChar == END_COMPOUND_MARKER) || @@ -632,70 +732,88 @@ FSTATIC eCorruptionType flmVerifyTextKey( ((uiNextChar == (COLL_MARKER | SC_LOWER)) && (!bIxAsia)) || ((uiNextChar == (COLL_MARKER | SC_UPPER)) && (!bIxAsia)) || (uiNextChar == COLL_TRUNCATED)) - { - /* These checks must be in order */ + { + + // These checks must be in order + if (uiCntJ > *puiOffsetRV && uiNextChar == COLL_FIRST_SUBSTRING) { uiCntJ++; if (bIxAsia) + { uiCntJ++; + } + continue; } + if (uiNextChar == COLL_TRUNCATED) { uiCntJ++; - if( bIxAsia) + if (bIxAsia) { uiCntJ++; } // Get character after COLL_TRUNCATED, if any - if( uiCntJ < uiKeyLen) + if (uiCntJ < uiKeyLen) { - uiNextChar = (FLMUINT)pKey[ uiCntJ]; + uiNextChar = (FLMUINT) pKey[uiCntJ]; if (bIxAsia) { if (uiCntJ + 1 >= uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiNextChar <<= 8; - uiNextChar += pKey [uiCntJ + 1]; + uiNextChar += pKey[uiCntJ + 1]; } } } break; } - /* - It is impossible to have a collated value that is - less than 0x20 (space). - */ + // It is impossible to have a collated value that is less than 0x20 + // (space). if (uiNextChar < 0x20) - return( FLM_BAD_TEXT_KEY_COLL_CHAR); + { + return (FLM_BAD_TEXT_KEY_COLL_CHAR); + } + uiTextCollateCount++; uiCntJ++; if (bIxAsia) + { uiCntJ++; + } } - /* See if we got sub-collation values. */ + // See if we got sub-collation values. if ((uiCntJ < uiKeyLen) && (uiNextChar == 0x07)) { uiCntJ++; if (bIxAsia) + { uiCntJ++; + } + if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiCntK = 0; uiBit = 0x80; - uiChar = pKey[ uiCntJ]; + uiChar = pKey[uiCntJ]; for (;;) { FLMUINT uiBitCode; - /* Determine what the code is. */ + // Determine what the code is. uiBitCode = 0; while (uiChar & uiBit) @@ -703,105 +821,131 @@ FSTATIC eCorruptionType flmVerifyTextKey( uiBitCode |= 0x01; uiBitCode <<= 1; - /* Get the next bit. */ + // Get the next bit. uiBit >>= 1; - /* See if we need to get the next byte. */ + // See if we need to get the next byte. if (!uiBit) { uiCntJ++; if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiChar = (FLMUINT)pKey [uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } + + uiChar = (FLMUINT) pKey[uiCntJ]; uiBit = 0x80; } } - /* - The uiBitCode value tells whether or not there is a collating - value and what type it is. - */ + // The uiBitCode value tells whether or not there is a collating + // value and what type it is. switch (uiBitCode) { - /* Code of zero means there is no collating value. */ + // Code of zero means there is no collating value. case 0: + { if ((!uiTextCollateCount) && (bIxArab)) + { uiBitsToSkip = 0; + } else + { uiBitsToSkip = 1; + } + uiCntK++; break; + } - /* - Code of 0x02 means that the sub-collation value is the - next five bits. - */ + // Code of 0x02 means that the sub-collation value is the next + // five bits. case 0x02: + { uiBitsToSkip = 6; uiCntK++; break; + } - /* - Code of 0x06 means that next two bytes contains sub-collation. - Code of 0x0E should only happen in Arabic, means that - next two bytes contains sub-collation, but should not be - counted. - */ + // Code of 0x06 means that next two bytes contains sub-collation. + // Code of 0x0E should only happen in Arabic, means that next two + // bytes contains sub-collation, but should not be counted. case 0x0E: + { if (!bIxArab) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiArabCollateCount++; - /* Deliberate fall through to 0x06 case. */ + // Fall through to 0x06 case. + } case 0x06: + { uiBitsToSkip = 0; uiCntJ += 3; + if (uiCntJ > uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiBit = 0x80; - uiChar = (FLMUINT)pKey[ uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } - /* If Arabic, the sub-collation should not be counted. */ + uiBit = 0x80; + uiChar = (FLMUINT) pKey[uiCntJ]; + + // If Arabic, the sub-collation should not be counted. if (uiBitCode != 0x0E) + { uiCntK++; + } + break; + } - /* - Unicode character that did not convert to a WP char. The - actual unicode character follows the 1E. - */ + // Unicode character that did not convert to a WP char. The + // actual unicode character follows the 1E. case 0x1E: + { uiBitsToSkip = 0; uiCntJ += 3; if (uiCntJ > uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiBit = 0x80; - uiChar = (FLMUINT)pKey[ uiCntJ]; + uiChar = (FLMUINT) pKey[uiCntJ]; uiCntK++; - // The spec for Unicode has an additional case bit. - // Added Oct 98. - // Note, the extra case bit is only set if we are not - // an asian index. + + // The spec for Unicode has an additional case bit. Added Oct + // 98. Note, the extra case bit is only set if we are not an + // asian index. + if (!bIxAsia) { uiArabCollateCount++; } break; + } + default: - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } } - /* Skip the required number of bits. */ + // Skip the required number of bits. while (uiBitsToSkip) { @@ -811,297 +955,335 @@ FSTATIC eCorruptionType flmVerifyTextKey( { uiCntJ++; if (uiCntJ == uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiChar = (FLMUINT)pKey[ uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } + + uiChar = (FLMUINT) pKey[uiCntJ]; uiBit = 0x80; } } - /* See if we are done processing. */ - - - /* See if we are done processing. */ - if (uiCntK >= uiTextCollateCount) { - if( !bIxArab) + if (!bIxArab) { break; } - /* - Arab languages have one more terminating bit. - See if we need to go to the next byte. - */ + // Arab languages have one more terminating bit. See if we + // need to go to the next byte. if (!uiBit) { - /* Terminating bit is in next byte. */ + // Terminating bit is in next byte. uiCntJ++; if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiChar = (FLMUINT)pKey [uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } + + uiChar = (FLMUINT) pKey[uiCntJ]; uiBit = 0x80; } - /* - If the next bit isn't set, we are done. However, we - must skip the current character - */ + // If the next bit isn't set, we are done. However, we must + // skip the current character - if( !(uiChar & uiBit)) + if (!(uiChar & uiBit)) { uiCntJ++; if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiChar = (FLMUINT)pKey [ uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } + + uiChar = (FLMUINT) pKey[uiCntJ]; uiBit = 0x80; break; } } } - /* If NOT at beginning of byte, increment uiCntJ to skip rest of byte. */ + // If NOT at beginning of byte, increment uiCntJ to skip rest of + // byte. if (uiBit != 0x80) + { uiCntJ++; + } } - /* Do lower/upper case bits -- unless a POST index. */ + // Do lower/upper case bits -- unless a POST index. if (pIfd->uiFlags & IFD_POST) + { *puiCollateCountRV = uiTextCollateCount + uiArabCollateCount; + } else { - /* If there are no UPPER/LOWER indicators, we have a problem. */ + // If there are no UPPER/LOWER indicators, we have a problem. if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); - uiNextChar = (FLMUINT)pKey [uiCntJ]; + { + return (FLM_BAD_KEY_LEN); + } + + uiNextChar = (FLMUINT) pKey[uiCntJ]; uiCntJ++; if (bIxAsia) { if (uiCntJ >= uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiNextChar <<= 8; - uiNextChar += (FLMUINT)pKey [uiCntJ]; + uiNextChar += (FLMUINT) pKey[uiCntJ]; uiCntJ++; } + switch (uiNextChar) { - case COLL_FIRST_SUBSTRING: // Same as NULL_KEY_MARKER: + case COLL_FIRST_SUBSTRING: + { break; + } + case COLL_TRUNCATED: + { break; + } + case (COLL_MARKER | SC_LOWER): case (COLL_MARKER | SC_UPPER): + { if (bIxAsia) - return( FLM_BAD_TEXT_KEY_CASE_MARKER); + { + return (FLM_BAD_TEXT_KEY_CASE_MARKER); + } break; + } + case (COLL_MARKER | SC_MIXED): + { uiCaseBits = uiTextCollateCount + uiArabCollateCount; if (bIxAsia) + { uiCaseBits <<= 1; + } + uiCntJ += ((uiCaseBits + 7) >> 3); break; + } + default: - return( FLM_BAD_TEXT_KEY_CASE_MARKER); + { + return (FLM_BAD_TEXT_KEY_CASE_MARKER); + } } } + if (uiCntJ > uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + *puiOffsetRV = uiCntJ; - return( FLM_NO_CORRUPTION); + return (FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: ? -*********************************************************************/ +/**************************************************************************** +Desc: +****************************************************************************/ FSTATIC eCorruptionType flmVerifyNumberKey( FLMBYTE * pKey, FLMUINT uiKeyLen, - FLMUINT * puiOffsetRV - ) + FLMUINT * puiOffsetRV) { FLMUINT uiCntJ = *puiOffsetRV; FLMUINT uiChar; FLMUINT uiNumDigits; FLMUINT uiNibble; - /* Determine the number of digits. */ + // Determine the number of digits. - uiChar = pKey [uiCntJ++]; - uiNumDigits = (FLMUINT)(uiChar & 0x7F); + uiChar = pKey[uiCntJ++]; + uiNumDigits = (FLMUINT) (uiChar & 0x7F); - /* If negative, the number of digits must be NOTed. */ + // If negative, the number of digits must be NOTed. if (!(uiChar & 0x80)) - uiNumDigits = (FLMUINT)((~uiNumDigits) & 0x7F); + { + uiNumDigits = (FLMUINT) ((~uiNumDigits) & 0x7F); + } - /* Adjust the number of digits by -64 + 1. */ + // Adjust the number of digits by -64 + 1. - uiNumDigits = (FLMUINT)(uiNumDigits - COLLATED_NUM_EXP_BIAS + 1); + uiNumDigits = (FLMUINT) (uiNumDigits - COLLATED_NUM_EXP_BIAS + 1); - /* - Process until we run out of digits or key or until - we hit the compound marker or post marker. - */ + // Process until we run out of digits or key or until we hit the + // compound marker or post marker. - while ((uiNumDigits) && - (uiCntJ < uiKeyLen) && - (pKey[ uiCntJ] != 0x02) && - (pKey[ uiCntJ] != 0x01)) + while( uiNumDigits && (uiCntJ < uiKeyLen) && (pKey[uiCntJ] != 0x02) && + (pKey[uiCntJ] != 0x01)) { - /* Check the first nibble. */ + // Check the first nibble. - uiNibble = (FLMUINT)((pKey[ uiCntJ] >> 4) & 0x0F); + uiNibble = (FLMUINT) ((pKey[uiCntJ] >> 4) & 0x0F); if ((uiNibble < 0x05) || (uiNibble > 0x0E)) - return( FLM_BAD_NUMBER_KEY); + { + return (FLM_BAD_NUMBER_KEY); + } + uiNumDigits--; - /* - Check the 2nd nibble. If we are out of digits - it had better be 0x0F. - */ + // Check the 2nd nibble. If we are out of digits it had better be + // 0x0F. - uiNibble = (FLMUINT)(pKey[ uiCntJ] & 0x0F); + uiNibble = (FLMUINT) (pKey[uiCntJ] & 0x0F); if (!uiNumDigits) { if (uiNibble != 0x0F) - return( FLM_BAD_NUMBER_KEY); + { + return (FLM_BAD_NUMBER_KEY); + } } else { if ((uiNibble < 0x05) || (uiNibble > 0x0E)) { - return( FLM_BAD_NUMBER_KEY); + return (FLM_BAD_NUMBER_KEY); } + uiNumDigits--; } + uiCntJ++; } - /* - If we ran out of key before we processed all of the - digits, we have an error. - */ + // If we ran out of key before we processed all of the digits, we have + // an error. if ((uiNumDigits) && (uiCntJ > uiKeyLen)) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } *puiOffsetRV = uiCntJ; - return( FLM_NO_CORRUPTION); + return (FLM_NO_CORRUPTION); } -/******************************************************************** -Desc: This routine verifies that a collated key conforms to the index - it belongs to. -*********************************************************************/ +/**************************************************************************** +Desc: This routine verifies that a collated key conforms to the index it + belongs to. +****************************************************************************/ eCorruptionType flmVerifyKey( - FLMBYTE * pKey, /* Key which is to be verified. */ - FLMUINT uiKeyLen, /* Byte length of pKey. */ - FLMUINT uiIxLang, /* Language for index. */ - IFD * pIfdArray, /* List of fields in index. */ - FLMUINT uiNumIxFields /* Number of fields in pIfdArray. */ - ) + FLMBYTE* pKey, // Key which is to be verified. + FLMUINT uiKeyLen, // Byte length of pKey. + FLMUINT uiIxLang, // Language for index. + IFD* pIfdArray, // List of fields in index. + FLMUINT uiNumIxFields) // Number of fields in pIfdArray. { - IFD * pIfd = pIfdArray; + IFD* pIfd = pIfdArray; FLMUINT uiI; FLMUINT uiJ; -#define MAX_IX_FIELDS 100 - FLMUINT uiCollateCount [MAX_IX_FIELDS]; +#define MAX_IX_FIELDS 100 + FLMUINT uiCollateCount[MAX_IX_FIELDS]; FLMUINT uiPostByteCount; eCorruptionType eCorruptionCode; FLMUINT uiTotalTextChars = 0; - FLMBOOL bIxAsia = - (uiIxLang >= FIRST_DBCS_LANG && uiIxLang <= LAST_DBCS_LANG) - ? TRUE - : FALSE; - FLMBOOL bIxArab = (uiIxLang == AR_LANG || - uiIxLang == FA_LANG || - uiIxLang == HE_LANG || - uiIxLang == UR_LANG) - ? TRUE - : FALSE; + FLMBOOL bIxAsia; + FLMBOOL bIxArab; FLMBOOL bIxIsPost = FALSE; FLMUINT uiTrueNumIxFields = uiNumIxFields; FLMUINT uiMarkerChar; FLMUINT uiCaseBits; FLMUINT uiFieldType; - /* - If we weren't able to get the IX information from the dictionary - just return FLM_NO_CORRUPTION. - */ + bIxAsia = (uiIxLang >= FIRST_DBCS_LANG && uiIxLang <= LAST_DBCS_LANG) + ? TRUE + : FALSE; + + bIxArab = (uiIxLang == AR_LANG || uiIxLang == FA_LANG || + uiIxLang == HE_LANG || uiIxLang == UR_LANG) + ? TRUE + : FALSE; + + // If we weren't able to get the IX information from the dictionary + // just return FLM_NO_CORRUPTION. if ((!pIfdArray) || (!uiNumIxFields)) - return( FLM_NO_CORRUPTION); + { + return (FLM_NO_CORRUPTION); + } - /* See if we have a POST index. */ + // See if we have a POST index. for (uiI = 0; uiI < uiNumIxFields; uiI++) { - if (pIfdArray [uiI].uiFlags & IFD_POST) + if (pIfdArray[uiI].uiFlags & IFD_POST) { bIxIsPost = TRUE; break; } } - /* - If it is not a compound index, set the uiNumIxFields to one - we only - need to examine one field, because they are all the same type. - */ + // If it is not a compound index, set the uiNumIxFields to one - we + // only need to examine one field, because they are all the same type. if (!(pIfdArray->uiFlags & IFD_COMPOUND)) { if (bIxIsPost) - return( FLM_BAD_IX_DEF); + { + return (FLM_BAD_IX_DEF); + } + uiNumIxFields = 1; } + uiJ = 0; uiI = 0; + if (uiNumIxFields > MAX_IX_FIELDS) - return( FLM_BAD_IX_DEF); + { + return (FLM_BAD_IX_DEF); + } + while (uiJ < uiKeyLen) { - uiCollateCount [uiI] = 0; + uiCollateCount[uiI] = 0; - /* - First see if the component has anything in it. If we hit the - compound marker right away, the component piece is empty. - */ + // First see if the component has anything in it. If we hit the + // compound marker right away, the component piece is empty. - uiMarkerChar = (FLMUINT)pKey [uiJ]; + uiMarkerChar = (FLMUINT) pKey[uiJ]; if ((bIxAsia) && (IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE) && (!(pIfd->uiFlags & IFD_CONTEXT))) { if (uiJ + 1 == uiKeyLen) - return( FLM_BAD_KEY_LEN); + { + return (FLM_BAD_KEY_LEN); + } + uiMarkerChar <<= 8; - uiMarkerChar += (FLMUINT)pKey [uiJ + 1]; + uiMarkerChar += (FLMUINT) pKey[uiJ + 1]; } + if (uiMarkerChar == 2) { - - /* Removed check Oct 98 because required fields may have no data. */ - //if (!(pIfd->uiFlags & IFD_OPTIONAL)) - // return( FLM_MISSING_REQ_KEY_FIELD); ; } else if (uiMarkerChar == 1) { - /* - If we hit a 1, it should be the beginning of upper/lower case - bits for a POST index. - */ + // If we hit a 1, it should be the beginning of upper/lower case + // bits for a POST index. break; } @@ -1116,273 +1298,325 @@ eCorruptionType flmVerifyKey( } } - /* - See if indexing context. If not, use the field's type to - determine how the key is formatted. - */ + // See if indexing context. If not, use the field's type to + // determine how the key is formatted. else if (pIfd->uiFlags & IFD_CONTEXT) { - /* - If indexing context, the first byte of the key is a 0x1E - followed by the two byte tag number in high/low order. - */ + // If indexing context, the first byte of the key is a 0x1E + // followed by the two byte tag number in high/low order. - if (pKey [uiJ] != 0x1E) - return( FLM_BAD_CONTEXT_KEY); + if (pKey[uiJ] != 0x1E) + { + return (FLM_BAD_CONTEXT_KEY); + } - /* - Verify that the tag portion of the key matches the - field number. - */ + // Verify that the tag portion of the key matches the field + // number. if (pIfd->uiFlags & IFD_COMPOUND) { - if (flmBigEndianToUINT16( &pKey [uiJ + 1]) != pIfd->uiFldNum) - return( FLM_BAD_CONTEXT_KEY); + if (flmBigEndianToUINT16( &pKey[uiJ + 1]) != pIfd->uiFldNum) + { + return (FLM_BAD_CONTEXT_KEY); + } } else { FLMUINT uiH; IFD * pTmpIfd; - /* - If it is NOT a compound index, be sure to check each field in - the index to see if it matches that field number - it could - be a multi-field index. - */ + // If it is NOT a compound index, be sure to check each field + // in the index to see if it matches that field number - it + // could be a multi-field index. - for (uiH= 0, pTmpIfd = pIfdArray; - uiH < uiTrueNumIxFields; - uiH++, pTmpIfd++) + for (uiH = 0, pTmpIfd = pIfdArray; + uiH < uiTrueNumIxFields; + uiH++, pTmpIfd++) { - if (flmBigEndianToUINT16( &pKey[ uiJ + 1]) == pTmpIfd->uiFldNum) + if (flmBigEndianToUINT16( &pKey[uiJ + 1]) == pTmpIfd->uiFldNum) { break; } } - /* If it did not match any of the fields, return an error. */ + // If it did not match any of the fields, return an error. if (uiH == uiTrueNumIxFields) { - return( FLM_BAD_CONTEXT_KEY); + return (FLM_BAD_CONTEXT_KEY); } } + uiJ += 3; } else { - switch (uiFieldType = (FLMUINT)(IFD_GET_FIELD_TYPE( pIfd))) + switch (uiFieldType = (FLMUINT) (IFD_GET_FIELD_TYPE( pIfd))) { case FLM_TEXT_TYPE: - if ((eCorruptionCode = flmVerifyTextKey( pIfd, - bIxAsia, bIxArab, - pKey, uiKeyLen, &uiJ, - &uiCollateCount [uiI])) != FLM_NO_CORRUPTION) - return( eCorruptionCode); - uiTotalTextChars += uiCollateCount [uiI]; + { + if ((eCorruptionCode = flmVerifyTextKey( pIfd, bIxAsia, bIxArab, + pKey, uiKeyLen, &uiJ, + &uiCollateCount[uiI])) != FLM_NO_CORRUPTION) + { + return (eCorruptionCode); + } + + uiTotalTextChars += uiCollateCount[uiI]; break; + } + case FLM_NUMBER_TYPE: - if ((eCorruptionCode = flmVerifyNumberKey( - pKey, uiKeyLen, &uiJ)) != FLM_NO_CORRUPTION) - return( eCorruptionCode); + { + if ((eCorruptionCode = flmVerifyNumberKey( pKey, + uiKeyLen, &uiJ)) != FLM_NO_CORRUPTION) + { + return (eCorruptionCode); + } break; + } + case FLM_BINARY_TYPE: - while ((uiJ < uiKeyLen) && - (pKey[ uiJ] != 0x02) && - (pKey[ uiJ] != 0x01) && - (pKey[ uiJ] != COLL_TRUNCATED)) + { + while( (uiJ < uiKeyLen) && (pKey[uiJ] != 0x02) && + (pKey[uiJ] != 0x01) && (pKey[uiJ] != COLL_TRUNCATED)) { - if ((pKey[ uiJ] < 0x20) || (pKey[ uiJ] > 0x2F)) - return( FLM_BAD_BINARY_KEY); + if ((pKey[uiJ] < 0x20) || (pKey[uiJ] > 0x2F)) + { + return (FLM_BAD_BINARY_KEY); + } + uiJ++; } - if( uiJ < uiKeyLen && pKey[ uiJ] == COLL_TRUNCATED) + + if (uiJ < uiKeyLen && pKey[uiJ] == COLL_TRUNCATED) { uiJ++; } break; + } + case FLM_CONTEXT_TYPE: - if (pKey[ uiJ] != 0x1F) - return( FLM_BAD_DRN_KEY); + { + if (pKey[uiJ] != 0x1F) + { + return (FLM_BAD_DRN_KEY); + } + uiJ += 5; break; + } + default: - return( FLM_BAD_KEY_FIELD_TYPE); + { + return (FLM_BAD_KEY_FIELD_TYPE); + } } } - /* See if there is another field. */ + // See if there is another field. - while( ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + while( ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd + 1)->uiCompoundPos)) { - // 05/30/96 removed uiI++; - pIfd++; + pIfd++; } - + // pIfd will point to the LAST ifd with the same compound position. // pIfd increments below AFTER the compound marker is added. - + uiI++; if (uiI == uiNumIxFields) + { break; + } - /* - If this is not the last field, make sure we are pointing to a - compound marker. - */ + // If this is not the last field, make sure we are pointing to a + // compound marker. if (uiJ >= uiKeyLen) - return( FLM_BAD_KEY_COMPOUND_MARKER); - uiMarkerChar = (FLMUINT)pKey [uiJ]; + { + return (FLM_BAD_KEY_COMPOUND_MARKER); + } + + uiMarkerChar = (FLMUINT) pKey[uiJ]; uiJ++; - if ((bIxAsia) && - (IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE) && - (!(pIfd->uiFlags & IFD_CONTEXT))) + + if (bIxAsia && + IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE && + !(pIfd->uiFlags & IFD_CONTEXT)) { if (uiJ >= uiKeyLen) - return( FLM_BAD_KEY_COMPOUND_MARKER); + { + return (FLM_BAD_KEY_COMPOUND_MARKER); + } + uiMarkerChar <<= 8; - uiMarkerChar += (FLMUINT)pKey [uiJ]; + uiMarkerChar += (FLMUINT) pKey[uiJ]; uiJ++; } + if (uiMarkerChar != 2) - return( FLM_BAD_KEY_COMPOUND_MARKER); - + { + return (FLM_BAD_KEY_COMPOUND_MARKER); + } + pIfd++; } - /* - If we didn't get through all of the fields in the loop above make - sure the remaining fields are all optional. No need to check for - alternate keys. - */ + // If we didn't get through all of the fields in the loop above make + // sure the remaining fields are all optional. No need to check for + // alternate keys. while (uiI < uiNumIxFields) { - uiCollateCount [uiI] = 0; - /* Removed check Oct 98 because required fields may have no data. */ - //if (!(pIfd->uiFlags & IFD_OPTIONAL)) - // return( FLM_MISSING_REQ_KEY_FIELD); + uiCollateCount[uiI] = 0; uiI++; pIfd++; } - /* - If we have a POST index, get the lower/upper case bits for each - text field. - */ + // If we have a POST index, get the lower/upper case bits for each text + // field. if ((bIxIsPost) && (uiTotalTextChars)) { - /* If it is not a compound key, we have an error. */ + // If it is not a compound key, we have an error. if (uiNumIxFields == 1) - return( FLM_BAD_IX_DEF); + { + return (FLM_BAD_IX_DEF); + } - /* If we did not hit a 0x01, we have an error. */ + // If we did not hit a 0x01, we have an error. if (uiJ >= uiKeyLen) - return( FLM_BAD_KEY_POST_MARKER); - uiMarkerChar = (FLMUINT)pKey [uiJ]; + { + return (FLM_BAD_KEY_POST_MARKER); + } + + uiMarkerChar = (FLMUINT) pKey[uiJ]; uiJ++; - /* - If the last field is text, and we are in an Asian index we need - two bytes for the post marker. - */ + // If the last field is text, and we are in an Asian index we need + // two bytes for the post marker. if (bIxAsia) { - pIfd = &pIfdArray [uiNumIxFields - 1]; + pIfd = &pIfdArray[uiNumIxFields - 1]; if ((IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE) && (!(pIfd->uiFlags & IFD_CONTEXT))) { if (uiJ >= uiKeyLen) - return( FLM_BAD_KEY_POST_MARKER); + { + return (FLM_BAD_KEY_POST_MARKER); + } + uiMarkerChar <<= 8; - uiMarkerChar += (FLMUINT)pKey [uiJ]; + uiMarkerChar += (FLMUINT) pKey[uiJ]; uiJ++; } } - if (uiMarkerChar != 1) - return( FLM_BAD_KEY_POST_MARKER); - /* Go through all of the fields looking for TEXT fields. */ + if (uiMarkerChar != 1) + { + return (FLM_BAD_KEY_POST_MARKER); + } + + // Go through all of the fields looking for TEXT fields. uiPostByteCount = 0; uiI = 0; pIfd = pIfdArray; while ((uiI < uiNumIxFields) && (uiJ < uiKeyLen)) { - if (uiCollateCount [uiI]) + if (uiCollateCount[uiI]) { FLMINT uiTempCnt; - uiMarkerChar = pKey [uiJ]; + uiMarkerChar = pKey[uiJ]; uiJ++; uiPostByteCount++; if (bIxAsia) { if (uiJ >= uiKeyLen) - return( FLM_BAD_KEY_POST_BYTE_COUNT); + { + return (FLM_BAD_KEY_POST_BYTE_COUNT); + } + uiMarkerChar <<= 8; - uiMarkerChar += (FLMUINT)pKey [uiJ]; + uiMarkerChar += (FLMUINT) pKey[uiJ]; uiJ++; uiPostByteCount++; } + switch (uiMarkerChar) { case 4: case 6: + { if (bIxAsia) - return( FLM_BAD_TEXT_KEY_CASE_MARKER); + { + return (FLM_BAD_TEXT_KEY_CASE_MARKER); + } break; + } + case 5: - uiCaseBits = uiCollateCount [uiI]; + { + uiCaseBits = uiCollateCount[uiI]; if (bIxAsia) + { uiCaseBits <<= 1; - uiTempCnt = (FLMUINT)((uiCaseBits + 7) >> 3); + } + + uiTempCnt = (FLMUINT) ((uiCaseBits + 7) >> 3); uiJ += uiTempCnt; uiPostByteCount += uiTempCnt; break; + } + default: - return( FLM_BAD_TEXT_KEY_CASE_MARKER); + { + return (FLM_BAD_TEXT_KEY_CASE_MARKER); + } } } - while( ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + + while( ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd + 1)->uiCompoundPos)) { - uiI++; // Compares against uiNumIxFields. - pIfd++; + uiI++; // Compares against uiNumIxFields. + pIfd++; } + uiI++; pIfd++; } - /* Account for the post byte count */ + // Account for the post byte count + + if ((uiJ >= uiKeyLen) || (uiPostByteCount != (FLMUINT) pKey[uiJ])) + { + return (FLM_BAD_KEY_POST_BYTE_COUNT); + } - if ((uiJ >= uiKeyLen) || (uiPostByteCount != (FLMUINT)pKey [uiJ])) - return( FLM_BAD_KEY_POST_BYTE_COUNT); uiJ++; } - /* We must end exactly right on the end of the key. */ + // We must end exactly right on the end of the key. - return( ((uiJ != uiKeyLen) || (uiI != uiNumIxFields)) - ? FLM_BAD_KEY_LEN - : FLM_NO_CORRUPTION); + return (((uiJ != uiKeyLen) || (uiI != uiNumIxFields)) + ? FLM_BAD_KEY_LEN + : FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: Verifies a block's header and sets up the STATE_INFO structure - to verify the rest of the block. -*********************************************************************/ +/**************************************************************************** +Desc: Verifies a block's header and sets up the STATE_INFO structure to + verify the rest of the block. +****************************************************************************/ eCorruptionType flmVerifyBlockHeader( STATE_INFO * pStateInfo, BLOCK_INFO * pBlockInfoRV, @@ -1392,129 +1626,137 @@ eCorruptionType flmVerifyBlockHeader( FLMBOOL bCheckEOF, FLMBOOL bCheckFullBlkAddr) { - FLMBYTE * pBlk = pStateInfo->pBlk; + FLMBYTE * pBlk = pStateInfo->pBlk; if (pBlockInfoRV) + { pBlockInfoRV->uiBlockCount++; - pStateInfo->uiNextBlkAddr = (FLMUINT)FB2UD( &pBlk [BH_NEXT_BLK]); - if ((pStateInfo->uiEndOfBlock = - (FLMUINT)FB2UW( &pBlk [BH_ELM_END])) < BH_OVHD) + } + + pStateInfo->uiNextBlkAddr = (FLMUINT) FB2UD( &pBlk[BH_NEXT_BLK]); + if ((pStateInfo->uiEndOfBlock = + (FLMUINT) FB2UW( &pBlk[BH_ELM_END])) < BH_OVHD) { pStateInfo->uiEndOfBlock = BH_OVHD; - return( FLM_BAD_BLK_HDR_BLK_END); + return (FLM_BAD_BLK_HDR_BLK_END); } else if (pStateInfo->uiEndOfBlock > uiBlockSize) { pStateInfo->uiEndOfBlock = uiBlockSize; - return( FLM_BAD_BLK_HDR_BLK_END); + return (FLM_BAD_BLK_HDR_BLK_END); } else if (pBlockInfoRV) { - pBlockInfoRV->ui64BytesUsed += - (FLMUINT64)(pStateInfo->uiEndOfBlock - BH_OVHD); + pBlockInfoRV->ui64BytesUsed += + (FLMUINT64) (pStateInfo->uiEndOfBlock - BH_OVHD); } pStateInfo->uiElmOffset = BH_OVHD; - /* Verify the block address. */ + // Verify the block address. if (bCheckFullBlkAddr) { if (GET_BH_ADDR( pBlk) != pStateInfo->uiBlkAddress) - return( FLM_BAD_BLK_HDR_ADDR); + { + return (FLM_BAD_BLK_HDR_ADDR); + } } else { if ((GET_BH_ADDR( pBlk) & 0xFFFFFF00) != - (pStateInfo->uiBlkAddress & 0xFFFFFF00)) - return( FLM_BAD_BLK_HDR_ADDR); + (pStateInfo->uiBlkAddress & 0xFFFFFF00)) + { + return (FLM_BAD_BLK_HDR_ADDR); + } } + // Verify that block address is below the logical EOF - /* Verify that block address is below the logical EOF */ - - if (bCheckEOF && pStateInfo->pDb) // rebuild passes in FALSE + if (bCheckEOF && pStateInfo->pDb) { - if (!FSAddrIsBelow( pStateInfo->uiBlkAddress, - pStateInfo->pDb->LogHdr.uiLogicalEOF)) - return FLM_BAD_FILE_SIZE; + if (!FSAddrIsBelow( pStateInfo->uiBlkAddress, + pStateInfo->pDb->LogHdr.uiLogicalEOF)) + { + return (FLM_BAD_FILE_SIZE); + } } - /* Verify the block type. */ + // Verify the block type. if ((pStateInfo->uiBlkType != 0xFF) && - (pStateInfo->uiBlkType != (FLMUINT)BH_GET_TYPE( pBlk))) - return( FLM_BAD_BLK_HDR_TYPE); + (pStateInfo->uiBlkType != (FLMUINT) BH_GET_TYPE( pBlk))) + { + return (FLM_BAD_BLK_HDR_TYPE); + } - /* Verify the block level. */ + // Verify the block level. - if ((pStateInfo->uiLevel != 0xFF) && - (pStateInfo->uiLevel != pBlk [BH_LEVEL])) - return( FLM_BAD_BLK_HDR_LEVEL); + if ((pStateInfo->uiLevel != 0xFF) && (pStateInfo->uiLevel != pBlk[BH_LEVEL])) + { + return (FLM_BAD_BLK_HDR_LEVEL); + } - /* - Verify the previous block address. If uiExpPrevBlkAddr is zero, we do - not know what the previous address should be, so we don't verify. - */ + // Verify the previous block address. If uiExpPrevBlkAddr is zero, we + // do not know what the previous address should be, so we don't verify. if ((uiExpPrevBlkAddr) && - (uiExpPrevBlkAddr != (FLMUINT)FB2UD( &pBlk [BH_PREV_BLK]))) - return( FLM_BAD_BLK_HDR_PREV); + (uiExpPrevBlkAddr != (FLMUINT) FB2UD( &pBlk[BH_PREV_BLK]))) + { + return (FLM_BAD_BLK_HDR_PREV); + } - /* - Verify the next block address. If uiExpNextBlkAddr is zero, we do not - know what the next address should be, se we don't verify. - */ + // Verify the next block address. If uiExpNextBlkAddr is zero, we do + // not know what the next address should be, se we don't verify. - if ((uiExpNextBlkAddr) && - (uiExpNextBlkAddr != pStateInfo->uiNextBlkAddr)) - return( FLM_BAD_BLK_HDR_NEXT); + if ((uiExpNextBlkAddr) && (uiExpNextBlkAddr != pStateInfo->uiNextBlkAddr)) + { + return (FLM_BAD_BLK_HDR_NEXT); + } - /* - Verify that if it is a root block, the root bit flags is set, - or if it is NOT a root block, that the root bit flag is NOT set. - */ + // Verify that if it is a root block, the root bit flags is set, or if + // it is NOT a root block, that the root bit flag is NOT set. if (pStateInfo->pLogicalFile) { if (pStateInfo->uiLevel != 0xFF) { - FLMBOOL bShouldBeRootBlk = - (pStateInfo->uiLevel == - pStateInfo->pLogicalFile->pLfStats->uiNumLevels - 1) - ? TRUE - : FALSE; + FLMBOOL bShouldBeRootBlk; + + bShouldBeRootBlk = (pStateInfo->uiLevel == + pStateInfo->pLogicalFile->pLfStats->uiNumLevels - 1) + ? TRUE + : FALSE; if (((bShouldBeRootBlk) && (!BH_IS_ROOT_BLK( pBlk))) || - ((!bShouldBeRootBlk) && (BH_IS_ROOT_BLK( pBlk)))) + ((!bShouldBeRootBlk) && (BH_IS_ROOT_BLK( pBlk)))) { - return( FLM_BAD_BLK_HDR_ROOT_BIT); + return (FLM_BAD_BLK_HDR_ROOT_BIT); } } - /* Verify the logical file number - if any. */ + // Verify the logical file number - if any. - if( pStateInfo->pLogicalFile->pLFile->uiLfNum != - (FLMUINT)FB2UW( &pBlk[ BH_LOG_FILE_NUM])) + if (pStateInfo->pLogicalFile->pLFile->uiLfNum != + (FLMUINT) FB2UW( &pBlk[BH_LOG_FILE_NUM])) { - return( FLM_BAD_BLK_HDR_LF_NUM); + return (FLM_BAD_BLK_HDR_LF_NUM); } } - return( FLM_NO_CORRUPTION); + + return (FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: ? -*********************************************************************/ +/**************************************************************************** +Desc: +****************************************************************************/ FLMINT flmCompareKeys( FLMBYTE * pBuf1, FLMUINT uiBuf1Len, FLMBYTE * pBuf2, - FLMUINT uiBuf2Len - ) + FLMUINT uiBuf2Len) { - FLMINT iStatus; + FLMINT iStatus; if (!uiBuf1Len) { @@ -1527,45 +1769,48 @@ FLMINT flmCompareKeys( else if (uiBuf1Len < uiBuf2Len) { if ((iStatus = f_memcmp( pBuf1, pBuf2, uiBuf1Len)) == 0) + { iStatus = -1; + } } else if (uiBuf1Len > uiBuf2Len) { if ((iStatus = f_memcmp( pBuf1, pBuf2, uiBuf2Len)) == 0) + { iStatus = 1; + } } else { iStatus = f_memcmp( pBuf1, pBuf2, uiBuf1Len); } - return( iStatus); + return (iStatus); } - -/******************************************************************** -Desc: Verify a index or data element in a b-tree and set pStateInfo. -*********************************************************************/ +/**************************************************************************** +Desc: Verify a index or data element in a b-tree and set pStateInfo. +****************************************************************************/ eCorruptionType flmVerifyElement( STATE_INFO * pStateInfo, FLMUINT uiFlags) { - FLMUINT uiEndOfBlock = pStateInfo->uiEndOfBlock; - FLMUINT uiOffset = pStateInfo->uiElmOffset; - FLMUINT uiBlkType = pStateInfo->uiBlkType; - FLMBYTE * pElm; - FLMUINT uiElmLen; - FLMBYTE * pElmKey; - FLMUINT uiElmKeyLen; - FLMUINT uiElmPKCLen; - FLMINT iCmpStatus = 0; - FLMBYTE * pCurKey = pStateInfo->pCurKey; - FLMUINT uiCurKeyLen = pStateInfo->uiCurKeyLen; - FLMBOOL bLfIsContainer = FALSE; - FLMBOOL bLfIsIndex = FALSE; - FLMUINT uiLfType = LF_INVALID; - IXD * pIxd = NULL; - IFD * pIfd = NULL; + FLMUINT uiEndOfBlock = pStateInfo->uiEndOfBlock; + FLMUINT uiOffset = pStateInfo->uiElmOffset; + FLMUINT uiBlkType = pStateInfo->uiBlkType; + FLMBYTE * pElm; + FLMUINT uiElmLen; + FLMBYTE * pElmKey; + FLMUINT uiElmKeyLen; + FLMUINT uiElmPKCLen; + FLMINT iCmpStatus = 0; + FLMBYTE * pCurKey = pStateInfo->pCurKey; + FLMUINT uiCurKeyLen = pStateInfo->uiCurKeyLen; + FLMBOOL bLfIsContainer = FALSE; + FLMBOOL bLfIsIndex = FALSE; + FLMUINT uiLfType = LF_INVALID; + IXD * pIxd = NULL; + IFD * pIfd = NULL; if (pStateInfo->pLogicalFile) { @@ -1576,79 +1821,94 @@ eCorruptionType flmVerifyElement( pIfd = pStateInfo->pLogicalFile->pIfd; } - /* Get a pointer to the element to work with. */ + // Get a pointer to the element to work with. - pElm = pStateInfo->pElm = &pStateInfo->pBlk [uiOffset]; + pElm = pStateInfo->pElm = &pStateInfo->pBlk[uiOffset]; - /* Get the element length. */ + // Get the element length. if (uiBlkType == BHT_LEAF) { if (uiOffset + BBE_KEY > uiEndOfBlock) - return( FLM_BAD_ELM_LEN); - uiElmLen = pStateInfo->uiElmLen = (FLMUINT)(BBE_LEN( pElm)); - pElmKey = pStateInfo->pElmKey = &pElm [BBE_KEY]; + { + return (FLM_BAD_ELM_LEN); + } + + uiElmLen = pStateInfo->uiElmLen = (FLMUINT) (BBE_LEN( pElm)); + pElmKey = pStateInfo->pElmKey = &pElm[BBE_KEY]; pStateInfo->pElmRec = BBE_REC_PTR( pElm); pStateInfo->uiElmRecLen = BBE_GET_RL( pElm); pStateInfo->uiElmRecOffset = 0; - /* Get the element key length and previous key count (PKC). */ + // Get the element key length and previous key count (PKC). - uiElmKeyLen = pStateInfo->uiElmKeyLen = (FLMUINT)(BBE_GET_KL( pElm)); - uiElmPKCLen = pStateInfo->uiElmPKCLen = (FLMUINT)(BBE_GET_PKC( pElm)); + uiElmKeyLen = pStateInfo->uiElmKeyLen = (FLMUINT) (BBE_GET_KL( pElm)); + uiElmPKCLen = pStateInfo->uiElmPKCLen = (FLMUINT) (BBE_GET_PKC( pElm)); } else if (uiBlkType == BHT_NON_LEAF_DATA) { if (uiOffset + pStateInfo->uiElmOvhd > uiEndOfBlock) - return( FLM_BAD_ELM_LEN); + { + return (FLM_BAD_ELM_LEN); + } + uiElmLen = pStateInfo->uiElmLen = BNE_DATA_OVHD; pElmKey = pStateInfo->pElmKey = pElm; uiElmKeyLen = 4; uiElmPKCLen = 0; - } - else // if( uiBlkType == BHT_NON_LEAF or BHT_NON_LEAF_COUNTS) + else { - if( uiBlkType == BHT_NON_LEAF_COUNTS) + if (uiBlkType == BHT_NON_LEAF_COUNTS) { pStateInfo->uiChildCount = FB2UD( pElm + BNE_CHILD_COUNT); } + if (uiOffset + pStateInfo->uiElmOvhd > uiEndOfBlock) - return( FLM_BAD_ELM_LEN); - uiElmLen = pStateInfo->uiElmLen = (FLMUINT) BBE_GET_KL(pElm) + - pStateInfo->uiElmOvhd + - (BNE_IS_DOMAIN(pElm) ? BNE_DOMAIN_LEN : 0); - pElmKey = pStateInfo->pElmKey = &pElm [pStateInfo->uiElmOvhd]; + { + return (FLM_BAD_ELM_LEN); + } - /* Get the element key length and previous key count (PKC). */ + uiElmLen = pStateInfo->uiElmLen = (FLMUINT) BBE_GET_KL( pElm) + + pStateInfo->uiElmOvhd + + (BNE_IS_DOMAIN( pElm) ? BNE_DOMAIN_LEN : 0); + pElmKey = pStateInfo->pElmKey = &pElm[pStateInfo->uiElmOvhd]; - uiElmKeyLen = pStateInfo->uiElmKeyLen = (FLMUINT)(BBE_GET_KL( pElm)); - uiElmPKCLen = pStateInfo->uiElmPKCLen = (FLMUINT)(BBE_GET_PKC( pElm)); + // Get the element key length and previous key count (PKC). + + uiElmKeyLen = pStateInfo->uiElmKeyLen = (FLMUINT) (BBE_GET_KL( pElm)); + uiElmPKCLen = pStateInfo->uiElmPKCLen = (FLMUINT) (BBE_GET_PKC( pElm)); } - - /* Make sure the element length is within the block boundary. */ + // Make sure the element length is within the block boundary. if (uiOffset + uiElmLen > uiEndOfBlock) - return( FLM_BAD_ELM_LEN); + { + return (FLM_BAD_ELM_LEN); + } - /* Get the record number from the element, if any. */ + // Get the record number from the element, if any. pStateInfo->uiElmDrn = 0; if ((bLfIsContainer) && (uiElmKeyLen + uiElmPKCLen == 4)) { - FLMBYTE ucRecBuff [4]; + FLMBYTE ucRecBuff[4]; if (uiElmPKCLen) { if ((uiCurKeyLen >= uiElmPKCLen) && (pStateInfo->bValidKey)) + { f_memcpy( ucRecBuff, pCurKey, uiElmPKCLen); + } else + { f_memset( ucRecBuff, 0, uiElmPKCLen); + } } + if (uiElmKeyLen) { - f_memcpy( &ucRecBuff [uiElmPKCLen], pElmKey, uiElmKeyLen); + f_memcpy( &ucRecBuff[uiElmPKCLen], pElmKey, uiElmKeyLen); } pStateInfo->uiElmDrn = flmBigEndianToUINT32( ucRecBuff); @@ -1656,40 +1916,47 @@ eCorruptionType flmVerifyElement( { FLMUINT uiTempDrn; - /* Verify that the marker value is > the last DRN value. */ + // Verify that the marker value is > the last DRN value. - uiTempDrn = (FLMUINT)FB2UD( &pElmKey [uiElmKeyLen]); + uiTempDrn = (FLMUINT) FB2UD( &pElmKey[uiElmKeyLen]); if (uiTempDrn <= pStateInfo->uiLastElmDrn) - return( FLM_BAD_LAST_DRN ); + { + return (FLM_BAD_LAST_DRN); + } + pStateInfo->uiLastElmDrn = uiTempDrn; } else - pStateInfo->uiLastElmDrn = pStateInfo->uiElmDrn; - } - - /* Verify the first/last flags if it is a leaf element. */ - - if (uiBlkType == BHT_LEAF) - { - FLMUINT uiFirstFlag = (FLMUINT)(BBE_IS_FIRST( pElm)); - FLMUINT uiPrevLastFlag = pStateInfo->uiElmLastFlag; - - /* Verify the first element flag */ - - pStateInfo->uiElmLastFlag = (FLMUINT)(BBE_IS_LAST( pElm)); - if (uiPrevLastFlag != 0xFF) { - if ((uiPrevLastFlag) && (!uiFirstFlag)) - return( FLM_BAD_FIRST_ELM_FLAG); - else if ((!uiPrevLastFlag) && (uiFirstFlag)) - return( FLM_BAD_LAST_ELM_FLAG); + pStateInfo->uiLastElmDrn = pStateInfo->uiElmDrn; } } - /* - If we are on the last element, verify that we are indeed. - If we are, set the key length to zero. - */ + // Verify the first/last flags if it is a leaf element. + + if (uiBlkType == BHT_LEAF) + { + FLMUINT uiFirstFlag = (FLMUINT) (BBE_IS_FIRST( pElm)); + FLMUINT uiPrevLastFlag = pStateInfo->uiElmLastFlag; + + // Verify the first element flag + + pStateInfo->uiElmLastFlag = (FLMUINT) (BBE_IS_LAST( pElm)); + if (uiPrevLastFlag != 0xFF) + { + if ((uiPrevLastFlag) && (!uiFirstFlag)) + { + return (FLM_BAD_FIRST_ELM_FLAG); + } + else if ((!uiPrevLastFlag) && (uiFirstFlag)) + { + return (FLM_BAD_LAST_ELM_FLAG); + } + } + } + + // If we are on the last element, verify that we are indeed. If we are, + // set the key length to zero. if ((uiElmLen == pStateInfo->uiElmOvhd) && (uiElmLen + uiOffset == uiEndOfBlock) && @@ -1699,64 +1966,56 @@ eCorruptionType flmVerifyElement( pStateInfo->uiCurKeyLen = uiCurKeyLen = 0; } - /* - If the length in a leaf element is BBE_LEM_LEN and - it is not the last element, we have an error. - */ + // If the length in a leaf element is BBE_LEM_LEN and it is not the + // last element, we have an error. else if ((uiBlkType == BHT_LEAF) && (uiElmLen == BBE_LEM_LEN)) - return( FLM_BAD_LEM); + { + return (FLM_BAD_LEM); + } - /* - If this is the last element in the block, and this is the - last block in the chain, this had better be the LEM. - */ + // If this is the last element in the block, and this is the last block + // in the chain, this had better be the LEM. else if ((uiOffset + uiElmLen == uiEndOfBlock) && (pStateInfo->uiNextBlkAddr == BT_END)) - return( FLM_BAD_LEM); - - /* - Verify that the key is OK. The key must pass three tests - in order for it to be OK. First, the total key length must - not exceed the maximum key size. Second, if there is a - previous key count, it must not exceed the size of the previous - key. Third, the new key must be greater than or equal to the - previous key -- all keys in the block must be in ascending order. - - The third part is tested by comparing only the part of the key - which is going to change - the part pointed to by pElmKey. - We already know that the part of the key represented in the - previous key count is equal - by definition, so there is no - need to test it. - */ - - else if ((uiElmKeyLen + uiElmPKCLen > MAX_KEY_SIZ) || - ((bLfIsContainer) && (uiElmKeyLen + uiElmPKCLen != 4) - && (uiBlkType != BHT_NON_LEAF_DATA))) { - pStateInfo->bValidKey = FALSE; - return( FLM_BAD_ELM_KEY_SIZE); + return (FLM_BAD_LEM); } - else if (((uiOffset == BH_OVHD) && (uiElmPKCLen)) || - ((uiElmPKCLen > uiCurKeyLen) && - (uiCurKeyLen) && - (pStateInfo->bValidKey))) + + // Verify that the key is OK. The key must pass three tests in order + // for it to be OK. First, the total key length must not exceed the + // maximum key size. Second, if there is a previous key count, it must + // not exceed the size of the previous key. Third, the new key must be + // greater than or equal to the previous key -- all keys in the block + // must be in ascending order. The third part is tested by comparing + // only the part of the key which is going to change - the part pointed + // to by pElmKey. We already know that the part of the key represented + // in the previous key count is equal - by definition, so there is no + // need to test it. + + else if ((uiElmKeyLen + uiElmPKCLen > MAX_KEY_SIZ) || + (bLfIsContainer && (uiElmKeyLen + uiElmPKCLen != 4) && + (uiBlkType != BHT_NON_LEAF_DATA))) { pStateInfo->bValidKey = FALSE; - return( FLM_BAD_ELM_PKC_LEN); + return (FLM_BAD_ELM_KEY_SIZE); + } + else if ((uiOffset == BH_OVHD && uiElmPKCLen) || + (uiElmPKCLen > uiCurKeyLen && uiCurKeyLen && pStateInfo->bValidKey)) + { + pStateInfo->bValidKey = FALSE; + return (FLM_BAD_ELM_PKC_LEN); } else { eCorruptionType eKeyCorruptionCode = FLM_NO_CORRUPTION; - /* - NOTE: The reason we are saving the error code into eKeyCorruptionCode - instead of returning when we detect it is because we want - to save the new key into pStateInfo->pCurKey before we - return. However, there are some checks which we must - make before saving the new key. - */ + // NOTE: The reason we are saving the error code into + // eKeyCorruptionCode instead of returning when we detect it is + // because we want to save the new key into pStateInfo->pCurKey + // before we return. However, there are some checks which we must + // make before saving the new key. if ((pStateInfo->bValidKey) || (uiElmPKCLen == 0)) { @@ -1764,33 +2023,36 @@ eCorruptionType flmVerifyElement( { if (uiBlkType == BHT_NON_LEAF_DATA) { - iCmpStatus = flmCompareKeys( pElmKey, uiElmKeyLen, - pCurKey, DIN_KEY_SIZ); + iCmpStatus = flmCompareKeys( pElmKey, uiElmKeyLen, pCurKey, + DIN_KEY_SIZ); } else { iCmpStatus = flmCompareKeys( pElmKey, uiElmKeyLen, - &pCurKey [uiElmPKCLen], - uiCurKeyLen - uiElmPKCLen); + &pCurKey[uiElmPKCLen], + uiCurKeyLen - uiElmPKCLen); } - if (iCmpStatus < 0) - eKeyCorruptionCode = FLM_BAD_ELM_KEY_ORDER; - /* Check the key compression to see if it is good. */ + if (iCmpStatus < 0) + { + eKeyCorruptionCode = FLM_BAD_ELM_KEY_ORDER; + } + + // Check the key compression to see if it is good. else if ((uiBlkType != BHT_NON_LEAF_DATA) && (uiOffset > BH_OVHD) && (uiElmKeyLen > 0) && (uiElmPKCLen < BBE_PKC_MAX) && (uiElmPKCLen < uiCurKeyLen) && - (pElmKey [0] == pCurKey [uiElmPKCLen])) + (pElmKey[0] == pCurKey[uiElmPKCLen])) + { eKeyCorruptionCode = FLM_BAD_ELM_KEY_COMPRESS; + } } - /* - The keys had better be equal if it is a continuation element. - Otherwise, they had better be different. - */ + // The keys had better be equal if it is a continuation element. + // Otherwise, they had better be different. if (!pStateInfo->bValidKey) { @@ -1802,42 +2064,46 @@ eCorruptionType flmVerifyElement( pStateInfo->ui64KeyCount++; pStateInfo->ui64KeyRefs = 0; - /* - If this is a continuation element in a leaf block, the key - should be the same as the last key. - */ + // If this is a continuation element in a leaf block, the key + // should be the same as the last key. if ((uiBlkType == BHT_LEAF) && (!BBE_IS_FIRST( pElm))) + { eKeyCorruptionCode = FLM_BAD_CONT_ELM_KEY; + } } else { if (pIxd) { if (((uiBlkType == BHT_LEAF) && (BBE_IS_FIRST( pElm))) || - ((uiBlkType != BHT_LEAF) && - (pIxd->uiFlags & IXD_UNIQUE))) + ((uiBlkType != BHT_LEAF) && (pIxd->uiFlags & IXD_UNIQUE))) + { eKeyCorruptionCode = FLM_NON_UNIQUE_FIRST_ELM_KEY; + } } } - /* Save the new key. */ + // Save the new key. - if( uiBlkType != BHT_NON_LEAF_DATA) + if (uiBlkType != BHT_NON_LEAF_DATA) { pStateInfo->uiCurKeyLen = uiCurKeyLen = uiElmPKCLen + uiElmKeyLen; - f_memcpy( &pCurKey [uiElmPKCLen], pElmKey, uiElmKeyLen); + f_memcpy( &pCurKey[uiElmPKCLen], pElmKey, uiElmKeyLen); } else { pStateInfo->uiCurKeyLen = uiCurKeyLen = DIN_KEY_SIZ; - *(FLMUINT32 *) pCurKey = *(FLMUINT32 *) pElmKey; + *(FLMUINT32*) pCurKey = *(FLMUINT32*) pElmKey; } + pStateInfo->bValidKey = TRUE; - /* Perform some additional checks on the key if an index key. */ + // Perform some additional checks on the key if an index key. - if (eKeyCorruptionCode == FLM_NO_CORRUPTION && bLfIsIndex && pIxd && + if (eKeyCorruptionCode == FLM_NO_CORRUPTION && + bLfIsIndex && + pIxd && (uiFlags & FLM_CHK_FIELDS)) { if (!pIxd->uiContainerNum) @@ -1854,37 +2120,41 @@ eCorruptionType flmVerifyElement( if (pStateInfo->pDb) { - if (RC_BAD( tmpRc = fdictGetContainer( - pStateInfo->pDb->pDict, - getContainerFromKey( pCurKey, uiCurKeyLen), - &pTmpLFile))) + if (RC_BAD( tmpRc = fdictGetContainer( pStateInfo->pDb->pDict, + getContainerFromKey( pCurKey, uiCurKeyLen), + &pTmpLFile))) { eKeyCorruptionCode = FLM_BAD_CONTAINER_IN_KEY; goto Bad_Key; } } + uiCurKeyLen -= uiContainerPartLen; } + eKeyCorruptionCode = flmVerifyKey( pCurKey, uiCurKeyLen, - pIxd->uiLanguage, pIfd, pIxd->uiNumFlds); + pIxd->uiLanguage, pIfd, + pIxd->uiNumFlds); } } + if (eKeyCorruptionCode != FLM_NO_CORRUPTION) { Bad_Key: + pStateInfo->bValidKey = FALSE; - return( eKeyCorruptionCode); + return (eKeyCorruptionCode); } } - return( FLM_NO_CORRUPTION); + + return (FLM_NO_CORRUPTION); } - -/******************************************************************** -Desc: ? -*********************************************************************/ +/**************************************************************************** +Desc: +****************************************************************************/ eCorruptionType flmVerifyElmFOP( - STATE_INFO * pStateInfo) + STATE_INFO * pStateInfo) { eCorruptionType eCorruptionCode = FLM_NO_CORRUPTION; FLMBYTE * pElmRec = pStateInfo->pElmRec; @@ -1897,13 +2167,13 @@ eCorruptionType flmVerifyElmFOP( FLMBYTE * pElm = pStateInfo->pElm; FLMUINT uiFOPDataLen; FLMUINT uiFldOverhead; - FLMUINT uiFldFlags; + FLMUINT uiBaseFldFlags; FLMUINT uiLfNumber; FLMUINT uiMaxDictFieldNum = FLM_LAST_DICT_FIELD_NUM; - uiLfNumber = (pStateInfo->pLogicalFile) - ? pStateInfo->pLogicalFile->pLFile->uiLfNum - : (FLMUINT)0; + uiLfNumber = (pStateInfo->pLogicalFile) + ? pStateInfo->pLogicalFile->pLFile->uiLfNum + : (FLMUINT) 0; if ((BBE_IS_FIRST( pElm)) && (uiElmRecOffset == 0)) { @@ -1925,13 +2195,12 @@ eCorruptionType flmVerifyElmFOP( { pStateInfo->pRecord->clear(); } + pStateInfo->bElmRecOK = TRUE; } - /* - If the state is goofed up, just give back the reset of the element. - Don't try to parse it. - */ + // If the state is goofed up, just give back the reset of the element. + // Don't try to parse it. if (!pStateInfo->bElmRecOK) { @@ -1940,18 +2209,16 @@ eCorruptionType flmVerifyElmFOP( pStateInfo->uiFieldProcessedLen = 0; } - /* - If we are at the first of an element's record and we have a - half processed field, return that first. - */ + // If we are at the first of an element's record and we have a half + // processed field, return that first. - else if ((uiElmRecOffset == 0) && - (pStateInfo->uiFieldProcessedLen < (pStateInfo->uiEncId - ? pStateInfo->uiEncFieldLen - : pStateInfo->uiFieldLen))) + else if (uiElmRecOffset == 0 && + (pStateInfo->uiFieldProcessedLen < (pStateInfo->uiEncId + ? pStateInfo->uiEncFieldLen + : pStateInfo->uiFieldLen))) { - /* If this is a FIRST element, we have a problem. */ + // If this is a FIRST element, we have a problem. if (BBE_IS_FIRST( pElm)) { @@ -1960,7 +2227,9 @@ eCorruptionType flmVerifyElmFOP( goto Exit; } else + { pStateInfo->uiFOPType = FLM_FOP_CONT_DATA; + } } else if (pStateInfo->uiElmDrn == DRN_LAST_MARKER) { @@ -1980,9 +2249,9 @@ eCorruptionType flmVerifyElmFOP( pStateInfo->uiFieldLen = 0; pStateInfo->uiEncId = 0; pStateInfo->uiEncFieldLen = 0; - pField = &pElmRec [uiElmRecOffset]; + pField = &pElmRec[uiElmRecOffset]; - /* Test for STANDARD field -- must be defined in dictionary. */ + // Test for STANDARD field -- must be defined in dictionary. if (FOP_IS_STANDARD( pField)) { @@ -1995,10 +2264,11 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldLen = (FLMUINT)(FSTA_FLD_LEN( pField)); + + pStateInfo->uiFieldLen = (FLMUINT) (FSTA_FLD_LEN( pField)); pStateInfo->uiFieldNum = FSTA_FLD_NUM( pField); - /* See if field is a child or sibling of previous field. */ + // See if field is a child or sibling of previous field. if (FSTA_LEVEL( pField)) { @@ -2006,51 +2276,41 @@ eCorruptionType flmVerifyElmFOP( } } - /* Test for OPEN type -- must also be defined in dictionary. */ + // Test for OPEN type -- must also be defined in dictionary. else if (FOP_IS_OPEN( pField)) { pStateInfo->uiFOPType = FLM_FOP_OPEN; bDictField = TRUE; - /* See if the field is a child or sibling of the previous field. */ + // See if the field is a child or sibling of the previous field. if (FOPE_LEVEL( pField)) - pStateInfo->uiFieldLevel++; - - /* See if field number is one or two bytes. */ - - pTmpFld = pField + 1; - uiFldFlags = (FLMUINT)(FOP_GET_FLD_FLAGS( pField)); - - if (FOP_2BYTE_FLDNUM( uiFldFlags)) { - uiFldOverhead = 3; + pStateInfo->uiFieldLevel++; + } + + // See if field number is one or two bytes. + + pTmpFld = pField; + uiFldOverhead = 0; + uiBaseFldFlags = (FLMUINT) (FOP_GET_FLD_FLAGS( pTmpFld)); + pTmpFld++; + + if (FOP_2BYTE_FLDNUM( uiBaseFldFlags)) + { + uiFldOverhead += 3; if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) { pStateInfo->bElmRecOK = FALSE; eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldNum = (FLMUINT)FB2UW( pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) FB2UW( pTmpFld); pTmpFld += 2; } else - { - uiFldOverhead = 2; - if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) - { - pStateInfo->bElmRecOK = FALSE; - eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; - goto Exit; - } - pStateInfo->uiFieldNum = (FLMUINT)(*pTmpFld); - pTmpFld++; - } - - /* See if the field length is one or two bytes. */ - - if (FOP_2BYTE_FLDLEN( uiFldFlags)) { uiFldOverhead += 2; if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) @@ -2059,7 +2319,24 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldLen = (FLMUINT)FB2UW( pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) (*pTmpFld); + pTmpFld++; + } + + // Determine the field length + + if (FOP_2BYTE_FLDLEN( uiBaseFldFlags)) + { + uiFldOverhead += 2; + if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) + { + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + + pStateInfo->uiFieldLen = (FLMUINT) FB2UW( pTmpFld); } else { @@ -2070,67 +2347,38 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldLen = (FLMUINT)(*pTmpFld); + + pStateInfo->uiFieldLen = (FLMUINT) (*pTmpFld); } } - /* Test for UNREGISTERED fields -- not in dictionary. */ + // Test for UNREGISTERED fields -- not in dictionary. else if (FOP_IS_TAGGED( pField)) { pStateInfo->uiFOPType = FLM_FOP_TAGGED; - /* See if the field is a child or sibling of the previous field. */ + // See if the field is a child or sibling of the previous field. if (FTAG_LEVEL( pField)) + { pStateInfo->uiFieldLevel++; - - /* Get the field type. */ - - pStateInfo->uiFieldType = (FLMUINT)FTAG_FLD_TYPE( pField); - - /* See if field number is one or two bytes. */ - - pTmpFld = pField + 2; - uiFldFlags = (FLMUINT)(FOP_GET_FLD_FLAGS( pField)); - if (FOP_2BYTE_FLDNUM( uiFldFlags)) - { - uiFldOverhead = 4; - if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) - { - pStateInfo->bElmRecOK = FALSE; - eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; - goto Exit; - } - pStateInfo->uiFieldNum = (FLMUINT)FB2UW( pTmpFld); - pTmpFld += 2; - } - else - { - uiFldOverhead = 3; - if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) - { - pStateInfo->bElmRecOK = FALSE; - eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; - goto Exit; - } - pStateInfo->uiFieldNum = (FLMUINT)(*pTmpFld); - pTmpFld++; } - /* - Toggle high bit to get true field number. FOP_TAGGED - is now used for more than just UNREGISTERED fields. - */ + pTmpFld = pField; + uiBaseFldFlags = (FLMUINT) (FOP_GET_FLD_FLAGS( pTmpFld)); + pTmpFld++; + uiFldOverhead = 1; - if (pStateInfo->uiFieldNum & 0x8000) - pStateInfo->uiFieldNum &= (FLMUINT) 0x7FFF; - else - pStateInfo->uiFieldNum |= (FLMUINT) 0x8000; + // Get the field type. - /* See if the field length is one or two bytes */ + pStateInfo->uiFieldType = (FLMUINT) FTAG_GET_FLD_TYPE( *pTmpFld); + pTmpFld++; + uiFldOverhead++; - if (FOP_2BYTE_FLDLEN( uiFldFlags)) + // See if field number is one or two bytes. + + if (FOP_2BYTE_FLDNUM( uiBaseFldFlags)) { uiFldOverhead += 2; if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) @@ -2139,7 +2387,9 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldLen = (FLMUINT)FB2UW( pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) FB2UW( pTmpFld); + pTmpFld += 2; } else { @@ -2150,11 +2400,52 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldLen = (FLMUINT)(*pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) (*pTmpFld); + pTmpFld++; + } + + // Toggle high bit to get true field number. FOP_TAGGED is now + // used for more than just UNREGISTERED fields. + + if (pStateInfo->uiFieldNum & 0x8000) + { + pStateInfo->uiFieldNum &= (FLMUINT) 0x7FFF; + } + else + { + pStateInfo->uiFieldNum |= (FLMUINT) 0x8000; + } + + // See if the field length is one or two bytes + + if (FOP_2BYTE_FLDLEN( uiBaseFldFlags)) + { + uiFldOverhead += 2; + if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) + { + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + + pStateInfo->uiFieldLen = (FLMUINT) FB2UW( pTmpFld); + } + else + { + uiFldOverhead++; + if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) + { + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + + pStateInfo->uiFieldLen = (FLMUINT) (*pTmpFld); } } - /* Test for a field with NO value -- must be in dictionary. */ + // Test for a field with NO value -- must be in dictionary else if (FOP_IS_NO_VALUE( pField)) { @@ -2162,16 +2453,18 @@ eCorruptionType flmVerifyElmFOP( bDictField = TRUE; pStateInfo->uiFieldLen = 0; - /* See if the field is a child or sibling of previous field. */ + // See if the field is a child or sibling of previous field if (FNOV_LEVEL( pField)) + { pStateInfo->uiFieldLevel++; + } - /* See if field number is one or two bytes. */ + // See if field number is one or two bytes pTmpFld = pField + 1; - uiFldFlags = (FLMUINT)(FOP_GET_FLD_FLAGS( pField)); - if (FOP_2BYTE_FLDNUM( uiFldFlags)) + uiBaseFldFlags = (FLMUINT) (FOP_GET_FLD_FLAGS( pField)); + if (FOP_2BYTE_FLDNUM( uiBaseFldFlags)) { uiFldOverhead = 3; if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) @@ -2180,7 +2473,8 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldNum = (FLMUINT)FB2UW( pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) FB2UW( pTmpFld); pTmpFld += 2; } else @@ -2192,12 +2486,13 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } - pStateInfo->uiFieldNum = (FLMUINT)(*pTmpFld); + + pStateInfo->uiFieldNum = (FLMUINT) (*pTmpFld); pTmpFld++; } } - /* Test for the code which just resets the field level. */ + // Test for the code which just resets the field level else if (FOP_IS_SET_LEVEL( pField)) { @@ -2211,21 +2506,24 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } + bFOPIsField = FALSE; pStateInfo->uiFieldNum = 0; pStateInfo->uiFieldLen = 0; pStateInfo->uiFieldType = 0xFF; - /* Jumping back better not cause us to go below level one. */ + // Jumping back better not cause us to go below level one - uiTempLevel = (FLMUINT)(FSLEV_GET( pField)); + uiTempLevel = (FLMUINT) (FSLEV_GET( pField)); pStateInfo->uiJumpLevel = uiTempLevel; + if (pStateInfo->uiFieldLevel <= uiTempLevel) { pStateInfo->bElmRecOK = FALSE; eCorruptionCode = FLM_BAD_ELM_FLD_LEVEL_JUMP; goto Exit; } + pStateInfo->uiFieldLevel -= uiTempLevel; } else if (FOP_IS_RECORD_INFO( pField)) @@ -2237,8 +2535,9 @@ eCorruptionType flmVerifyElmFOP( pStateInfo->uiFieldType = 0xFF; pTmpFld = pField + 1; - uiFldFlags = (FLMUINT)(FOP_GET_FLD_FLAGS( pField)); - if (FOP_2BYTE_FLDLEN( uiFldFlags)) + uiBaseFldFlags = (FLMUINT) (FOP_GET_FLD_FLAGS( pField)); + + if (FOP_2BYTE_FLDLEN( uiBaseFldFlags)) { uiFldOverhead += 2; if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) @@ -2247,8 +2546,9 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } + pStateInfo->uiFieldLen = *pTmpFld++; - pStateInfo->uiFieldLen += ((FLMUINT) *pTmpFld++) << 8; + pStateInfo->uiFieldLen += ((FLMUINT) * pTmpFld++) << 8; } else { @@ -2259,15 +2559,16 @@ eCorruptionType flmVerifyElmFOP( eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; goto Exit; } + pStateInfo->uiFieldLen = *pTmpFld++; } } else if (FOP_IS_ENCRYPTED( pField)) { - FLMBOOL bTagSz; - FLMBOOL bLenSz; - FLMBOOL bENumSz; - FLMBOOL bELenSz; + FLMBOOL bTagSz; + FLMBOOL bLenSz; + FLMBOOL bENumSz; + FLMBOOL bELenSz; pStateInfo->uiFOPType = FLM_FOP_ENCRYPTED; bFOPIsField = TRUE; @@ -2281,16 +2582,16 @@ eCorruptionType flmVerifyElmFOP( goto Exit; } - if( FENC_LEVEL( pField )) + if (FENC_LEVEL( pField)) { pStateInfo->uiFieldLevel++; } - pStateInfo->uiFieldType = (FLMUINT)(FENC_FLD_TYPE( pField )); + pStateInfo->uiFieldType = (FLMUINT) (FENC_FLD_TYPE( pField)); bTagSz = FENC_TAG_SZ( pField); if (bTagSz) { - uiFldOverhead +=2; + uiFldOverhead += 2; } else { @@ -2300,7 +2601,7 @@ eCorruptionType flmVerifyElmFOP( bLenSz = FENC_LEN_SZ( pField); if (bLenSz) { - uiFldOverhead +=2; + uiFldOverhead += 2; } else { @@ -2310,7 +2611,7 @@ eCorruptionType flmVerifyElmFOP( bENumSz = FENC_ETAG_SZ( pField); if (bENumSz) { - uiFldOverhead +=2; + uiFldOverhead += 2; } else { @@ -2320,7 +2621,7 @@ eCorruptionType flmVerifyElmFOP( bELenSz = FENC_ELEN_SZ( pField); if (bELenSz) { - uiFldOverhead +=2; + uiFldOverhead += 2; } else { @@ -2336,35 +2637,84 @@ eCorruptionType flmVerifyElmFOP( pTmpFld = pField + 2; - pStateInfo->uiFieldNum = (FLMUINT) *pTmpFld++; - if ( bTagSz) + pStateInfo->uiFieldNum = (FLMUINT) * pTmpFld++; + if (bTagSz) { - pStateInfo->uiFieldNum += ((FLMUINT) *pTmpFld++) << 8; + pStateInfo->uiFieldNum += ((FLMUINT) * pTmpFld++) << 8; } - pStateInfo->uiFieldLen = (FLMUINT)*pTmpFld++; + pStateInfo->uiFieldLen = (FLMUINT) * pTmpFld++; if (bLenSz) { - pStateInfo->uiFieldLen += ((FLMUINT) *pTmpFld++) << 8; + pStateInfo->uiFieldLen += ((FLMUINT) * pTmpFld++) << 8; } - pStateInfo->uiEncId = (FLMUINT) *pTmpFld++; + pStateInfo->uiEncId = (FLMUINT) * pTmpFld++; if (bENumSz) { - pStateInfo->uiEncId += ((FLMUINT) *pTmpFld++) << 8; + pStateInfo->uiEncId += ((FLMUINT) * pTmpFld++) << 8; } - pStateInfo->uiEncFieldLen = (FLMUINT) *pTmpFld++; + pStateInfo->uiEncFieldLen = (FLMUINT) * pTmpFld++; if (bELenSz) { - pStateInfo->uiEncFieldLen += ((FLMUINT) *pTmpFld++) << 8; + pStateInfo->uiEncFieldLen += ((FLMUINT) * pTmpFld++) << 8; } } + else if (FOP_IS_LARGE( pField)) + { + if( pStateInfo->uiVersionNum < FLM_FILE_FORMAT_VER_4_61) + { + pStateInfo->uiFOPType = FLM_FOP_BAD; + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + + pStateInfo->uiFOPType = FLM_FOP_LARGE; + bFOPIsField = TRUE; - /* Anything else is a code we don't understand. */ + uiFldOverhead = 2; + if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) + { + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + + if (FLARGE_LEVEL( pField)) + { + pStateInfo->uiFieldLevel++; + } + + pStateInfo->uiFieldType = FLARGE_FLD_TYPE( pField); + + pStateInfo->uiFieldNum = FLARGE_TAG_NUM( pField); + uiFldOverhead += 2; + + pStateInfo->uiFieldLen = FLARGE_DATA_LEN( pField); + uiFldOverhead += 4; + + if (FLARGE_ENCRYPTED( pField)) + { + pStateInfo->uiEncId = FLARGE_ETAG_NUM( pField); + uiFldOverhead += 2; + + pStateInfo->uiEncFieldLen = FLARGE_EDATA_LEN( pField); + uiFldOverhead += 4; + } + + if (uiElmRecOffset + uiFldOverhead > uiElmRecLen) + { + pStateInfo->bElmRecOK = FALSE; + eCorruptionCode = FLM_BAD_ELM_FLD_OVERHEAD; + goto Exit; + } + } else { + // Anything else is a code we don't understand pStateInfo->uiFOPType = FLM_FOP_BAD; @@ -2375,7 +2725,7 @@ eCorruptionType flmVerifyElmFOP( // If it is a field, get its type and make further checks - if( bFOPIsField) + if (bFOPIsField) { FLMUINT uiFldNum = pStateInfo->uiFieldNum; @@ -2384,13 +2734,14 @@ eCorruptionType flmVerifyElmFOP( pStateInfo->pLogicalFile->pLfStats->ui64FldRefCount++; } - // If it is a dictionary field, verify that it is indeed - // and get the field type from the dictionary. + // If it is a dictionary field, verify that it is indeed and get + // the field type from the dictionary. - if( bDictField) + if (bDictField) { + // If the field number is a reserved dictionary tag, it must - // be a TEXT field. These are always stored in the FOP_OPEN + // be a TEXT field. These are always stored in the FOP_OPEN // format - hence, the bDictField flag will be TRUE. if ((uiFldNum >= FLM_DICT_FIELD_NUMS) && @@ -2399,8 +2750,8 @@ eCorruptionType flmVerifyElmFOP( pStateInfo->uiFieldType = FLM_TEXT_TYPE; } - // If we have no dictionary, set the field type to binary - // so that the field will pass every test. + // If we have no dictionary, set the field type to binary so + // that the field will pass every test. else if (!pStateInfo->pDb) { @@ -2408,20 +2759,21 @@ eCorruptionType flmVerifyElmFOP( } else { - // If we can't find the field in the dictionary we have - // a corruption. - if( RC_BAD( fdictGetField( pStateInfo->pDb->pDict, uiFldNum, - &pStateInfo->uiFieldType, NULL, NULL))) + // If we can't find the field in the dictionary we have a + // corruption. + + if (RC_BAD( fdictGetField( pStateInfo->pDb->pDict, uiFldNum, + &pStateInfo->uiFieldType, NULL, NULL))) { pStateInfo->bElmRecOK = FALSE; pStateInfo->uiFieldType = FLM_BINARY_TYPE; eCorruptionCode = FLM_BAD_ELM_FLD_NUM; - // Keep processing and fill out the rest of the state information. - // Even though we have a bad field number here, the caller may - // want to simply skip the field instead of aborting the entire - // element. + // Keep processing and fill out the rest of the state + // information. Even though we have a bad field number + // here, the caller may want to simply skip the field + // instead of aborting the entire element. goto Keep_Processing_Field; } @@ -2436,22 +2788,31 @@ eCorruptionType flmVerifyElmFOP( case FLM_NUMBER_TYPE: case FLM_BINARY_TYPE: case FLM_BLOB_TYPE: + { break; + } + case FLM_CONTEXT_TYPE: - if ((pStateInfo->uiFieldLen != 0) && - (pStateInfo->uiFieldLen != 4)) + { + if (pStateInfo->uiFieldLen != 0 && pStateInfo->uiFieldLen != 4) { pStateInfo->bElmRecOK = FALSE; eCorruptionCode = FLM_BAD_ELM_FLD_LEN; goto Exit; } + break; + } + default: + { pStateInfo->bElmRecOK = FALSE; eCorruptionCode = FLM_BAD_ELM_FLD_TYPE; goto Exit; + } } } + Keep_Processing_Field: // At this point, it is possible for us to have a bad field number @@ -2466,14 +2827,13 @@ Keep_Processing_Field: if (pStateInfo->uiEncId) { - uiFOPDataLen = pStateInfo->uiEncFieldLen - - pStateInfo->uiFieldProcessedLen; + uiFOPDataLen = pStateInfo->uiEncFieldLen - pStateInfo->uiFieldProcessedLen; } else { - uiFOPDataLen = - pStateInfo->uiFieldLen - pStateInfo->uiFieldProcessedLen; + uiFOPDataLen = pStateInfo->uiFieldLen - pStateInfo->uiFieldProcessedLen; } + if (uiFOPDataLen > uiElmRecLen - uiElmRecOffset) { uiFOPDataLen = uiElmRecLen - uiElmRecOffset; @@ -2486,85 +2846,18 @@ Keep_Processing_Field: pStateInfo->uiFieldProcessedLen += uiFOPDataLen; pStateInfo->uiFOPDataLen = uiFOPDataLen; - pStateInfo->pFOPData = &pElmRec [uiElmRecOffset]; + pStateInfo->pFOPData = &pElmRec[uiElmRecOffset]; uiElmRecOffset += uiFOPDataLen; pStateInfo->uiElmRecOffset = uiElmRecOffset; Exit: - return( eCorruptionCode); + return (eCorruptionCode); } - -/******************************************************************** -Desc: ? -*********************************************************************/ -FSTATIC FLMBOOL flmGetSEN( - FLMBYTE * pTmpElmRec, - FLMUINT * puiDrnRV, - FLMUINT * puiNumBytesRV - ) -{ - FLMUINT uiNumBytes; - FLMUINT uiDrn; - FLMUINT uiChar = (FLMUINT)*pTmpElmRec; - FLMUINT uiTempDrn; - - pTmpElmRec++; - if (!(uiChar & 0x80)) - { - uiNumBytes = 0; - uiDrn = (FLMUINT)uiChar; - } - else if ((uiChar & 0xC0) == 0x80) - { - uiNumBytes = 1; - uiDrn = (FLMUINT)(uiChar & 0x3F); - } - else if ((uiChar & 0xF0) == 0xC0) - { - uiNumBytes = 2; - uiDrn = (FLMUINT)(uiChar & 0x0F); - } - else if ((uiChar & 0xF0) == 0xD0) - { - uiNumBytes = 3; - uiDrn = (FLMUINT)(uiChar & 0x0F); - } - else if ((uiChar & 0xF0) == 0xE0) - { - uiNumBytes = 4; - uiDrn = (FLMUINT)(uiChar & 0x0F); - } - else - { - return( FALSE); - } - - *puiNumBytesRV = uiNumBytes + 1; - - while (uiNumBytes) - { - // Check for overflow - - uiTempDrn = (FLMUINT)(*pTmpElmRec); - if (0xFFFFFFFF - uiDrn < (FLMUINT)256 + uiTempDrn) - { - return( FALSE); - } - uiDrn <<= 8; - uiDrn += uiTempDrn; - pTmpElmRec++; - uiNumBytes--; - } - - *puiDrnRV = uiDrn; - return( TRUE); -} - -/******************************************************************** -Desc: ? -*********************************************************************/ +/**************************************************************************** +Desc: +****************************************************************************/ RCODE flmVerifyIXRefs( STATE_INFO * pStateInfo, IX_CHK_INFO * pIxChkInfo, @@ -2595,57 +2888,60 @@ RCODE flmVerifyIXRefs( // Determine the element domain uiLowestDrn = 0; - if( *pElmRec == 0xFC) + if (*pElmRec == 0xFC) { uiElmRecOffset++; - if (!flmGetSEN( &pElmRec [uiElmRecOffset], &uiLowestDrn, &uiNumBytes)) + if (!flmGetSEN( &pElmRec[uiElmRecOffset], &uiLowestDrn, &uiNumBytes)) { pStateInfo->bElmRecOK = FALSE; *peElmCorruptionCode = FLM_BAD_ELM_DOMAIN_SEN; goto Exit; } + uiElmRecOffset += uiNumBytes; uiLowestDrn <<= 8; } // Get the base DRN for the element - if (!flmGetSEN( &pElmRec [uiElmRecOffset], &uiDrn, &uiNumBytes)) + if (!flmGetSEN( &pElmRec[uiElmRecOffset], &uiDrn, &uiNumBytes)) { pStateInfo->bElmRecOK = FALSE; *peElmCorruptionCode = FLM_BAD_ELM_BASE_SEN; goto Exit; } + uiElmRecOffset += uiNumBytes; - // If this is the first element or the state info has not yet - // been set, set the pStateInfo. + // If this is the first element or the state info has not yet been + // set, set the pStateInfo. - if( (BBE_IS_FIRST( pElm)) || (!pStateInfo->uiCurrIxRefDrn)) + if ((BBE_IS_FIRST( pElm)) || (!pStateInfo->uiCurrIxRefDrn)) { pStateInfo->uiCurrIxRefDrn = uiDrn; } - else if( uiDrn >= pStateInfo->uiCurrIxRefDrn) + else if (uiDrn >= pStateInfo->uiCurrIxRefDrn) { + // If the DRN's are not descending, we have a problem pStateInfo->bElmRecOK = FALSE; *peElmCorruptionCode = FLM_BAD_ELM_IX_REF; goto Exit; } + uiElmRefs++; - - if( uiDrn <= uiResetDrn) + + if (uiDrn <= uiResetDrn) { uiResetDrn = 0; } - if( pIxChkInfo != NULL && !uiResetDrn) + if (pIxChkInfo != NULL && !uiResetDrn) { pStateInfo->uiCurrIxRefDrn = uiDrn; - if(( RC_BAD( rc = chkVerifyIXRSet( pStateInfo, - pIxChkInfo, uiDrn))) || - (pIxChkInfo->pDbInfo->bReposition)) + if ((RC_BAD( rc = chkVerifyIXRSet( pStateInfo, pIxChkInfo, uiDrn))) || + (pIxChkInfo->pDbInfo->bReposition)) { goto Exit; } @@ -2653,21 +2949,21 @@ RCODE flmVerifyIXRefs( while (uiElmRecOffset < uiElmRecLen) { - pTmpElmRec = &pElmRec [uiElmRecOffset]; + pTmpElmRec = &pElmRec[uiElmRecOffset]; // See if we have a one run bOneRun = FALSE; - if( *pTmpElmRec >= 0xF0 && *pTmpElmRec <= 0xF7) + if (*pTmpElmRec >= 0xF0 && *pTmpElmRec <= 0xF7) { - uiTmpNum = (FLMUINT)((*pTmpElmRec & 0x0F) + 2); + uiTmpNum = (FLMUINT) ((*pTmpElmRec & 0x0F) + 2); uiElmRefs += uiTmpNum; uiNumBytes = 1; bOneRun = TRUE; } else if (*pTmpElmRec == 0xF8) { - if( !flmGetSEN( pTmpElmRec + 1, &uiTmpNum, &uiNumBytes)) + if (!flmGetSEN( pTmpElmRec + 1, &uiTmpNum, &uiNumBytes)) { pStateInfo->bElmRecOK = FALSE; *peElmCorruptionCode = FLM_BAD_ELM_ONE_RUN_SEN; @@ -2680,6 +2976,7 @@ RCODE flmVerifyIXRefs( } else { + // We have a delta if (!flmGetSEN( pTmpElmRec, &uiTmpNum, &uiNumBytes)) @@ -2688,6 +2985,7 @@ RCODE flmVerifyIXRefs( *peElmCorruptionCode = FLM_BAD_ELM_DELTA_SEN; goto Exit; } + uiElmRefs++; } @@ -2700,26 +2998,26 @@ RCODE flmVerifyIXRefs( goto Exit; } - if( bOneRun) + if (bOneRun) { - while( uiTmpNum > 0) + while (uiTmpNum > 0) { uiTmpNum--; uiDrn--; - if( uiDrn <= uiResetDrn) + if (uiDrn <= uiResetDrn) { uiResetDrn = 0; } pStateInfo->uiCurrIxRefDrn = uiDrn; - if( pIxChkInfo != NULL && !uiResetDrn) + if (pIxChkInfo != NULL && !uiResetDrn) { + // Verify that the key+ref is in the result set - if(( RC_BAD( rc = chkVerifyIXRSet( pStateInfo, - pIxChkInfo, uiDrn))) || - (pIxChkInfo->pDbInfo->bReposition)) + if ((RC_BAD( rc = chkVerifyIXRSet( pStateInfo, pIxChkInfo, + uiDrn))) || pIxChkInfo->pDbInfo->bReposition) { goto Exit; } @@ -2730,19 +3028,19 @@ RCODE flmVerifyIXRefs( { uiDrn -= uiTmpNum; - if( uiDrn <= uiResetDrn) + if (uiDrn <= uiResetDrn) { uiResetDrn = 0; } pStateInfo->uiCurrIxRefDrn = uiDrn; - if( pIxChkInfo != NULL && !uiResetDrn) + if (pIxChkInfo != NULL && !uiResetDrn) { + // Verify that the key+ref is in the result set - if(( RC_BAD( rc = chkVerifyIXRSet( pStateInfo, - pIxChkInfo, uiDrn))) || - (pIxChkInfo->pDbInfo->bReposition)) + if ((RC_BAD( rc = chkVerifyIXRSet( pStateInfo, pIxChkInfo, + uiDrn))) || pIxChkInfo->pDbInfo->bReposition) { goto Exit; } @@ -2770,62 +3068,132 @@ RCODE flmVerifyIXRefs( *peElmCorruptionCode = FLM_BAD_ELM_DOMAIN; goto Exit; } + pStateInfo->uiCurrIxRefDrn = uiDrn; pStateInfo->uiElmRecOffset = uiElmRecOffset; if (pStateInfo->pLogicalFile) { - pStateInfo->pLogicalFile->pLfStats->ui64FldRefCount += (FLMUINT64)uiElmRefs; + pStateInfo->pLogicalFile->pLfStats->ui64FldRefCount += (FLMUINT64) uiElmRefs; } - pStateInfo->ui64KeyRefs += (FLMUINT64)uiElmRefs; + pStateInfo->ui64KeyRefs += (FLMUINT64) uiElmRefs; // Check for a non-unique reference in a unique key if ((pStateInfo->pLogicalFile) && (pStateInfo->pLogicalFile->pIxd->uiFlags & IXD_UNIQUE) && - (pStateInfo->ui64KeyRefs > (FLMUINT64)1)) + (pStateInfo->ui64KeyRefs > (FLMUINT64) 1)) { pStateInfo->bElmRecOK = FALSE; - if( pIxChkInfo != NULL) + if (pIxChkInfo != NULL) { - // Give the application the option of deleting the - // record to resolve the corruption. - if( RC_BAD( rc = chkResolveNonUniqueKey( - pStateInfo, pIxChkInfo, pStateInfo->pLogicalFile->pLFile->uiLfNum, - pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, - pStateInfo->uiCurrIxRefDrn))) + // Give the application the option of deleting the record to + // resolve the corruption. + + if (RC_BAD( rc = chkResolveNonUniqueKey( pStateInfo, pIxChkInfo, + pStateInfo->pLogicalFile->pLFile->uiLfNum, + pStateInfo->pCurKey, pStateInfo->uiCurKeyLen, + pStateInfo->uiCurrIxRefDrn))) { - if( rc == FERR_OLD_VIEW) + if (rc == FERR_OLD_VIEW) { + // Set uiCurrIxRefDrn to zero so that the check will - // re-position to the first reference of the current - // key. + // re-position to the first reference of the current key. pStateInfo->uiCurrIxRefDrn = 0; } + goto Exit; } } + *peElmCorruptionCode = FLM_NON_UNIQUE_ELM_KEY_REF; } Exit: - return( rc); + return (rc); } +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBOOL flmGetSEN( + FLMBYTE * pTmpElmRec, + FLMUINT * puiDrnRV, + FLMUINT * puiNumBytesRV) +{ + FLMUINT uiNumBytes; + FLMUINT uiDrn; + FLMUINT uiChar = (FLMUINT) *pTmpElmRec; + FLMUINT uiTempDrn; -/******************************************************************** -Desc: ? -*********************************************************************/ + pTmpElmRec++; + if (!(uiChar & 0x80)) + { + uiNumBytes = 0; + uiDrn = (FLMUINT) uiChar; + } + else if ((uiChar & 0xC0) == 0x80) + { + uiNumBytes = 1; + uiDrn = (FLMUINT) (uiChar & 0x3F); + } + else if ((uiChar & 0xF0) == 0xC0) + { + uiNumBytes = 2; + uiDrn = (FLMUINT) (uiChar & 0x0F); + } + else if ((uiChar & 0xF0) == 0xD0) + { + uiNumBytes = 3; + uiDrn = (FLMUINT) (uiChar & 0x0F); + } + else if ((uiChar & 0xF0) == 0xE0) + { + uiNumBytes = 4; + uiDrn = (FLMUINT) (uiChar & 0x0F); + } + else + { + return (FALSE); + } + + *puiNumBytesRV = uiNumBytes + 1; + + while (uiNumBytes) + { + + // Check for overflow + + uiTempDrn = (FLMUINT) (*pTmpElmRec); + if (0xFFFFFFFF - uiDrn < (FLMUINT) 256 + uiTempDrn) + { + return (FALSE); + } + + uiDrn <<= 8; + uiDrn += uiTempDrn; + pTmpElmRec++; + uiNumBytes--; + } + + *puiDrnRV = uiDrn; + return (TRUE); +} + +/**************************************************************************** +Desc: +****************************************************************************/ void flmInitReadState( STATE_INFO * pStateInfo, FLMBOOL * pbStateInitialized, FLMUINT uiVersionNum, - FDB * pDb, // May be NULL. + FDB * pDb, // May be NULL. LF_HDR * pLogicalFile, FLMUINT uiLevel, FLMUINT uiBlkType, @@ -2837,7 +3205,7 @@ void flmInitReadState( pStateInfo->pRecord = NULL; } - f_memset( pStateInfo, 0, sizeof( STATE_INFO)); + f_memset( pStateInfo, 0, sizeof(STATE_INFO)); *pbStateInitialized = TRUE; pStateInfo->uiVersionNum = uiVersionNum; pStateInfo->pDb = pDb; @@ -2845,7 +3213,7 @@ void flmInitReadState( pStateInfo->uiLevel = uiLevel; // Special cases for leaf and non-leaf blocks - + if (uiBlkType == BHT_LEAF) { pStateInfo->uiElmOvhd = BBE_KEY; @@ -2885,6 +3253,7 @@ void flmInitReadState( { pStateInfo->uiElmOvhd = BNE_KEY_COUNTS_START; } + pStateInfo->uiBlkType = uiBlkType; pStateInfo->pCurKey = pKeyBuffer; pStateInfo->uiElmLastFlag = 0xFF; diff --git a/flaim/src/fmisc.cpp b/flaim/src/fmisc.cpp index 71dda09..3e35598 100644 --- a/flaim/src/fmisc.cpp +++ b/flaim/src/fmisc.cpp @@ -24,10 +24,101 @@ #include "flaimsys.h" -/*API~*********************************************************************** -Desc : Returns TRUE if the passed in RCODE indicates that a corruption - has occured in a FLAIM database file. -*END************************************************************************/ +/**************************************************************************** +Desc: FLAIM language code table +****************************************************************************/ +static char flmLangTable[ LAST_LANG + LAST_LANG] = +{ + 'U', 'S', // English, United States + 'A', 'F', // Afrikaans + 'A', 'R', // Arabic + 'C', 'A', // Catalan + 'H', 'R', // Croatian + 'C', 'Z', // Czech + 'D', 'K', // Danish + 'N', 'L', // Dutch + 'O', 'Z', // English, Australia + 'C', 'E', // English, Canada + 'U', 'K', // English, United Kingdom + 'F', 'A', // Farsi + 'S', 'U', // Finnish + 'C', 'F', // French, Canada + 'F', 'R', // French, France + 'G', 'A', // Galician + 'D', 'E', // German, Germany + 'S', 'D', // German, Switzerland + 'G', 'R', // Greek + 'H', 'E', // Hebrew + 'M', 'A', // Hungarian + 'I', 'S', // Icelandic + 'I', 'T', // Italian + 'N', 'O', // Norwegian + 'P', 'L', // Polish + 'B', 'R', // Portuguese, Brazil + 'P', 'O', // Portuguese, Portugal + 'R', 'U', // Russian + 'S', 'L', // Slovak + 'E', 'S', // Spanish + 'S', 'V', // Swedish + 'Y', 'K', // Ukrainian + 'U', 'R', // Urdu + 'T', 'K', // Turkey + 'J', 'P', // Japanese + 'K', 'R', // Korean + 'C', 'T', // Chinese-Traditional + 'C', 'S', // Chinese-Simplified + 'L', 'A' // Future asian language +}; + +/**************************************************************************** +Desc: Determine the language number from the 2 byte language code +****************************************************************************/ +FLMEXP FLMUINT FLMAPI FlmLanguage( + char * pszLanguageCode) +{ + char cFirstChar = *pszLanguageCode; + char cSecondChar = *(pszLanguageCode + 1); + FLMUINT uiTablePos; + + for (uiTablePos = 0; uiTablePos < (LAST_LANG+LAST_LANG); uiTablePos += 2 ) + { + if (flmLangTable[ uiTablePos] == cFirstChar && + flmLangTable[ uiTablePos + 1] == cSecondChar) + { + + // Return uiTablePos div 2 + + return( uiTablePos >> 1); + } + } + + // Language not found, return default US language + + return( US_LANG); +} + +/**************************************************************************** +Desc: Determine the language code from the language number +****************************************************************************/ +FLMEXP void FLMAPI FlmGetLanguage( + FLMUINT uiLangNum, + char * pszLanguageCode) +{ + if (uiLangNum >= LAST_LANG) + { + uiLangNum = US_LANG; + } + + uiLangNum += uiLangNum; + *pszLanguageCode++ = flmLangTable[ uiLangNum]; + *pszLanguageCode++ = flmLangTable[ uiLangNum + 1]; + *pszLanguageCode = 0; +} + +/**************************************************************************** +Desc: Returns TRUE if the passed in RCODE indicates that a corruption + has occured in a FLAIM database file. +****************************************************************************/ FLMEXP FLMBOOL FLMAPI FlmErrorIsFileCorrupt( RCODE rc) { @@ -35,43 +126,35 @@ FLMEXP FLMBOOL FLMAPI FlmErrorIsFileCorrupt( switch( rc) { - /* This is the list of errors within FLAIM that indicate a corruption - has been found within FLAIM database file. */ - case FERR_BTREE_ERROR : - case FERR_DATA_ERROR : - case FERR_DD_ERROR : - case FERR_NOT_FLAIM : - case FERR_PCODE_ERROR : - case FERR_BLOCK_CHECKSUM : - case FERR_INCOMPLETE_LOG : - case FERR_KEY_NOT_FOUND : - case FERR_NO_REC_FOR_KEY: - b = TRUE; - break; - default : - break; + case FERR_BTREE_ERROR : + case FERR_DATA_ERROR : + case FERR_DD_ERROR : + case FERR_NOT_FLAIM : + case FERR_PCODE_ERROR : + case FERR_BLOCK_CHECKSUM : + case FERR_INCOMPLETE_LOG : + case FERR_KEY_NOT_FOUND : + case FERR_NO_REC_FOR_KEY: + b = TRUE; + break; + default : + break; } return( b); } - -/*API~*********************************************************************** -Desc : Returns specific information about the most recent error that - occured within FLAIM. -Notes: FLAIM maintains information about the operation which generated - the error. This information can include a field number - or other information specific to the operation and can - be useful in identifying the cause of the error. -*END************************************************************************/ +/**************************************************************************** +Desc: Returns specific information about the most recent error that + occured within FLAIM. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmGetDiagInfo( HFDB hDb, eDiagInfoType eDiagCode, - void * pvDiagInfo - ) + void * pvDiagInfo) { - RCODE rc = FERR_OK; - FDB * pDb; + RCODE rc = FERR_OK; + FDB * pDb; if ((pDb = (FDB *)hDb) == NULL) { diff --git a/flaim/src/fnative.cpp b/flaim/src/fnative.cpp deleted file mode 100644 index 40e2e95..0000000 --- a/flaim/src/fnative.cpp +++ /dev/null @@ -1,448 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Native text conversion routines. -// Tabs: 3 -// -// Copyright (c) 1999-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fnative.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define NON_DISPLAYABLE_CHAR 0xFF - -/**************************************************************************** -Desc: Returns the size of buffer needed to hold the native string in - FLAIM's storage format. -****************************************************************************/ -FLMEXP FLMUINT FLMAPI FlmGetNativeStorageLength( - const char * pszStr) -{ - RCODE rc; - FLMUINT uiStorageLength; - - rc = FlmNative2Storage( pszStr, &uiStorageLength, NULL); - flmAssert( rc == FERR_OK); - - return uiStorageLength; -} - -/**************************************************************************** -Desc: Copies and formats a native 8-bit null terminated string into a - caller supplied buffer, It converts the string into an internal FLAIM - TEXT string. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmNative2Storage( - const char * pszNativeString, - FLMUINT * puiStorageLen, - FLMBYTE * pStorageBuffer) -{ - FLMBOOL bGetLengthPass; - const char * ptr; - FLMBYTE c; - FLMUINT uiLength = 0; - - // Are we determining the needed length or converting the data - - bGetLengthPass = ( pStorageBuffer) ? FALSE : TRUE; - - /* Parse through the string */ - - ptr = pszNativeString; - for( ;;) - { - - /* Put the character in a local variable for speed */ - - c = f_toascii( *ptr); - - /* See if we are at the end of the string */ - - if( !c) - { - /* We have reached end of the string, return the storage length */ - - *puiStorageLen = uiLength; - return( FERR_OK); - } - else - { - if( c < ASCII_SPACE) - { - - /* If it is a tab, carriage return, or linefeed, output */ - /* a whitespace code for indexing and each word purposes */ - - if( c == ASCII_TAB) - { - if( bGetLengthPass) - uiLength++; - else - *pStorageBuffer++ = WHITE_SPACE_CODE | NATIVE_TAB; - } - else if( c == ASCII_NEWLINE) - { - if( bGetLengthPass) - uiLength++; - else - *pStorageBuffer++ = WHITE_SPACE_CODE | NATIVE_LINEFEED; - } - else if( c == ASCII_CR) - { - if( bGetLengthPass) - uiLength++; - else - *pStorageBuffer++ = WHITE_SPACE_CODE | HARD_RETURN; - } - else - { - if( bGetLengthPass) - { - uiLength += 2; - } - else - { - /* Output the character as an unknown byte if no WP char found */ - *pStorageBuffer++ = UNK_EQ_1_CODE | NATIVE_TYPE; - *pStorageBuffer++ = c; - } - } - } - else if( c < 127) - { - /* For now assume < 127 means character set zero. */ - /* Value 127 is very sacred in WP land and is really an */ - /* extended character */ - - if( bGetLengthPass) - uiLength++; - else - *pStorageBuffer++ = c; - } - else - { - if( bGetLengthPass) - { - uiLength += 2; - } - else - { - *pStorageBuffer++ = OEM_CODE; - *pStorageBuffer++ = c; - } - } - /* Increment our pointer past the character just handled */ - - ptr++; - } - } -} - -/**************************************************************************** -Desc: Convert a storage text string into a native string -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmStorage2Native( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, - FLMUINT * puiOutBufLenRV, - char * pOutBuffer) -{ - RCODE rc = FERR_OK; - const FLMBYTE * ptr = pucValue; - char * outPtr; - FLMBYTE c; - FLMUINT bytesProcessed; - FLMUINT bytesOutput; - FLMUINT valLength = uiValueLength; - FLMUINT outputData; - FLMUINT maxOutLen = 0; - FLMBYTE objType; - FLMUINT objLength = 0; - FLMBYTE TempBuf[ 80]; - FLMUINT length; - - /* If the input is not a TEXT or a NUMBER node, return an error for now. */ - - if( (uiValueType == FLM_BINARY_TYPE) || (uiValueType == FLM_CONTEXT_TYPE)) - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - - /* If the node is a number, convert to text first */ - - if( uiValueType != FLM_TEXT_TYPE) - { - if( ptr == NULL) - { - valLength = 0; - } - else - { - valLength = sizeof( TempBuf); - flmAssert( uiValueType == FLM_NUMBER_TYPE); - if (RC_BAD( rc = GedNumToText( ptr, TempBuf, &valLength))) - { - goto Exit; - } - ptr = &TempBuf[ 0]; - } - } - - outputData = ((pOutBuffer != NULL) && (*puiOutBufLenRV)); - if( outputData) - { - maxOutLen = *puiOutBufLenRV - 1; - } - - bytesProcessed = 0; - bytesOutput = 0; - outPtr = pOutBuffer; - - while( bytesProcessed < valLength) - { - c = *ptr; - objType = (FLMBYTE)GedTextObjType( c); - - switch( objType) - { - case ASCII_CHAR_CODE: - objLength = 1; - if( outputData) - { - if( bytesOutput < maxOutLen) - *outPtr++ = f_tonative( c); - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - case CHAR_SET_CODE: - objLength = 2; - if( outputData) - { - if( bytesOutput < maxOutLen) - { - /**----------------------------------------- - *** Can only convert to native if the char - *** has been stored as a extended NATIVE. - *** FLM Doesn't support code pages - *** or alt WP to native mappings at all! - *** OLD CODE BELOW... - *** wpchr = (((FLMUINT16) (c & 0x3F)) << 8)+ CharSet - *** *(ptr + 1); CharVal - *** WpCh6Getnative( wpchr, outPtr); - *** outPtr++; - ***----------------------------------------*/ - - if( (c & (~objType)) == 0) - *outPtr++ = f_tonative( *(ptr + 1)); - else - *outPtr++ = NON_DISPLAYABLE_CHAR; - } - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - case WHITE_SPACE_CODE: - objLength = 1; - - /* ALWAYS OUTPUT A SPACE WHEN WE SEE A WHITE_SPACE_CODE */ - /* UNLESS IT IS A HYPHEN */ - - if( outputData) - { - if( bytesOutput < maxOutLen) - { - c &= (~WHITE_SPACE_MASK); - if( (c == HARD_HYPHEN) || - (c == HARD_HYPHEN_EOL) || - (c == HARD_HYPHEN_EOP) - ) - c = ASCII_DASH; /* Minus sign -- character set zero */ - else if( c == NATIVE_TAB) - c = ASCII_TAB; - else if( c == NATIVE_LINEFEED) - c = ASCII_NEWLINE; - else if( c == HARD_RETURN) - c = ASCII_CR; - else - c = ASCII_SPACE; /* Space */ - *outPtr++ = f_tonative( c); - } - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - case UNK_GT_255_CODE: - case UNK_LE_255_CODE: - if( objType == UNK_GT_255_CODE) - { - length = FB2UW( ptr + 1); - objLength = (FLMUINT16)(1 + sizeof( FLMUINT16) + length); - } - else - { - length = (FLMUINT16)*(ptr + 1); - objLength = (FLMUINT16)(2 + length); - } - - /* Skip it if it is not a NATIVE code */ - - if( (c & (~objType)) == NATIVE_TYPE) - { - if( outputData) - { - if( (maxOutLen < length) || (bytesOutput > maxOutLen - length)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - if( objType == UNK_LE_255_CODE) - f_memcpy( outPtr, ptr + 2, length); - else - f_memcpy( outPtr, ptr + 1 + sizeof( FLMUINT16), length); - outPtr += length; - } - bytesOutput += length; - } - break; - case UNK_EQ_1_CODE: - objLength = 2; - - /* Skip it if it is not a NATIVE code */ - - if( (c & (~objType)) == NATIVE_TYPE) - { - if( outputData) - { - if( bytesOutput < maxOutLen) - *outPtr++ = f_tonative( *(ptr + 1)); - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - } - break; - case EXT_CHAR_CODE: - objLength = 3; - if( outputData) - { - if( bytesOutput < maxOutLen) - { - /**----------------------------------------- - *** Can no longer convert to native - *** because toolkit will not support - *** code pages or alt WP->native mappings - *** OLD CODE BELOW... - *** wpchr = (((FLMUINT16) (*(ptr+1))) << 8) + ** Character set - *** *(ptr + 2); ** Character - *** WpCh6Getnative( wpchr, outPtr); - *** outPtr++; - ***----------------------------------------*/ - - *outPtr += NON_DISPLAYABLE_CHAR; - } - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - - case OEM_CODE: - objLength = 2; - if( outputData) - { - /** This code takes the original OEM 8-bit code. - *** This bothers me (Scott) a bit (good pun!) because the - *** character could have come from a different code page. - *** In the far future, 8-bit codes could be remembered - *** with the original code page that was used to create - *** the text. This way the database could have good - *** storage and recall of the information. All databases - *** share this common problem and none solve it well except - *** for Lotus Notes which have their own character set like - *** WP. - **/ - - if( bytesOutput < maxOutLen) - *outPtr++ = f_tonative( *(ptr + 1)); - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - - - case UNICODE_CODE: - objLength = 3; - if( outputData) - { - if( bytesOutput < maxOutLen ) - *outPtr++ = UNICODE_UNCONVERTABLE_CHAR; - else - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Native_Output; - } - } - bytesOutput++; - break; - - default: - - /* These codes should NEVER HAPPEN -- bug if we get here */ - - break; - } - ptr += objLength; - bytesProcessed += objLength; - } - - /* Add a terminating NULL character, but DO NOT increment the */ - /* bytesOutput counter! */ - -Native_Output: - if( outputData) - *outPtr = 0; - *puiOutBufLenRV = bytesOutput; - -Exit: - return( rc); -} diff --git a/flaim/src/fntable.cpp b/flaim/src/fntable.cpp index 317825a..a5fb6c1 100644 --- a/flaim/src/fntable.cpp +++ b/flaim/src/fntable.cpp @@ -913,7 +913,7 @@ RCODE F_NameTable::setupFromDb( FLMUINT uiLoop; BTSK StackBuf [BH_MAX_LEVELS]; FLMBOOL bStackInitialized = FALSE; - BTSK_p pStack; + BTSK * pStack; FLMBYTE ucKeyBuf [8]; FLMBYTE ucDrnBuf [8]; void * pvField; diff --git a/flaim/src/fposix.cpp b/flaim/src/fposix.cpp index 022e194..e88211a 100644 --- a/flaim/src/fposix.cpp +++ b/flaim/src/fposix.cpp @@ -58,6 +58,7 @@ extern RCODE gv_CriticalFSError; /**************************************************************************** Desc: ****************************************************************************/ +#if defined( FLM_UNIX) F_FileHdlImp::F_FileHdlImp() { m_fd = INVALID_HANDLE_VALUE; @@ -73,10 +74,12 @@ F_FileHdlImp::F_FileHdlImp() m_pucAlignedBuff = NULL; m_uiAlignedBuffSize = 0; } +#endif /**************************************************************************** Desc: ****************************************************************************/ +#if defined( FLM_UNIX) F_FileHdlImp::~F_FileHdlImp() { if( m_bFileOpened) @@ -89,10 +92,12 @@ F_FileHdlImp::~F_FileHdlImp() free( m_pucAlignedBuff); } } +#endif /*************************************************************************** Desc: Open or create a file. ***************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::OpenOrCreate( const char * pFileName, FLMUINT uiAccess, @@ -108,13 +113,13 @@ RCODE F_FileHdlImp::OpenOrCreate( goto Exit; } -#if !defined( FLM_UNIX) +#if defined( FLM_LINUX) || defined( FLM_SOLARIS) bDoDirectIO = (uiAccess & F_IO_DIRECT) ? TRUE : FALSE; #endif -// HPUX needs this defined to access files larger than 2 GB. The Linux -// man pages *say* it's needed although as of Suse 9.1 it actually -// isn't. Including this flag on Linux anyway just it case... + // HPUX needs this defined to access files larger than 2 GB. The Linux + // man pages *say* it's needed although as of Suse 9.1 it actually + // isn't. Including this flag on Linux anyway just it case... #if defined( FLM_HPUX) || defined( FLM_LINUX) openFlags |= O_LARGEFILE; @@ -191,6 +196,34 @@ RCODE F_FileHdlImp::OpenOrCreate( { bDoDirectIO = FALSE; } + else + { +#if defined( FLM_LINUX) + FLMUINT uiMajor = gv_FlmSysData.uiLinuxMajorVer; + FLMUINT uiMinor = gv_FlmSysData.uiLinuxMinorVer; + FLMUINT uiRevision = gv_FlmSysData.uiLinuxRevision; + + if( uiMajor > 2 || (uiMajor == 2 && uiMinor > 6) || + (uiMajor == 2 && uiMinor == 6 && uiRevision >= 5)) + { + openFlags |= O_DIRECT; + + if( gv_FlmSysData.bOkToDoAsyncWrites) + { + m_bCanDoAsync = TRUE; + } + } + else + { + bDoDirectIO = FALSE; + } +#elif defined( FLM_SOLARIS) + if( gv_FlmSysData.bOkToDoAsyncWrites) + { + m_bCanDoAsync = TRUE; + } +#endif + } } } @@ -221,6 +254,15 @@ Retry_Create: goto Retry_Create; } } +#ifdef FLM_LINUX + else if( errno == EINVAL && bDoDirectIO) + { + openFlags &= ~O_DIRECT; + bDoDirectIO = FALSE; + m_bCanDoAsync = FALSE; + goto Retry_Create; + } +#endif rc = MapErrnoToFlaimErr( errno, FERR_OPENING_FILE); goto Exit; @@ -246,10 +288,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Create a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Create( const char * pIoPath, FLMUINT uiIoFlags) @@ -276,10 +320,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::CreateUnique( char * pIoPath, const char * pszFileExtension, @@ -389,10 +435,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Open a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Open( const char * pIoPath, FLMUINT uiIoFlags) @@ -440,11 +488,12 @@ Exit: return( rc); } - +#endif /**************************************************************************** Desc: Close a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Close( void) { FLMBOOL bDeleteAllowed = TRUE; @@ -484,10 +533,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Make sure all file data is safely on disk ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Flush( void) { #ifdef FLM_SOLARIS @@ -536,10 +587,12 @@ RCODE F_FileHdlImp::Flush( void) return( FERR_OK); } +#endif /**************************************************************************** Desc: Read from a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::DirectRead( FLMUINT uiReadOffset, FLMUINT uiBytesToRead, @@ -623,26 +676,12 @@ RCODE F_FileHdlImp::DirectRead( bHitEOF = FALSE; -#ifdef HAVE_PREAD if( (iTmp = pread( m_fd, pucReadBuffer, uiMaxBytesToRead, GetSectorStartOffset( uiReadOffset))) == -1) { rc = MapErrnoToFlaimErr( errno, FERR_READING_FILE); goto Exit; } -#else - if( lseek( m_fd, GetSectorStartOffset( uiReadOffset), SEEK_SET) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_POSITIONING_IN_FILE); - goto Exit; - } - - if( (iTmp = read( m_fd, pucReadBuffer, uiMaxBytesToRead)) == -1) - { - rc = MapErrnoToFlaimErr(errno, FERR_READING_FILE); - goto Exit; - } -#endif uiBytesRead = (FLMUINT)iTmp; if( uiBytesRead < uiMaxBytesToRead) @@ -709,10 +748,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Read from a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Read( FLMUINT uiReadOffset, FLMUINT uiBytesToRead, @@ -741,28 +782,11 @@ RCODE F_FileHdlImp::Read( uiReadOffset = m_uiCurrentPos; } -#ifdef HAVE_PREAD if( (iBytesRead = pread( m_fd, pvBuffer, uiBytesToRead, uiReadOffset)) == -1) { rc = MapErrnoToFlaimErr(errno, FERR_READING_FILE); goto Exit; } -#else - if( m_uiCurrentPos != uiReadOffset) - { - if( lseek( m_fd, uiReadOffset, SEEK_SET) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_POSITIONING_IN_FILE); - goto Exit; - } - } - - if( (iBytesRead = read( m_fd, pvBuffer, uiBytesToRead)) == -1) - { - rc = MapErrnoToFlaimErr(errno, FERR_READING_FILE); - goto Exit; - } -#endif if( puiBytesRead) { @@ -781,12 +805,14 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Note: This function assumes that the pvBuffer that is passed in is a multiple of a the sector size. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::SectorRead( FLMUINT uiReadOffset, FLMUINT uiBytesToRead, @@ -803,11 +829,13 @@ RCODE F_FileHdlImp::SectorRead( return( Read( uiReadOffset, uiBytesToRead, pvBuffer, puiBytesRead)); } } +#endif /**************************************************************************** Desc: Sets current position of file. Note: F_IO_SEEK_END is not supported. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Seek( FLMUINT uiOffset, FLMINT iWhence, @@ -850,24 +878,18 @@ RCODE F_FileHdlImp::Seek( } } -#ifndef HAVE_PREAD - if( lseek( m_fd, m_uiCurrentPos, SEEK_SET) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_POSITIONING_IN_FILE); - goto Exit; - } -#endif - *puiNewOffset = m_uiCurrentPos; Exit: return( rc); } +#endif /**************************************************************************** Desc: Return the size of the file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Size( FLMUINT * puiSize) { @@ -894,10 +916,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Returns m_uiCurrentPos ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Tell( FLMUINT * puiOffset) { @@ -914,12 +938,14 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Truncate the file to the indicated size WARNING: Direct IO methods are calling this method. Make sure that all changes to this method work in direct IO mode. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Truncate( FLMUINT uiSize) { @@ -942,10 +968,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Write to a file ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Write( FLMUINT uiWriteOffset, FLMUINT uiBytesToWrite, @@ -975,29 +1003,12 @@ RCODE F_FileHdlImp::Write( uiWriteOffset = m_uiCurrentPos; } -#ifdef HAVE_PREAD if( (iBytesWritten = pwrite(m_fd, pvBuffer, uiBytesToWrite, uiWriteOffset)) == -1) { rc = MapErrnoToFlaimErr( errno, FERR_WRITING_FILE); goto Exit; } -#else - if( m_uiCurrentPos != uiWriteOffset) - { - if( lseek(m_fd, uiWriteOffset, SEEK_SET) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_POSITIONING_IN_FILE); - goto Exit; - } - } - - if( (iBytesWritten = write( m_fd, pvBuffer, uiBytesToWrite)) == -1) - { - rc = MapErrnoToFlaimErr(errno, FERR_WRITING_FILE); - goto Exit; - } -#endif if( puiBytesWrittenRV) { @@ -1016,10 +1027,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Allocate an aligned buffer. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::AllocAlignBuffer( void) { #if !defined( FLM_LINUX) && !defined( FLM_SOLARIS) @@ -1052,6 +1065,7 @@ Exit: return( rc); #endif } +#endif /**************************************************************************** Desc: @@ -1061,11 +1075,12 @@ Note: This routine assumes that the size of pvBuffer is a multiple of buffer will still be written out - a partial sector on disk will not be preserved. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::DirectWrite( FLMUINT uiWriteOffset, FLMUINT uiBytesToWrite, const void * pvBuffer, - FLMUINT, + FLMUINT uiBufferSize, F_IOBuffer * pBufferObj, FLMUINT * puiBytesWrittenRV, FLMBOOL bBuffHasFullSectors, @@ -1077,9 +1092,6 @@ RCODE F_FileHdlImp::DirectWrite( FLMUINT uiBytesBeingOutput; FLMBYTE * pucWriteBuffer; FLMBYTE * pucSrcBuffer; - FLMBOOL bDoAsync = (pBufferObj != NULL) - ? TRUE - : FALSE; FLMBOOL bDidAsync = FALSE; FLMUINT uiLastWriteOffset; FLMUINT uiLastWriteSize; @@ -1087,12 +1099,10 @@ RCODE F_FileHdlImp::DirectWrite( flmAssert( m_bFileOpened); #ifdef FLM_DEBUG - if( bDoAsync) + if( pBufferObj != NULL) { flmAssert( m_bCanDoAsync); } -#else - (void)bDoAsync; #endif if( puiBytesWrittenRV) @@ -1126,7 +1136,7 @@ RCODE F_FileHdlImp::DirectWrite( // Cannot be using a temporary write buffer if we are doing // asynchronous writes! - flmAssert( !bDoAsync || !m_bCanDoAsync); + flmAssert( !pBufferObj || !m_bCanDoAsync); if( !m_pucAlignedBuff) { @@ -1214,26 +1224,12 @@ RCODE F_FileHdlImp::DirectWrite( { FLMINT iBytesWritten; -#ifdef HAVE_PREAD if( (iBytesWritten = pwrite( m_fd, pucWriteBuffer, uiMaxBytesToWrite, uiLastWriteOffset)) == -1) { rc = MapErrnoToFlaimErr( errno, FERR_WRITING_FILE); goto Exit; } -#else - if( lseek( m_fd, uiLastWriteOffset, SEEK_SET) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_POSITIONING_IN_FILE); - goto Exit; - } - - if( (iBytesWritten = write( m_fd, pucWriteBuffer, uiMaxBytesToWrite)) == -1) - { - rc = MapErrnoToFlaimErr( errno, FERR_WRITING_FILE); - goto Exit; - } -#endif if( (FLMUINT)iBytesWritten < uiMaxBytesToWrite) { @@ -1243,7 +1239,32 @@ RCODE F_FileHdlImp::DirectWrite( } else { - flmAssert( 0); +#ifdef FLM_OSX + // Mac OS doesn't have posix async io, so we don't ever + // want to enter this else clause + + rc = RC_SET_AND_ASSERT( FERR_NOT_IMPLEMENTED); + goto Exit; +#else + struct aiocb * pAio = pBufferObj->getAIOStruct(); + + f_memset( pAio, 0, sizeof( struct aiocb)); + pAio->aio_lio_opcode = LIO_WRITE; + pAio->aio_sigevent.sigev_notify = SIGEV_NONE; + pAio->aio_fildes = m_fd; + pAio->aio_offset = uiLastWriteOffset; + pAio->aio_nbytes = uiMaxBytesToWrite; + pAio->aio_buf = pucWriteBuffer; + + if( aio_write( pAio) == -1) + { + rc = MapErrnoToFlaimErr( errno, FERR_WRITING_FILE); + goto Exit; + } + + pBufferObj->makePending(); + bDidAsync = TRUE; +#endif } uiBytesToWrite -= uiBytesBeingOutput; @@ -1274,20 +1295,24 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Returns flag indicating whether or not we can do async writes. ****************************************************************************/ +#if defined( FLM_UNIX) FLMBOOL F_FileHdlImp::CanDoAsync( void) { return( m_bCanDoAsync); } +#endif /**************************************************************************** Desc: Attempts to lock byte 0 of the file. This method is used to lock byte 0 of the .lck file to ensure that only one process has access to a database. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Lock( void) { RCODE rc = FERR_OK; @@ -1311,10 +1336,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Attempts to unlock byte 0 of the file. ****************************************************************************/ +#if defined( FLM_UNIX) RCODE F_FileHdlImp::Unlock( void) { struct flock LockStruct; @@ -1338,11 +1365,12 @@ Exit: return( rc); } +#endif /*************************************************************************** Desc: Determines the kernel version of a linux system ***************************************************************************/ -#ifdef FLM_LINUX +#if defined( FLM_LINUX) void flmGetLinuxKernelVersion( FLMUINT * puiMajor, FLMUINT * puiMinor, @@ -1427,7 +1455,7 @@ Exit: /*************************************************************************** Desc: Determines if the linux system we are running on is 2.4 or greater. ***************************************************************************/ -#ifdef FLM_LINUX +#if defined( FLM_LINUX) FLMUINT flmGetLinuxMaxFileSize( FLMUINT uiSizeofFLMUINT) { @@ -1469,6 +1497,7 @@ Exit: /**************************************************************************** Desc: This routine gets the block size for the file system a file belongs to. ****************************************************************************/ +#if defined( FLM_UNIX) FLMUINT flmGetFSBlockSize( const char * pszFileName) { @@ -1523,6 +1552,7 @@ FLMUINT flmGetFSBlockSize( return( uiFSBlkSize); } +#endif #if defined( FLM_SOLARIS) && defined( FLM_SPARC) && !defined( FLM_GNUC) /**************************************************************************** diff --git a/flaim/src/fqcur.cpp b/flaim/src/fqcur.cpp index 11cb513..a30f95c 100644 --- a/flaim/src/fqcur.cpp +++ b/flaim/src/fqcur.cpp @@ -34,43 +34,43 @@ POOL_STATS g_QueryPoolStats = {0,0}; // Local Function Prototypes FSTATIC RCODE flmCurCopyQTInfo( - QTINFO_p pSrc, - QTINFO_p pDest, + QTINFO * pSrc, + QTINFO * pDest, POOL * pPool); FSTATIC void flmCurClearSelect( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmCurPosToEOF( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmCurPosToBOF( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmCurSetPos( - CURSOR_p pDestCursor, - CURSOR_p pSrcCursor ); + CURSOR * pDestCursor, + CURSOR * pSrcCursor ); FSTATIC RCODE flmCurSetAbsolutePos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiPosition, FLMBOOL bFallForward, FLMUINT * puiPosition); FSTATIC RCODE flmCurPositionable( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL * pbPositionable); FSTATIC RCODE flmCurAbsPositionable( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL * pbAbsPositionable); FSTATIC RCODE flmCurGetAbsolutePos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiPosition); FSTATIC RCODE flmCurGetAbsoluteCount( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiCount); FSTATIC FLMBOOL flmCurMatchIndexPath( @@ -82,7 +82,7 @@ FSTATIC FLMBOOL flmCurMatchIndexPath( Desc: Finishes a source's invisible transaction, if any. ****************************************************************************/ void flmCurFinishTrans( - CURSOR_p pCursor) + CURSOR * pCursor) { FLMBOOL bIgnore; @@ -112,7 +112,7 @@ void flmCurFinishTrans( Desc: Initializes an FDB for a source. ****************************************************************************/ RCODE flmCurDbInit( - CURSOR_p pCursor) + CURSOR * pCursor) { RCODE rc; FLMBOOL bStartedTrans; @@ -131,19 +131,18 @@ RCODE flmCurDbInit( return( rc); } -/*API~*********************************************************************** -Desc : Initializes a cursor for subsequent definition and navigation of - a record set. A cursor must be initialized before it can - be used. -*END************************************************************************/ +/**************************************************************************** +Desc: Initializes a cursor for subsequent definition and navigation of + a record set. A cursor must be initialized before it can + be used. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorInit( HFDB hDb, FLMUINT uiContainer, - HFCURSOR * phCursor - ) + HFCURSOR * phCursor) { RCODE rc = FERR_OK; - CURSOR_p pCursor = NULL; + CURSOR * pCursor = NULL; FDB * pDb = (FDB *)hDb; flmAssert( hDb != HFDB_NULL); @@ -200,14 +199,14 @@ Desc: Copies a passed-in query tree into a new tree, using the passed-in memory pool. ****************************************************************************/ FSTATIC RCODE flmCurCopyQTInfo( - QTINFO_p pSrc, - QTINFO_p pDest, + QTINFO * pSrc, + QTINFO * pDest, POOL * pPool) { RCODE rc = FERR_OK; - FQNODE_p pDestParentNode; - FQNODE_p pSrcCurrNode; - FQNODE_p pDestCurrNode; + FQNODE * pDestParentNode; + FQNODE * pSrcCurrNode; + FQNODE * pDestCurrNode; FLMBOOL bGoingUp = FALSE; FLMBOOL bTreeComplete; @@ -358,20 +357,19 @@ Exit: return( rc); } -/*API~*********************************************************************** -Desc : Initializes a new cursor and sets its selection criteria and record - sources to be the same as those of the passed-in cursor. -*END************************************************************************/ +/**************************************************************************** +Desc: Initializes a new cursor and sets its selection criteria and record + sources to be the same as those of the passed-in cursor. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorClone( HFCURSOR hSource, - HFCURSOR * phCursor - ) + HFCURSOR * phCursor) { - RCODE rc = FERR_OK; - CURSOR_p pSrcCursor; - CURSOR_p pDestCursor = NULL; + RCODE rc = FERR_OK; + CURSOR * pSrcCursor; + CURSOR * pDestCursor = NULL; - if ((pSrcCursor = (CURSOR_p)hSource) == NULL) + if ((pSrcCursor = (CURSOR *)hSource) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -445,7 +443,7 @@ Exit: Desc: Frees up memory associated with a subquery structure. ****************************************************************************/ void flmSQFree( - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMBOOL bFreeEverything) { if (!bFreeEverything) @@ -461,7 +459,7 @@ void flmSQFree( } else { - FQNODE_p pCurrNode = pSubQuery->pTree; + FQNODE * pCurrNode = pSubQuery->pTree; QTYPES eType; // Free the memory associated with callbacks in the query tree. @@ -528,11 +526,11 @@ void flmSQFree( Desc: Frees up memory associated with a cursor. ****************************************************************************/ void flmCurFree( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFinishTrans) { FLMUINT uiCnt; - CS_CONTEXT_p pCSContext; + CS_CONTEXT * pCSContext; if (bFinishTrans) { @@ -616,37 +614,36 @@ CS_Exit: return; } -/*API~*********************************************************************** +/**************************************************************************** Desc: Frees resources of the cursor without actually freeing the cursor. Keeps around the stuff that is needed to display the cursor information for debugging purposes after the fact. At this point the cursor is no longer usable. -*END************************************************************************/ +****************************************************************************/ FLMEXP void FLMAPI FlmCursorReleaseResources( - HFCURSOR hCursor - ) + HFCURSOR hCursor) { - FLMUINT uiCnt; - CURSOR_p pCursor = (CURSOR_p)hCursor; + FLMUINT uiCnt; + CURSOR * pCursor = (CURSOR *)hCursor; flmCurFinishTransactions( pCursor, TRUE); flmCurFreeSQList( pCursor, FALSE); + for (uiCnt = 0; uiCnt < pCursor->QTInfo.uiNumPredicates; uiCnt++) { pCursor->QTInfo.ppPredicates [uiCnt]->releaseResources(); } } -/*API~*********************************************************************** -Desc : Frees memory allocated to an initialized cursor. The cursor handle - cannot be used for additional cursor operations unless it is - re-initialized. -*END************************************************************************/ +/**************************************************************************** +Desc: Frees memory allocated to an initialized cursor. The cursor handle + cannot be used for additional cursor operations unless it is + re-initialized. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorFree( - HFCURSOR * phCursor - ) + HFCURSOR * phCursor) { - CURSOR_p pCursor = (CURSOR *)*phCursor; + CURSOR * pCursor = (CURSOR *)*phCursor; F_LogMessage * pLogMsg = NULL; flmAssert( pCursor != NULL); @@ -675,15 +672,15 @@ FLMEXP RCODE FLMAPI FlmCursorFree( return FERR_OK; } -/*API~*********************************************************************** -Desc : Sets flags in the query that determine text comparision modes and the - granularity for QuickFinder indexes. -*END************************************************************************/ +/**************************************************************************** +Desc: Sets flags in the query that determine text comparision modes + and the granularity for QuickFinder indexes. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorSetMode( HFCURSOR hCursor, FLMUINT uiFlags) { - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; flmAssert( pCursor != NULL); @@ -700,7 +697,7 @@ FLMEXP RCODE FLMAPI FlmCursorSetMode( Desc: Clears the selection criteria in a query. ****************************************************************************/ FSTATIC void flmCurClearSelect( - CURSOR_p pCursor) + CURSOR * pCursor) { flmCurFreeSQList( pCursor, TRUE); pCursor->pTree = NULL; @@ -727,8 +724,7 @@ FSTATIC void flmCurClearSelect( Desc: Positions a cursor to EOF. ****************************************************************************/ FSTATIC RCODE flmCurPosToEOF( - CURSOR_p pCursor - ) + CURSOR * pCursor) { RCODE rc = FERR_OK; FlmRecord * pRecord = NULL; @@ -766,7 +762,7 @@ FSTATIC RCODE flmCurPosToEOF( Desc: Positions a cursor to BOF. ****************************************************************************/ FSTATIC RCODE flmCurPosToBOF( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; @@ -806,16 +802,16 @@ Desc: Sets the positioning information in a query to be the same as that of another query. ****************************************************************************/ FSTATIC RCODE flmCurSetPos( - CURSOR_p pDestCursor, - CURSOR_p pSrcCursor) + CURSOR * pDestCursor, + CURSOR * pSrcCursor) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; + FDB * pDb = NULL; FlmRecord * pRecord = NULL; FLMUINT uiRecordDrn; FLMUINT uiContainerNum; - SUBQUERY_p pSrcSubQuery; - SUBQUERY_p pDestSubQuery; + SUBQUERY * pSrcSubQuery; + SUBQUERY * pDestSubQuery; FLMUINT uiRecMatch; FLMBYTE * pucKeyBuffer = NULL; FLMUINT uiKeyLen; @@ -1111,11 +1107,11 @@ Exit: Desc: Saves the current cursor position. ****************************************************************************/ RCODE flmCurSavePosition( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - SUBQUERY_p pSaveSubQuery; + SUBQUERY * pSaveSubQuery; pCursor->pSaveSubQuery = pSaveSubQuery = pCursor->pCurrSubQuery; if (pSaveSubQuery) @@ -1156,11 +1152,11 @@ Exit: Desc: Restores the last cursor position that was saved. ****************************************************************************/ RCODE flmCurRestorePosition( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - SUBQUERY_p pSaveSubQuery = pCursor->pSaveSubQuery; + SUBQUERY * pSaveSubQuery = pCursor->pSaveSubQuery; if ((pCursor->pCurrSubQuery = pSaveSubQuery = @@ -1204,7 +1200,7 @@ Exit: Desc: Sets a cursor to an absolute position. ****************************************************************************/ FSTATIC RCODE flmCurSetAbsolutePos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiPosition, FLMBOOL bFallForward, FLMUINT * puiPosition @@ -1545,10 +1541,10 @@ Exit: return( pCursor->rc = rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Allows configuration of cursor attributes, including assignment of QuickFinder strings, indexes and search records. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorConfig( HFCURSOR hCursor, eCursorConfigType eConfigType, @@ -1557,7 +1553,7 @@ FLMEXP RCODE FLMAPI FlmCursorConfig( ) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -1701,9 +1697,9 @@ FLMEXP RCODE FLMAPI FlmCursorConfig( case FCURSOR_SET_POS: { - CURSOR_p pPosCursor; + CURSOR * pPosCursor; - if ((pPosCursor = (CURSOR_p)Value1) == NULL) + if ((pPosCursor = (CURSOR *)Value1) == NULL) { flmAssert( 0); rc = RC_SET( FERR_INVALID_PARM); @@ -1776,11 +1772,11 @@ Exit: Desc : Returns whether or not a query is positionable. *************************************************************************/ FSTATIC RCODE flmCurPositionable( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL * pbPositionable) { RCODE rc = FERR_OK; - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; *pbPositionable = FALSE; @@ -1819,11 +1815,11 @@ Exit: Desc : Returns whether or not a query is absolute positionable. *************************************************************************/ FSTATIC RCODE flmCurAbsPositionable( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL * pbAbsPositionable) { RCODE rc = FERR_OK; - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; FLMBOOL bSavedInvisTrans; *pbAbsPositionable = FALSE; @@ -1870,7 +1866,7 @@ Exit: Desc : Returns absolute position of cursor. *************************************************************************/ FSTATIC RCODE flmCurGetAbsolutePos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiPosition ) { @@ -1951,7 +1947,7 @@ Desc : Returns absolute count for the cursor's index. NOTE: This is will pass the filter criteria. *************************************************************************/ FSTATIC RCODE flmCurGetAbsoluteCount( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiCount ) { @@ -2010,18 +2006,17 @@ Exit: return( pCursor->rc = rc); } -/*API~*********************************************************************** -Desc : Returns FLAIM cursor configuration values. -*END************************************************************************/ +/**************************************************************************** +Desc: Returns FLAIM cursor configuration values. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorGetConfig( HFCURSOR hCursor, eCursorGetConfigType eGetConfigType, void * Value1, - void * Value2 - ) + void * Value2) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -2038,6 +2033,7 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( switch( eGetConfigType) { case FCURSOR_GET_PERCENT_POS: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2046,8 +2042,12 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { rc = flmCurGetPercentPos( pCursor, (FLMUINT *)Value1); } + break; + } + case FCURSOR_GET_ABS_POS: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2056,8 +2056,12 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { rc = flmCurGetAbsolutePos( pCursor, (FLMUINT *)Value1); } + break; + } + case FCURSOR_GET_ABS_COUNT: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2066,8 +2070,12 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { rc = flmCurGetAbsoluteCount( pCursor, (FLMUINT *)Value1); } + break; + } + case FCURSOR_GET_OPT_INFO_LIST: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2086,6 +2094,7 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( goto Exit; } } + for (pSubQuery = pCursor->pSubQueryList; pSubQuery; pSubQuery = pSubQuery->pNext) @@ -2095,12 +2104,18 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( f_memcpy( &pOptInfoArray[ uiSubQueryCnt], &pSubQuery->OptInfo, sizeof( OPT_INFO)); } + uiSubQueryCnt++; } + *puiSubQueryCnt = uiSubQueryCnt; } + break; + } + case FCURSOR_GET_OPT_INFO: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2114,14 +2129,19 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( goto Exit; } } + if (pCursor->pSubQueryList) { f_memcpy( (OPT_INFO *)Value2, &pCursor->pSubQueryList->OptInfo, sizeof( OPT_INFO)); } } + break; + } + case FCURSOR_GET_FLM_IX: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2142,7 +2162,7 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( if( pCursor->pSubQueryList) { - SUBQUERY_p pTmpSubQuery = pCursor->pSubQueryList; + SUBQUERY * pTmpSubQuery = pCursor->pSubQueryList; FLMUINT uiSQIndex = 0; while( pTmpSubQuery) @@ -2158,7 +2178,9 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { FLMUINT uiTmpIndexInfo; - uiSQIndex = pTmpSubQuery->pPredicate->getIndex( &uiTmpIndexInfo); + uiSQIndex = pTmpSubQuery->pPredicate->getIndex( + &uiTmpIndexInfo); + if (uiTmpIndexInfo == HAVE_MULTIPLE_INDEXES) { if (!uiIxNum) @@ -2231,14 +2253,24 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( *((FLMUINT *)Value2) = uiIndexInfo; } } + break; + } + case FCURSOR_GET_REC_TYPE: + { *((FLMUINT *)Value1) = pCursor->uiRecType; break; + } + case FCURSOR_GET_FLAGS: + { *((FLMUINT *)Value1) = pCursor->QTInfo.uiFlags; break; + } + case FCURSOR_GET_STATE: + { *((FLMUINT *)Value1) = 0; if (pCursor->QTInfo.pTopNode || @@ -2247,23 +2279,30 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { *((FLMUINT *)Value1) |= FCURSOR_HAVE_CRITERIA; } + if (pCursor->QTInfo.uiExpecting & FLM_Q_OPERATOR) { *((FLMUINT *)Value1) |= FCURSOR_EXPECTING_OPERATOR; } + if ((pCursor->QTInfo.uiNestLvl == 0) || ((pCursor->QTInfo.uiExpecting & FLM_Q_OPERATOR) && pCursor->QTInfo.pTopNode)) { *((FLMUINT *)Value1) |= FCURSOR_QUERY_COMPLETE; } + if (pCursor->bOptimized) { *((FLMUINT *)Value1) |= (FCURSOR_QUERY_OPTIMIZED | FCURSOR_READ_PERFORMED); } + break; + } + case FCURSOR_GET_POSITIONABLE: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2272,8 +2311,12 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { rc = flmCurPositionable( pCursor, (FLMBOOL *)Value1); } + break; + } + case FCURSOR_GET_ABS_POSITIONABLE: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2282,8 +2325,12 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( { rc = flmCurAbsPositionable( pCursor, (FLMBOOL *)Value1); } + break; + } + case FCURSOR_AT_BOF: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2297,13 +2344,18 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( goto Exit; } } + *((FLMBOOL *)Value1) = (FLMBOOL)((!pCursor->uiLastRecID && pCursor->ReadRc == FERR_BOF_HIT) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } + break; + } + case FCURSOR_AT_EOF: + { if (pCursor->pCSContext) { rc = RC_SET( FERR_NOT_IMPLEMENTED); @@ -2317,24 +2369,31 @@ FLMEXP RCODE FLMAPI FlmCursorGetConfig( goto Exit; } } + *((FLMBOOL *)Value1) = (FLMBOOL)((!pCursor->uiLastRecID && pCursor->ReadRc == FERR_EOF_HIT) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); } + break; + } + default: + { rc = RC_SET( FERR_NOT_IMPLEMENTED); break; + } } Exit: + return( rc); } /**************************************************************************** -Desc: Given a IFD this function will verify that the input path matches and - that it is in the same position (for compound keys) +Desc: Given a IFD this function will verify that the input path matches and + that it is in the same position (for compound keys) ****************************************************************************/ FSTATIC FLMBOOL flmCurMatchIndexPath( IFD * pIfd, @@ -2370,7 +2429,7 @@ Exit: return( bIsMatch); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Uses the specified field path[s] to find a matching ordering index. Note: FlmCursorConfig( type == FCURSOR_SET_FLM_IX) and FlmCursorSetOrderIndex cannot both be called for the same cursor (they will override each @@ -2378,7 +2437,7 @@ Note: FlmCursorConfig( type == FCURSOR_SET_FLM_IX) and FlmCursorSetOrderIndex Warning: The index selected from this call will be used for query optimization in addition to ordering the results. This could result in slower query performance. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorSetOrderIndex( HFCURSOR hCursor, FLMUINT * puiFieldPaths, /* List of field paths to match on. Each path @@ -2389,11 +2448,11 @@ FLMEXP RCODE FLMAPI FlmCursorSetOrderIndex( was found. */ { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; - FDB_p pDb = NULL; - IFD_p pIfd; - IFD_p pIfd2; - IXD_p pIxd; + CURSOR * pCursor = (CURSOR *)hCursor; + FDB * pDb = NULL; + IFD * pIfd; + IFD * pIfd2; + IXD * pIxd; FLMUINT * puiField = puiFieldPaths; FLMUINT uiPos; FLMUINT uiScore; @@ -2557,10 +2616,10 @@ Exit: Desc: ****************************************************************************/ void flmCurFreeSQList( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFreeEverything) { - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; for( pSubQuery = pCursor->pSubQueryList; pSubQuery; diff --git a/flaim/src/fqdecl.cpp b/flaim/src/fqdecl.cpp index 5ab243e..20c5a53 100644 --- a/flaim/src/fqdecl.cpp +++ b/flaim/src/fqdecl.cpp @@ -26,18 +26,18 @@ FSTATIC RCODE flmSendCursorFrom( FCL_WIRE * pWire, - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmSendCursorWhere( FCL_WIRE * pWire, - CURSOR_p pCursor); + CURSOR * pCursor); /**************************************************************************** Desc: Send the FROM information for the cursor to the client. ****************************************************************************/ FSTATIC RCODE flmSendCursorFrom( FCL_WIRE * pWire, - CURSOR_p pCursor) + CURSOR * pCursor) { RCODE rc = FERR_OK; NODE * pRootNode; @@ -46,7 +46,7 @@ FSTATIC RCODE flmSendCursorFrom( POOL * pPool = pWire->getPool(); void * pvMark = GedPoolMark( pPool); FLMUINT uiTmp; - CS_CONTEXT_p pCSContext = pWire->getContext(); + CS_CONTEXT * pCSContext = pWire->getContext(); if ((pRootNode = GedNodeMake( pPool, FCS_ITERATOR_FROM, &rc)) == NULL) { @@ -102,7 +102,7 @@ FSTATIC RCODE flmSendCursorFrom( // Add bOkToReturnKeys flag - if( pCSContext->uiServerFlaimVer >= FLM_VER_4_3) + if( pCSContext->uiServerFlaimVer >= FLM_FILE_FORMAT_VER_4_3) { uiTmp = (FLMUINT)(pCursor->bOkToReturnKeys ? 1 : 0); if (RC_BAD( rc = gedAddField( pPool, pChildNode, @@ -152,19 +152,19 @@ Desc: Send selection criteria for the cursor to the server. ****************************************************************************/ FSTATIC RCODE flmSendCursorWhere( FCL_WIRE * pWire, - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; NODE * pRootNode; NODE * pFldNode; - FQNODE_p pQNode; + FQNODE * pQNode; FLMUINT uiOperator; FLMUINT uiLastFlags = 0; QTYPES eOp; POOL * pPool = pWire->getPool(); void * pvMark = GedPoolMark( pPool); - CS_CONTEXT_p pCSContext = pWire->getContext(); + CS_CONTEXT * pCSContext = pWire->getContext(); if ((pRootNode = GedNodeMake( pPool, FCS_ITERATOR_WHERE, &rc)) == NULL) { @@ -499,11 +499,11 @@ Exit: Desc: Initialize a query over the client/server line. ****************************************************************************/ RCODE flmInitCurCS( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - CS_CONTEXT_p pCSContext = pCursor->pCSContext; + CS_CONTEXT * pCSContext = pCursor->pCSContext; FCL_WIRE Wire( pCSContext); if (pCursor->uiCursorId != FCS_INVALID_ID) @@ -556,23 +556,21 @@ Transmission_Error: goto Exit; } -/*API~*********************************************************************** -Desc : Validates the selection criteria of a cursor. -Notes: It is not necessary to explicitly validate the selection criteria - through a call to this routine. FLAIM will automatically attempt - validation on the first call to any of the cursor routines which - make use of the criteria. Although explicit validation is unnecessary, - it can be convenient to identify an error in the selection criteria - before calling cursor routines which will make use of it. -Ret: FERR_CURSOR_SYNTAX - The selection criteria contains a syntax error -*END************************************************************************/ +/**************************************************************************** +Desc: Validates the selection criteria of a cursor. +Notes: It is not necessary to explicitly validate the selection criteria + through a call to this routine. FLAIM will automatically attempt + validation on the first call to any of the cursor routines which + make use of the criteria. Although explicit validation is + unnecessary, it can be convenient to identify an error in the + selection criteria before calling cursor routines which will make + use of it. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorValidate( - HFCURSOR hCursor - // [IN] Handle to a cursor. - ) + HFCURSOR hCursor) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { diff --git a/flaim/src/fqeval.cpp b/flaim/src/fqeval.cpp index e97957f..011a4d8 100644 --- a/flaim/src/fqeval.cpp +++ b/flaim/src/fqeval.cpp @@ -1,2271 +1,3652 @@ -//------------------------------------------------------------------------- -// Desc: Query evaluation -// Tabs: 3 -// -// Copyright (c) 1994-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fqeval.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -extern FQ_OPERATION * FQ_DoOperation[]; - -FSTATIC FLMUINT flmCurEvalTrueFalse( - FQATOM_p pElm); - -FSTATIC RCODE flmCurGetAtomFromRec( - FDB * pDb, - POOL * pPool, - FQATOM_p pTreeAtom, - FlmRecord * pRecord, - QTYPES eFldType, - FLMBOOL bGetAtomVals, - FQATOM_p pResult, - FLMBOOL bHaveKey); - -FSTATIC RCODE flmFieldIterate( - FDB * pDb, - POOL * pPool, - QTYPES eFldType, - FQNODE_p pOpCB, - FlmRecord * pRecord, - FLMBOOL bHaveKey, - FLMBOOL bGetAtomVals, - FLMUINT uiAction, - FQATOM_p pResult); - -FSTATIC RCODE flmCurEvalArithOp( - FDB * pDb, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, - FQNODE_p pQNode, - QTYPES eOp, - FLMBOOL bGetNewField, - FLMBOOL bHaveKey, - FQATOM_p pResult); - -FSTATIC RCODE flmCurEvalLogicalOp( - FDB * pDb, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, - FQNODE_p pQNode, - QTYPES eOp, - FLMBOOL bHaveKey, - FQATOM_p pResult); - -#define IS_EXPORT_PTR( e) \ - ((e) == FLM_TEXT_VAL || (e) == FLM_BINARY_VAL) - -/**************************************************************************** -Desc: Evaluates a list of QATOM elements, and returns a complex boolean - based on their contents. -Ret: FLM_TRUE if all elements have nonzero numerics or nonempty buffers. - FLM_FALSE if all contents are zero or empty. - FLM_UNK if any QATOM is of type FLM_UNKNOWN. - Any combination of the preceeding values if their corresponding criteria - are met. -****************************************************************************/ -FSTATIC FLMUINT flmCurEvalTrueFalse( - FQATOM_p pQAtom - ) -{ - FQATOM_p pTmpQAtom; - FLMUINT uiTrueFalse = 0; - - for (pTmpQAtom = pQAtom; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext) - { - if (IS_BUF_TYPE( pTmpQAtom->eType)) - { - if (pTmpQAtom->uiBufLen > 0) - { - uiTrueFalse |= FLM_TRUE; - } - else - { - uiTrueFalse |= FLM_FALSE; - } - } - else - { - switch (pTmpQAtom->eType) - { - case FLM_BOOL_VAL: - uiTrueFalse |= pTmpQAtom->val.uiBool; - break; - case FLM_UNKNOWN: - uiTrueFalse |= FLM_UNK; - break; - case FLM_INT32_VAL: - if (pTmpQAtom->val.iVal) - { - uiTrueFalse |= FLM_TRUE; - } - else - { - uiTrueFalse |= FLM_FALSE; - } - break; - case FLM_UINT32_VAL: - if (pTmpQAtom->val.uiVal) - { - uiTrueFalse |= FLM_TRUE; - } - else - { - uiTrueFalse |= FLM_FALSE; - } - break; - default: - goto Exit; - } - } - if (uiTrueFalse == FLM_ALL_BOOL) - { - break; - } - } - -Exit: - return( uiTrueFalse); -} - -/**************************************************************************** -Desc: Gets a value from the passed-in record field and stuffs it into the - passed-in FQATOM. -****************************************************************************/ -RCODE flmCurGetAtomVal( - FlmRecord * pRecord, - void * pField, - POOL * pPool, - QTYPES eFldType, - FQATOM_p pResult) -{ - RCODE rc = FERR_OK; - FLMUINT uiType = 0; - - if (pField) - { - uiType = pRecord->getDataType( pField); - if (uiType == FLM_BLOB_TYPE) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - switch (eFldType) - { - case FLM_TEXT_VAL: - - if (!pField) // Use default value - { - pResult->uiBufLen = 0; - pResult->val.pucBuf = NULL; - } - else - { - pResult->uiBufLen = pRecord->getDataLength( pField); - if (pResult->uiBufLen) - { - pResult->val.pucBuf = (FLMBYTE *)pRecord->getDataPtr( pField); - pResult->pFieldRec = pRecord; - } - else - { - if ((pResult->val.pucBuf = - (FLMBYTE *)GedPoolAlloc( pPool, 1)) == NULL) - { - rc = RC_SET( FERR_MEM); - break; - } - pResult->val.pucBuf [0] = 0; - } - } - pResult->eType = FLM_TEXT_VAL; - break; - - case FLM_INT32_VAL: - if (!pField || pRecord->getDataLength( pField) == 0) // Use default value - { - pResult->val.iVal = 0; - } - else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE) - { - if (RC_BAD( rc = pRecord->getINT( pField, &pResult->val.iVal))) - { - - // Try to get the number as an unsigned value. For purposes of - // evaluation, the 32-bit value will still be treated as - // signed. In effect, the large positive value is wrapped and - // becomes a negative value. - - if (rc == FERR_CONV_NUM_OVERFLOW) - { - rc = pRecord->getUINT( pField, &pResult->val.uiVal); - eFldType = FLM_UINT32_VAL; - } - } - } - else if (uiType == FLM_CONTEXT_TYPE) - { - rc = pRecord->getUINT( pField, &pResult->val.uiVal); - eFldType = FLM_UINT32_VAL; - } - else - { - rc = RC_SET( FERR_CONV_BAD_SRC_TYPE); - } - if (RC_OK( rc)) - { - pResult->eType = eFldType; - } - break; - case FLM_UINT32_VAL: - case FLM_REC_PTR_VAL: - if (!pField || pRecord->getDataLength( pField) == 0) // Use default value - { - pResult->val.uiVal = 0; - } - else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE) - { - if (RC_BAD( rc = pRecord->getUINT( pField, &pResult->val.uiVal))) - { - - // Try to get the number as a signed value. For purposes of - // evaluation, the 32-bit value will still be treated as - // unsigned. In effect, the negative value is wrapped and - // becomes a large positive value. - - if (rc == FERR_CONV_NUM_UNDERFLOW) - { - rc = pRecord->getINT( pField, &pResult->val.iVal); - eFldType = FLM_INT32_VAL; - } - } - } - else if (uiType == FLM_CONTEXT_TYPE) - { - rc = pRecord->getUINT( pField, &(pResult->val.uiVal)); - } - else - { - rc = RC_SET( FERR_CONV_BAD_SRC_TYPE); - } - if (RC_OK( rc)) - { - pResult->eType = eFldType; - } - break; - case FLM_BINARY_VAL: - if (pField) - { - pResult->uiBufLen = pRecord->getDataLength( pField); - } - else - { - pResult->uiBufLen = 0; - } - if (!pResult->uiBufLen) - { - pResult->val.pucBuf = NULL; - } - else - { - pResult->val.pucBuf = (FLMBYTE *)pRecord->getDataPtr( pField); - pResult->pFieldRec = pRecord; - } - pResult->eType = FLM_BINARY_VAL; - break; - - // No type -- use the type in the passed-in node. - - case NO_TYPE: - - // At this point, if we are attempting to get a default - // value, but don't know the type, it is because both - // sides of the operand are unknown, so we need to return - // no type. - - if (!pField) - { - pResult->eType = NO_TYPE; - } - else - { - switch (uiType) - { - case FLM_TEXT_TYPE: - { - pResult->uiBufLen = pRecord->getDataLength( pField); - if (pResult->uiBufLen) - { - pResult->val.pucBuf = (FLMBYTE *)pRecord->getDataPtr( pField); - pResult->pFieldRec = pRecord; - } - else - { - if ((pResult->val.pucBuf = - (FLMBYTE *)GedPoolAlloc( pPool, 1)) == NULL) - { - rc = RC_SET( FERR_MEM); - break; - } - pResult->val.pucBuf[ 0] = 0; - } - pResult->eType = FLM_TEXT_VAL; - break; - } - - case FLM_BINARY_TYPE: - if (pField) - { - pResult->uiBufLen = pRecord->getDataLength( pField); - } - else - { - pResult->uiBufLen = 0; - } - if (!pResult->uiBufLen) - { - pResult->val.pucBuf = NULL; - } - else - { - pResult->val.pucBuf = (FLMBYTE *)pRecord->getDataPtr( pField); - pResult->pFieldRec = pRecord; - } - pResult->eType = FLM_BINARY_VAL; - break; - - case FLM_NUMBER_TYPE: - if (RC_OK( rc = pRecord->getUINT( pField, &pResult->val.uiVal))) - { - pResult->eType = FLM_UINT32_VAL; - } - else if (RC_OK( rc = pRecord->getINT( pField, &pResult->val.iVal))) - { - pResult->eType = FLM_INT32_VAL; - } - break; - - case FLM_CONTEXT_TYPE: - if (RC_OK( rc = pRecord->getUINT( pField, &(pResult->val.uiVal)))) - { - pResult->eType = FLM_UINT32_VAL; - } - break; - } - } - break; - default: - rc = RC_SET( FERR_CURSOR_SYNTAX); - break; - } - -Exit: - pResult->uiFlags &= ~(FLM_IS_RIGHT_TRUNCATED_DATA | - FLM_IS_LEFT_TRUNCATED_DATA); - if (RC_OK( rc) && pField) - { - if (pRecord->isRightTruncated( pField)) - { - pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; - } - if (pRecord->isLeftTruncated( pField)) - { - pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; - } - } - - return( rc); -} - -/**************************************************************************** -Desc: Given a list of FQATOMs containing alternate field paths, finds those - field paths in a compound record and creates a list of FQATOMs from the - contents of those paths. -Ret: -****************************************************************************/ -FSTATIC RCODE flmCurGetAtomFromRec( - FDB * pDb, - POOL * pPool, - FQATOM_p pTreeAtom, - FlmRecord * pRecord, // may be NULL - for testing query on empty rec - QTYPES eFldType, - FLMBOOL bGetAtomVals, - FQATOM_p pResult, - FLMBOOL bHaveKey) -{ - RCODE rc = FERR_OK; - FQATOM_p pTmpResult = NULL; - void * pvField; - void * pvLastLevelOneField; - FLMUINT * puiFldPath; - FLMUINT uiCurrFieldPath[ GED_MAXLVLNUM + 1]; - FLMUINT uiFieldLevel; - FLMUINT uiTmp; - FLMUINT uiLeafFldNum; - FLMUINT uiRecFldNum; - FLMBOOL bFound; - FLMBOOL bSavedInvisTrans; - FLMUINT uiResult; - FLMBOOL bPathFromRoot; - FLMBOOL bUseFieldIdLookupTable; - FLMUINT * puiPToCPath; - FLMUINT uiHighestLevel; - FLMUINT uiLevelOneFieldId; - - pResult->eType = NO_TYPE; - if (pTreeAtom->val.QueryFld.puiFldPath [0] == FLM_MISSING_FIELD_TAG) - { - goto Exit; - } - if (!pRecord) - { - goto Exit; - } - - flmAssert( !pTreeAtom->pNext); - puiFldPath = pTreeAtom->val.QueryFld.puiFldPath; - puiPToCPath = pTreeAtom->val.QueryFld.puiPToCPath; - uiLevelOneFieldId = puiPToCPath [1]; - - // We are only going to do the path to root optimation if - // the field path is specified as having to be from the root (FLM_ROOTED_PATH) - // and it goes down to at least level 1 in the tree, and our record - // has a field id table in it. - - bPathFromRoot = (!bHaveKey && - (pTreeAtom->uiFlags & FLM_ROOTED_PATH)) - ? TRUE - : FALSE; - bUseFieldIdLookupTable = (bPathFromRoot && - pRecord->fieldIdTableEnabled() && - uiLevelOneFieldId) - ? TRUE - : FALSE; - if (*puiFldPath == FLM_RECID_FIELD) - { - pResult->eType = FLM_UINT32_VAL; - pResult->val.uiVal = pRecord->getID(); - goto Exit; - } - pvField = pRecord->root(); - uiFieldLevel = 0; - if (bPathFromRoot) - { - // Determine the highest level we need to go down to in the record. - - uiHighestLevel = 1; - while (puiPToCPath [uiHighestLevel + 1]) - { - uiHighestLevel++; - } - if (puiPToCPath [0] != pRecord->getFieldID( pvField)) - { - goto Exit; - } - if (bUseFieldIdLookupTable) - { - if ((pvLastLevelOneField = - pRecord->findLevelOneField( uiLevelOneFieldId, FALSE)) == NULL) - { - goto Exit; - } - uiCurrFieldPath [0] = puiPToCPath [0]; - pvField = pvLastLevelOneField; - uiFieldLevel = 1; - } - } - uiLeafFldNum = puiFldPath[ 0]; - for (;;) - { - uiRecFldNum = pRecord->getFieldID( pvField); - uiCurrFieldPath[ uiFieldLevel] = uiRecFldNum; - - // When we are doing path from root, we only need to traverse - // back up when we are on a field that is exactly at the highest level - // we can go down to in the tree - no need to check any others. - // If we are not doing bPathFromRoot, we check all node paths. - - if (uiRecFldNum == uiLeafFldNum && - (!bPathFromRoot || uiFieldLevel == uiHighestLevel)) - { - bFound = TRUE; - - // We already know that puiFldPath[0] matches - it is the same - // as uiLeafFldNum. Traverse back up the tree and see if - // the rest of the path matches. - - for (uiTmp = 1; puiFldPath[ uiTmp]; uiTmp++) - { - if (!uiFieldLevel) - { - bFound = FALSE; - break; - } - uiFieldLevel--; - if (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiFieldLevel]) - { - bFound = FALSE; - break; - } - } - - // Found field in proper path. Get the value if requested, - // otherwise set the result to FLM_TRUE and exit. If a - // callback is set, do that first to see if it is REALLY - // found. - - if (bFound && pTreeAtom->val.QueryFld.fnGetField) - { - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pTreeAtom->val.QueryFld.fnGetField( - pTreeAtom->val.QueryFld.pvUserData, pRecord, - (HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath, - FLM_FLD_VALIDATE, NULL, &pvField, &uiResult); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( rc)) - { - goto Exit; - } - if (uiResult == FLM_FALSE) - { - bFound = FALSE; - } - else if (uiResult == FLM_UNK) - { - if (bHaveKey) - { - - // bHaveKey means we are evaluating a key. There - // should only be one occurrence of the field in the - // key in this case. If the callback does not know - // if the field really exists, we must defer judgement - // on this one until we can fetch the record. Hence, - // we force the result to be UNKNOWN. Note that it - // must be set to UNKNOWN, even if this is a field exists - // predicate (!bGetAtomVals). If we set it to NO_TYPE - // and fall through to exist, it would get converted to - // a FLM_BOOL_VAL of FALSE, which is NOT what we - // want. - - pResult->eType = FLM_UNKNOWN; - pResult->uiFlags = pTreeAtom->uiFlags & - ~(FLM_IS_RIGHT_TRUNCATED_DATA | - FLM_IS_LEFT_TRUNCATED_DATA); - if (pvField) - { - if (pRecord->isRightTruncated( pvField)) - { - pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; - } - if (pRecord->isLeftTruncated( pvField)) - { - pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; - } - } - - // Better not be multiple results in this case because - // we are evaluating a key. - - flmAssert( pResult->pNext == NULL); - pResult->pNext = NULL; - goto Exit; - } - else - { - bFound = FALSE; - } - } - } - - if (bFound) - { - if (!bGetAtomVals) - { - pResult->eType = FLM_BOOL_VAL; - pResult->val.uiBool = FLM_TRUE; - goto Exit; - } - if (!pTmpResult) - { - pTmpResult = pResult; - } - else if (pTmpResult->eType) - { - if ((pTmpResult->pNext = - (FQATOM_p)GedPoolCalloc( pPool, sizeof( FQATOM))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTmpResult = pTmpResult->pNext; - } - pTmpResult->uiFlags = pTreeAtom->uiFlags; - if ((rc = flmCurGetAtomVal( pRecord, pvField, pPool, eFldType, - pTmpResult)) == FERR_CURSOR_SYNTAX) - { - goto Exit; - } - } - } - - // Get the next field to process. If bPathFromRoot is set, we will skip - // any fields that are at too high of levels in the record. - // If bUseFieldIdLookupTable is set, it means - // that when we get back up to level one fields, we should call the - // API to get the next level one field. - - for (;;) - { - if ((pvField = pRecord->next( pvField)) == NULL) - { - break; - } - uiFieldLevel = pRecord->getLevel( pvField); - if (!bPathFromRoot) - { - break; - } - if (uiFieldLevel > uiHighestLevel) - { - continue; - } - if (bUseFieldIdLookupTable && uiFieldLevel == 1) - { - pvLastLevelOneField = pvField = pRecord->nextLevelOneField( - pvLastLevelOneField); - } - break; - } - - // If the end of the record has been reached, and the last field - // value searched for was not found, unlink it from the result list. - - if (!pvField) - { - if (pTmpResult && pTmpResult != pResult && - pTmpResult->eType == NO_TYPE) - { - FQATOM_p pTmp; - - for (pTmp = pResult; - pTmp && pTmp->pNext != pTmpResult; - pTmp = pTmp->pNext) - { - ; - } - pTmp->pNext = NULL; - } - break; - } - } - -Exit: - - // If no match was found anywhere, set the result to FLM_UNKNOWN if field - // content was requested, or FLM_FALSE if field existence was to be tested. - - if (pResult->eType == NO_TYPE) - { - if (bGetAtomVals && !bHaveKey && - !pTreeAtom->val.QueryFld.fnGetField && - (pTreeAtom->uiFlags & FLM_USE_DEFAULT_VALUE)) - { - rc = flmCurGetAtomVal( pRecord, NULL, pPool, eFldType, pResult); - } - else - { - if (bGetAtomVals || bHaveKey) - { - pResult->eType = FLM_UNKNOWN; - } - else - { - pResult->eType = FLM_BOOL_VAL; - pResult->val.uiBool = FLM_FALSE; - } - pResult->uiFlags = pTreeAtom->uiFlags; - } - } - return( rc); -} - -/**************************************************************************** -Desc: Iterate to the next occurrance of a field. -****************************************************************************/ -FSTATIC RCODE flmFieldIterate( - FDB * pDb, - POOL * pPool, - QTYPES eFldType, - FQNODE_p pOpCB, - FlmRecord * pRecord, // may be NULL - for testing query on empty rec. - FLMBOOL bHaveKey, - FLMBOOL bGetAtomVals, - FLMUINT uiAction, - FQATOM_p pResult) -{ - RCODE rc = FERR_OK; - FlmRecord * pFieldRec = NULL; - void * pField = NULL; - FLMBOOL bSavedInvisTrans; - - if (bHaveKey) - { - // bHaveKey is TRUE when we are evaluating a key instead of the - // full record. In this case, it will not be possible for the - // callback function to get all of the values - so we simply - // return unknown, which will be handled by the outside. If the - // entire query evaluates to unknown, FLAIM will fetch the - // record and evaluate the entire thing. This is the safe - // route to take in this case. - - pResult->eType = FLM_UNKNOWN; - } - else - { - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pOpCB->pQAtom->val.QueryFld.fnGetField( - pOpCB->pQAtom->val.QueryFld.pvUserData, pRecord, (HFDB)pDb, - pOpCB->pQAtom->val.QueryFld.puiFldPath, uiAction, - &pFieldRec, &pField, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( rc)) - { - goto Exit; - } - if (!pField) - { - if (!bGetAtomVals) - { - pResult->eType = FLM_BOOL_VAL; - pResult->val.uiBool = FLM_FALSE; - } - else - { - if ((pOpCB->pQAtom->uiFlags & FLM_USE_DEFAULT_VALUE) && - (uiAction == FLM_FLD_FIRST)) - { - if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, NULL, - pPool, eFldType, pResult))) - { - goto Exit; - } - } - else - { - pResult->eType = FLM_UNKNOWN; - } - } - } - else - { - if (!bGetAtomVals) - { - pResult->eType = FLM_BOOL_VAL; - pResult->val.uiBool = FLM_TRUE; - } - else if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, - pField, pPool, eFldType, pResult))) - { - goto Exit; - } - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Performs arithmetic operations on stack element lists. -Notes: This is a recursive routine. -****************************************************************************/ -FSTATIC RCODE flmCurEvalArithOp( - FDB * pDb, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, - FQNODE_p pQNode, - QTYPES eOp, - FLMBOOL bGetNewField, - FLMBOOL bHaveKey, - FQATOM_p pResult - ) -{ - RCODE rc = FERR_OK; - FQNODE_p pTmpQNode; - FQATOM Lhs; - FQATOM Rhs; - FQATOM_p pTmpQAtom; - FQATOM_p pRhs; - FQATOM_p pLhs; - FQATOM_p pFirstRhs; - QTYPES eType; - QTYPES eFldType = NO_TYPE; - FLMBOOL bSecondOperand = FALSE; - FQNODE_p pRightOpCB = NULL; - FQNODE_p pLeftOpCB = NULL; - FQNODE_p pOpCB = NULL; - POOL * pTmpPool = &pDb->TempPool; - FLMBOOL bSavedInvisTrans; - RCODE TempRc; - - if ((pTmpQNode = pQNode->pChild) == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - return( rc); - } - - pLhs = &Lhs; - pRhs = &Rhs; - - pLhs->pNext = NULL; - pLhs->pFieldRec = NULL; - pLhs->eType = NO_TYPE; - pLhs->uiBufLen = 0; - pLhs->val.uiVal = 0; - - pRhs->pNext = NULL; - pRhs->pFieldRec = NULL; - pRhs->eType = NO_TYPE; - pRhs->uiBufLen = 0; - pRhs->val.uiVal = 0; - - // Get the two operands (may be multiple values per operand) - - pTmpQAtom = pLhs; -Get_Operand: - eType = GET_QNODE_TYPE( pTmpQNode); - if (IS_FLD_CB( eType, pTmpQNode)) - { - eType = FLM_CB_FLD; - } - if (IS_VAL( eType)) - { - if (bSecondOperand) - { - pRhs = pTmpQNode->pQAtom; - } - else - { - pLhs = pTmpQNode->pQAtom; - } - } - else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD) - { - if (bSecondOperand) - { - eFldType = pLhs->eType; - if (eType == FLM_CB_FLD) - { - pOpCB = pRightOpCB = pTmpQNode; - } - } - else - { - if (pTmpQNode->pNextSib == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib); - - if (eType == FLM_CB_FLD) - { - pOpCB = pLeftOpCB = pTmpQNode; - } - } - - if (!IS_VAL( eFldType)) - { - eFldType = NO_TYPE; - } - - if (eType == FLM_CB_FLD) - { - // Get the first occurrence of the field. - - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB, - pRecord, bHaveKey, TRUE, - FLM_FLD_FIRST, pTmpQAtom))) - { - goto Exit; - } - } - else - { - if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool, - pTmpQNode->pQAtom, pRecord, - eFldType, TRUE, pTmpQAtom, bHaveKey))) - { - goto Exit; - } - } - } - else if (IS_ARITH_OP( eType)) - { - - // Recursive call - - if (RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, - pTmpQNode, eType, bGetNewField, bHaveKey, - pTmpQAtom))) - { - goto Exit; - } - } - else - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - if (!bSecondOperand) - { - if (eOp == FLM_NEG_OP) - { - pResult = pTmpQAtom; - flmCurDoNeg( pResult); - goto Exit; - } - else - { - if (pTmpQNode->pNextSib == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - pTmpQNode = pTmpQNode->pNextSib; - pTmpQAtom = pRhs; - bSecondOperand = TRUE; - goto Get_Operand; - } - } - - // Now do the operation using our operators - - pFirstRhs = pRhs; - pTmpQAtom = pResult; - - for (;;) - { - if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN) - { - pTmpQAtom->eType = FLM_UNKNOWN; - } - else - { - int opPos = (eOp - FIRST_ARITH_OP) * 9; - - QTYPES lhType = (QTYPES)(pLhs->eType - FLM_UINT32_VAL); - QTYPES rhType = (QTYPES)(pRhs->eType - FLM_UINT32_VAL); - - if (lhType > 2 || rhType > 2) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - opPos += (lhType * 3) + rhType; - - // Call through a table the operation handling routine. - - rc = (FQ_DoOperation[ opPos ]) ( pLhs, pRhs, pTmpQAtom ); - } - - // Doing contextless, do them all - loop through right hand - // operands, then left hand operands. - - // Get the next right hand operand. - - if (!pRightOpCB) - { - pRhs = pRhs->pNext; - } - else if (pRhs->eType == FLM_UNKNOWN) - { - pRhs = NULL; - } - else - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pRightOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_NEXT, pRhs))) - { - goto Exit; - } - if (pRhs->eType == FLM_UNKNOWN) - { - pRhs = NULL; - } - } - - // If no more right hand side, get the next left hand - // side, and reset the right hand side. - - if (!pRhs) - { - if (!pLeftOpCB) - { - pLhs = pLhs->pNext; - } - else if (pLhs->eType == FLM_UNKNOWN) - { - pLhs = NULL; - } - else - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pLeftOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_NEXT, pLhs))) - { - goto Exit; - } - if (pLhs->eType == FLM_UNKNOWN) - { - pLhs = NULL; - } - } - if (!pLhs) - { - break; - } - - // Reset the right hand side back to first. - - if (pRightOpCB) - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pRightOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_FIRST, pRhs))) - { - goto Exit; - } - } - else - { - pRhs = pFirstRhs; - } - } - - // Set up for next result - - if ((pTmpQAtom->pNext = - (FQATOM_p)GedPoolCalloc( pTmpPool, sizeof( FQATOM))) - == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pTmpQAtom = pTmpQAtom->pNext; - } - -Exit: - - // Clean up any field callbacks. - - if (pLeftOpCB) - { - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField( - pLeftOpCB->pQAtom->val.QueryFld.pvUserData, - NULL, (HFDB)pDb, - pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( TempRc)) - { - if (RC_OK( rc)) - { - rc = TempRc; - } - } - } - if (pRightOpCB) - { - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField( - pRightOpCB->pQAtom->val.QueryFld.pvUserData, NULL, - (HFDB)pDb, - pRightOpCB->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( TempRc)) - { - if (RC_OK( rc)) - { - rc = TempRc; - } - } - } - return( rc); -} - -/**************************************************************************** -Desc: Performs a comparison operation on two operands, - one or both of which can be FLM_UNKNOWN. -****************************************************************************/ -void flmCompareOperands( - FLMUINT uiLang, - FQATOM_p pLhs, - FQATOM_p pRhs, - QTYPES eOp, - FLMBOOL bResolveUnknown, - FLMBOOL bForEvery, - FLMBOOL bNotted, - FLMBOOL bHaveKey, - FLMUINT * puiTrueFalse) -{ - if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN) - { - - // If we are not resolving predicates with unknown operands, - // return FLM_UNK. - - if (bHaveKey || !bResolveUnknown) - { - *puiTrueFalse = FLM_UNK; - } - else if (bNotted) - { - - // If bNotted is TRUE, the result will be inverted on the outside, - // so we need to set it to the opposite of what we want it to - // ultimately be. - - *puiTrueFalse = (bForEvery - ? FLM_FALSE // will be changed to FLM_TRUE on outside - : FLM_TRUE); // will be changed to FLM_FALSE on outside - - - } - else - { - *puiTrueFalse = (bForEvery - ? FLM_TRUE - : FLM_FALSE); - } - } - - // At this point, both operands are known to be present. The comparison - // will therefore be performed according to the operator specified. - - else - { - switch( eOp) - { - case FLM_EQ_OP: - - // OPTIMIZATION: for UINT32 compares avoid func call by doing - // compare here! - - if (pLhs->eType == FLM_UINT32_VAL && - pRhs->eType == FLM_UINT32_VAL) - { - *puiTrueFalse = (FQ_COMPARE( pLhs->val.uiVal, - pRhs->val.uiVal) == 0) - ? FLM_TRUE - : FLM_FALSE; - } - else - { - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, - pRhs, uiLang) == 0) - ? FLM_TRUE - : FLM_FALSE; - } - break; - - case FLM_MATCH_OP: - if ((pLhs->uiFlags & FLM_WILD) || (pRhs->uiFlags & FLM_WILD)) - { - *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, - FALSE, FALSE); - } - else - { - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, - pRhs, uiLang) == 0) - ? FLM_TRUE - : FLM_FALSE; - } - break; - - case FLM_MATCH_BEGIN_OP: - *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, - FALSE, TRUE); - break; - - case FLM_MATCH_END_OP: - *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, - TRUE, FALSE); - break; - - case FLM_NE_OP: - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, pRhs, uiLang) != 0) - ? FLM_TRUE - : FLM_FALSE; - break; - - case FLM_LT_OP: - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, pRhs, uiLang) < 0) - ? FLM_TRUE - : FLM_FALSE; - break; - - case FLM_LE_OP: - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, pRhs, uiLang) <= 0) - ? FLM_TRUE - : FLM_FALSE; - break; - - case FLM_GT_OP: - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, pRhs, uiLang) > 0) - ? FLM_TRUE - : FLM_FALSE; - break; - - case FLM_GE_OP: - *puiTrueFalse = (flmCurDoRelationalOp( pLhs, pRhs, uiLang) >= 0) - ? FLM_TRUE - : FLM_FALSE; - break; - - case FLM_CONTAINS_OP: - *puiTrueFalse = flmCurDoContainsOp( pLhs, pRhs, uiLang); - break; - - default: - *puiTrueFalse = 0; // Syntax error. - flmAssert( 0); - break; - } - } -} - -/**************************************************************************** -Desc: Performs relational operations on stack elements. -****************************************************************************/ -RCODE flmCurEvalCompareOp( - FDB * pDb, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, // maybe NULL - for testing query on empty rec. - FQNODE_p pQNode, - QTYPES eOp, - FLMBOOL bHaveKey, - FQATOM_p pResult - ) -{ - RCODE rc = FERR_OK; - FQNODE_p pTmpQNode; - FQATOM_p pTmpQAtom; - FQATOM_p pLhs; - FQATOM_p pRhs; - FQATOM_p pFirstRhs; - FQATOM Lhs; - FQATOM Rhs; - QTYPES wTmpOp = eOp; - QTYPES eType; - QTYPES eFldType = NO_TYPE; - FLMUINT uiTrueFalse = 0; - FLMBOOL bSecondOperand; - FLMBOOL bSwitchOperands = FALSE; - FLMBOOL bGetNewField = FALSE; - FLMBOOL bRightTruncated = FALSE; - FLMBOOL bNotted = (pQNode->uiStatus & FLM_NOTTED) ? TRUE : FALSE; - FLMBOOL bResolveUnknown = (pQNode->uiStatus & FLM_RESOLVE_UNK) - ? TRUE : FALSE; - FLMBOOL bForEvery = - (pQNode->uiStatus & FLM_FOR_EVERY) ? TRUE : FALSE; - FQNODE_p pRightOpCB = NULL; - FQNODE_p pLeftOpCB = NULL; - FQNODE_p pOpCB = NULL; - RCODE TempRc; - FLMBOOL bSavedInvisTrans; - POOL * pTmpPool = &pDb->TempPool; - void * pvMark = GedPoolMark( pTmpPool); - - pResult->eType = FLM_BOOL_VAL; - pResult->pNext = NULL; - pResult->val.uiBool = 0; - if (pQNode->pChild == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - pLhs = &Lhs; - pRhs = &Rhs; - - pTmpQNode = pQNode->pChild; - bSecondOperand = FALSE; - f_memset( &Lhs, 0, sizeof( FQATOM )); - f_memset( &Rhs, 0, sizeof( FQATOM )); - pLhs->eType = pRhs->eType = NO_TYPE; - - // Get the two operands from the stack or passed-in record node - - pTmpQAtom = pLhs; -Get_Operand: - eType = GET_QNODE_TYPE( pTmpQNode); - if (IS_FLD_CB( eType, pTmpQNode)) - { - eType = FLM_CB_FLD; - } - if (IS_VAL( eType)) - { - if (bSecondOperand) - { - pRhs = pTmpQNode->pQAtom; - } - else - { - pLhs = pTmpQNode->pQAtom; - bSwitchOperands = TRUE; - } - } - else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD) - { - if (bSecondOperand) - { - eFldType = pLhs->eType; - if (eType == FLM_CB_FLD) - { - pOpCB = pRightOpCB = pTmpQNode; - } - } - else - { - if (pTmpQNode->pNextSib == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib); - if (eType == FLM_CB_FLD) - { - pOpCB = pLeftOpCB = pTmpQNode; - } - } - if (!IS_VAL( eFldType)) - { - eFldType = NO_TYPE; - } - - if (eType == FLM_CB_FLD) - { - - // Get the first occurrence of the field. - - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB, - pRecord, bHaveKey, TRUE, - FLM_FLD_FIRST, pTmpQAtom))) - { - goto Exit; - } - if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) - { - bRightTruncated = TRUE; - } - } - else - { - if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool, - pTmpQNode->pQAtom, pRecord, eFldType, - TRUE, pTmpQAtom, bHaveKey))) - { - goto Exit; - } - if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) - { - bRightTruncated = TRUE; - } - } - - // Check to see if this field is a substring field in the index. If it - // is, and it is not the first substring value in the field, and we are - // doing a match begin or match operator, return FLM_FALSE - we cannot - // evaluate anything except first substrings in these two cases. - // NOTE: If we are evaluating a key and this is a callback field, - // we don't need to worry about this condition, because the CB field - // will have been set up to return unknown. - - if (bHaveKey && - (pTmpQAtom->uiFlags & FLM_IS_LEFT_TRUNCATED_DATA) && - (eOp == FLM_MATCH_OP || eOp == FLM_MATCH_BEGIN_OP)) - { - pResult->val.uiBool = FLM_FALSE; - goto Exit; - } - } - else if (IS_ARITH_OP( eType)) - { - if( RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, - pTmpQNode, eType, bGetNewField, - bHaveKey, pTmpQAtom))) - { - goto Exit; - } - } - else - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - if (!bSecondOperand) - { - if (pTmpQNode->pNextSib == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - pTmpQNode = pTmpQNode->pNextSib; - pTmpQAtom = pRhs; - bSecondOperand = TRUE; - goto Get_Operand; - } - - // If necessary, reverse the operator to render the expression in the form - // . - - if (bSwitchOperands) - { - if (REVERSIBLE( eOp)) - { - wTmpOp = DO_REVERSE( eOp); - pLhs = &Rhs; - pRhs = &Lhs; - } - else - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - } - - // Now do the operation using our operators. - - pFirstRhs = pRhs; - for (;;) - { - FLMBOOL bDoComp = TRUE; - - // If this key piece is truncated, and the selection criteria can't be - // evaluated as a result, read the record and start again. - // NOTE: this will only happen if the field type is text or binary. - - if (bHaveKey && - bRightTruncated && - pRhs->eType != FLM_UNKNOWN && - pLhs->eType != FLM_UNKNOWN) - { - - // VISIT: - // We should optimized to flunk or pass text compares. The problems come - // with comparing only up to the first wildcard. - - if( pLhs->eType != FLM_BINARY_VAL) - { - uiTrueFalse = FLM_UNK; - } - else - { - FLMINT iCompVal; - - // We better only compare binary types here. - - flmAssert( pRhs->eType == FLM_BINARY_VAL); - - iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, - f_min( pLhs->uiBufLen, pRhs->uiBufLen)); - - if( !iCompVal) - { - // Lhs is the truncated key. If its length is <= to the length - // of the Rhs, comparison must continue by fetching the record. - // So, we set uiTrueFalse to FLM_UNK. Otherwise, we know that - // the Lhs length is greater than the Rhs, so we are able to - // complete the comparison even though the key is truncated. - - if( pLhs->uiBufLen <= pRhs->uiBufLen) - { - uiTrueFalse = FLM_UNK; - } - else - { - iCompVal = 1; - } - } - - // iCompVal == 0 has been handled above. This means that - // uiTrueFalse has been set to FLM_UNK. - - if( iCompVal) - { - switch (eOp) - { - case FLM_NE_OP: - // We know that iCompVal != 0 - uiTrueFalse = FLM_TRUE; - break; - case FLM_GT_OP: - case FLM_GE_OP: - uiTrueFalse = (iCompVal > 0) ? FLM_TRUE : FLM_FALSE; - break; - case FLM_LT_OP: - case FLM_LE_OP: - uiTrueFalse = (iCompVal < 0) ? FLM_TRUE : FLM_FALSE; - break; - case FLM_EQ_OP: - default: - // We know that iCompVal != 0 - uiTrueFalse = FLM_FALSE; - break; - } - } - bDoComp = FALSE; - } - } - else - { - flmCompareOperands( pSubQuery->uiLanguage, pLhs, pRhs, eOp, - bResolveUnknown, bForEvery, bNotted, - bHaveKey, &uiTrueFalse); - } - - if (bNotted) - { - uiTrueFalse = (uiTrueFalse == FLM_TRUE) - ? FLM_FALSE - : (uiTrueFalse == FLM_FALSE) - ? FLM_TRUE - : FLM_UNK; - } - - // For index keys - validate that the field is correct if the - // compare returned true. Otherwise, set the result to unknown. - // VISIT: This will not work for index keys that have more than - // one field that needs to be validated. - - if (bDoComp && - eType == FLM_FLD_PATH && - uiTrueFalse == FLM_TRUE && - bHaveKey) - { - FQATOM_p pTreeAtom = pTmpQNode->pQAtom; - FLMUINT uiResult; - void * pField = NULL; - - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pTreeAtom->val.QueryFld.fnGetField( - pTreeAtom->val.QueryFld.pvUserData, pRecord, - (HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath, - FLM_FLD_VALIDATE, NULL, &pField, &uiResult); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( rc)) - { - goto Exit; - } - else if (uiResult == FLM_UNK) - { - uiTrueFalse = FLM_UNK; - } - else if (uiResult == FLM_FALSE) - { - uiTrueFalse = FLM_FALSE; - } - } - - pResult->val.uiBool = uiTrueFalse; - - // Doing contextless, see if we need to process any more. - // If the FOR EVERY flag is TRUE (universal quantifier), we - // quit when we see a FALSE. If the FOR EVERY flag is FALSE - // (existential quantifier), we quit when we see a TRUE. - - if ((bForEvery && uiTrueFalse == FLM_FALSE) || - (!bForEvery && uiTrueFalse == FLM_TRUE)) - { - break; - } - - // Get the next right hand operand. - - if (!pRightOpCB) - { - pRhs = pRhs->pNext; - } - else if (pRhs->eType == FLM_UNKNOWN) - { - pRhs = NULL; - } - else - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pRightOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_NEXT, pRhs))) - { - goto Exit; - } - if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) - { - bRightTruncated = TRUE; - } - if (pRhs->eType == FLM_UNKNOWN) - { - pRhs = NULL; - } - } - - // If no more right hand side, get the next left hand - // side, and reset the right hand side. - - if (!pRhs) - { - if (!pLeftOpCB) - { - pLhs = pLhs->pNext; - } - else if (pLhs->eType == FLM_UNKNOWN) - { - pLhs = NULL; - } - else - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pLeftOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_NEXT, pLhs))) - { - goto Exit; - } - if (pLhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) - { - bRightTruncated = TRUE; - } - if (pLhs->eType == FLM_UNKNOWN) - { - pLhs = NULL; - } - } - if (!pLhs) - { - break; - } - - // Reset the right hand side to the first. - - if (pRightOpCB) - { - if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, - pRightOpCB, pRecord, bHaveKey, - TRUE, FLM_FLD_FIRST, pRhs))) - { - goto Exit; - } - if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) - { - bRightTruncated = TRUE; - } - } - else - { - pRhs = pFirstRhs; - } - } - } - -Exit: - - // Clean up any field callbacks. - - if (pLeftOpCB) - { - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField( - pLeftOpCB->pQAtom->val.QueryFld.pvUserData, - NULL, (HFDB)pDb, - pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( TempRc)) - { - if (RC_OK( rc)) - { - rc = TempRc; - } - } - } - if (pRightOpCB) - { - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField( - pRightOpCB->pQAtom->val.QueryFld.pvUserData, - NULL, (HFDB)pDb, - pRightOpCB->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( TempRc)) - { - if (RC_OK( rc)) - { - rc = TempRc; - } - } - } - GedPoolReset( pTmpPool, pvMark); - return( rc); -} - -/**************************************************************************** -Desc: Performs logical AND or OR operations -****************************************************************************/ -FSTATIC RCODE flmCurEvalLogicalOp( - FDB * pDb, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, - FQNODE_p pQNode, - QTYPES eOp, - FLMBOOL bHaveKey, - FQATOM_p pResult - ) -{ - RCODE rc = FERR_OK; - FQATOM TmpQAtom; - FQNODE_p pTmpQNode; - FQATOM_p pTmpQAtom; - QTYPES eType; - FLMBOOL bSavedInvisTrans; - FLMUINT uiTrueFalse; - RCODE TempRc; - - pResult->eType = FLM_BOOL_VAL; - pResult->pNext = NULL; - pResult->val.uiBool = 0; - - if (pQNode->pChild == NULL) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - FLM_SET_RESULT( pQNode->uiStatus, 0); - pTmpQNode = pQNode->pChild; - -Get_Operand: - - // Get the operand to process - - pTmpQAtom = &TmpQAtom; - pTmpQAtom->pNext = NULL; - pTmpQAtom->pFieldRec = NULL; - pTmpQAtom->eType = NO_TYPE; - pTmpQAtom->uiBufLen = 0; - pTmpQAtom->val.uiVal = 0; - - eType = GET_QNODE_TYPE( pTmpQNode); - if (IS_FLD_CB( eType, pTmpQNode)) - { - eType = FLM_CB_FLD; - } - if (IS_VAL( eType)) - { - pTmpQAtom = pTmpQNode->pQAtom; - } - else if (eType == FLM_CB_FLD) - { - - // Get the first occurrence of the field. - - if (RC_OK( rc = flmFieldIterate( pDb, &pDb->TempPool, NO_TYPE, - pTmpQNode, pRecord, bHaveKey, FALSE, - FLM_FLD_FIRST, pTmpQAtom))) - { - if (pTmpQNode->uiStatus & FLM_NOTTED && - pTmpQAtom->eType == FLM_BOOL_VAL) - { - pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE) - ? FLM_FALSE - : FLM_TRUE; - } - } - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pTmpQNode->pQAtom->val.QueryFld.fnGetField( - pTmpQNode->pQAtom->val.QueryFld.pvUserData, - NULL, (HFDB)pDb, - pTmpQNode->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - - if (RC_BAD( TempRc) && RC_OK( rc)) - { - rc = TempRc; - } - if (RC_BAD( rc)) - { - goto Exit; - } - } - else if (eType == FLM_FLD_PATH) - { - if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, &pDb->TempPool, - pTmpQNode->pQAtom, pRecord, NO_TYPE, FALSE, - pTmpQAtom, bHaveKey))) - { - goto Exit; - } - - // NOTE: pTmpQAtom could come back from this as an UNKNOWN now, - // even though we are testing for field existence. This could - // happen when we are testing a key and we have a callback, but - // the callback cannot tell if the field instance is actually - // present or not. - - if ((pTmpQNode->uiStatus & FLM_NOTTED) && - (pTmpQAtom->eType == FLM_BOOL_VAL)) - { - pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE) - ? FLM_FALSE - : FLM_TRUE; - } - } - else if (IS_LOG_OP( eType)) - { - - // Traverse down the tree. - - pQNode = pTmpQNode; - eOp = eType; - FLM_SET_RESULT( pQNode->uiStatus, 0); - pTmpQNode = pTmpQNode->pChild; - goto Get_Operand; - } - else if (IS_COMPARE_OP( eType)) - { - if (RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, - pTmpQNode, eType, bHaveKey, pTmpQAtom))) - { - goto Exit; - } - } - else if (eType == FLM_USER_PREDICATE) - { - if (bHaveKey) - { - - // Don't want to do the callback if we only have a key - because - // the callback won't have access to all of the values from - // here. The safe thing is to just return unknown. - - pResult->eType = FLM_UNKNOWN; - goto Exit; - } - else - { - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pTmpQNode->pQAtom->val.pPredicate->testRecord( - (HFDB)pDb, pRecord, pRecord->getID(), - &pTmpQAtom->val.uiBool); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( rc)) - { - goto Exit; - } - pTmpQAtom->eType = FLM_BOOL_VAL; - } - } - else - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - // See what our TRUE/FALSE result is. - - uiTrueFalse = flmCurEvalTrueFalse( pTmpQAtom); - - // Traverse back up the tree, ORing or ANDing or NOTing - // this result as necessary. - - for (;;) - { - - // If ANDing and we have a FALSE result or ORing and - // we have a TRUE result, the result can simply be - // propagated up the tree. - - if ((eOp == FLM_AND_OP && uiTrueFalse == FLM_FALSE) || - (eOp == FLM_OR_OP && uiTrueFalse == FLM_TRUE)) - { - - // We are done if we can go no higher in the tree. - - pTmpQNode = pQNode; - if ((pQNode = pQNode->pParent) == NULL) - { - break; - } - eOp = GET_QNODE_TYPE( pQNode); - } - else if (pTmpQNode->pNextSib) - { - - // Can only be one operand of a NOT operator. - - flmAssert( eOp != FLM_NOT_OP); - - // Save the left-hand side result into pQNode->uiStatus - - FLM_SET_RESULT( pQNode->uiStatus, uiTrueFalse); - pTmpQNode = pTmpQNode->pNextSib; - goto Get_Operand; - } - else // Processing results of right hand operand - { - FLMUINT uiRhs; - - if (eOp == FLM_AND_OP) - { - - // FALSE case for AND operator has already been - // handled up above. - - flmAssert( uiTrueFalse != FLM_FALSE); - - // AND the results from the left-hand side. - // Get left-hand side result from pQNode. - - uiRhs = uiTrueFalse; - uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus); - - // Perform logical AND operation. - - if (uiRhs & FLM_FALSE) - { - uiTrueFalse |= FLM_FALSE; - } - if (uiRhs & FLM_UNK) - { - uiTrueFalse |= FLM_UNK; - } - - // If both left hand side and right hand side do - // not have FLM_TRUE set, we must turn it off. - - if ((uiTrueFalse & FLM_TRUE) && - (!(uiRhs & FLM_TRUE))) - { - uiTrueFalse &= (~(FLM_TRUE)); - } - } - else if (eOp == FLM_OR_OP) - { - // TRUE case for OR operator better have been - // handled up above. - - flmAssert( uiTrueFalse != FLM_TRUE); - - // OR the results from the left hand side. - // Get left-hand side result from pQNode. - - uiRhs = uiTrueFalse; - uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus); - - // Perform logical OR operation. - - if (uiRhs & FLM_TRUE) - { - uiTrueFalse |= FLM_TRUE; - } - if (uiRhs & FLM_UNK) - { - uiTrueFalse |= FLM_UNK; - } - - // If both left hand side and right hand side do - // not have FLM_FALSE set, we must turn it off. - - if ((uiTrueFalse & FLM_FALSE) && - (!(uiRhs & FLM_FALSE))) - { - uiTrueFalse &= (~(FLM_FALSE)); - } - } - else // (eOp == FLM_NOT_OP) - { - flmAssert( eOp == FLM_NOT_OP); - - // NOT the result - - if (uiTrueFalse == FLM_TRUE) - { - uiTrueFalse = FLM_FALSE; - } - else if (uiTrueFalse == FLM_FALSE) - { - uiTrueFalse = FLM_TRUE; - } - else if (uiTrueFalse == (FLM_UNK | FLM_TRUE)) - { - uiTrueFalse = FLM_FALSE | FLM_UNK; - } - else if (uiTrueFalse == (FLM_UNK | FLM_FALSE)) - { - uiTrueFalse = FLM_TRUE | FLM_UNK; - } - // Other cases are: - // FLM_TRUE | FLM_FALSE - Unchanged - // FLM_UNK - Unchanged - // FLM_UNK | FLM_TRUE | FLM_FALSE - Unchanged - // 0 - should not be possible at this point. - } - - // Traverse back up to the parent with this - // result. - - pTmpQNode = pQNode; - - // We are done if we are at the top of the tree. - - if ((pQNode = pQNode->pParent) == NULL) - { - break; - } - eOp = GET_QNODE_TYPE( pQNode); - } - } - - // At this point, we are done, because there is no higher to - // traverse back up in the tree. - - pResult->val.uiBool = uiTrueFalse; - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Checks a record that has been retrieved from the database in GEDCOM tree - format to see if it matches the criteria specified in the query stack. -Note: Note the two early returns. -****************************************************************************/ -RCODE flmCurEvalCriteria( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery, - FlmRecord * pRecord, // Points to the data record - FLMBOOL bHaveKey, // Evaluating key? - FLMUINT * puiResult // Returns FLM_TRUE if match. - ) -{ - RCODE rc = FERR_OK; - FQATOM Result; - QTYPES eType; - FDB_p pDb = pCursor->pDb; - FQNODE_p pQNode; - void * pTmpMark = GedPoolMark( &pDb->TempPool); - FLMUINT uiResult = 0; - FQNODE_p pOpCB = NULL; - RCODE TempRc; - - // By definition, a NULL record doesn't match selection criteria. - - if (!pRecord) - { - uiResult = FLM_FALSE; - goto Exit; - } - - // Record's container ID must match the cursor's - - if (pRecord->getContainerID() != pCursor->uiContainer) - { - uiResult = FLM_FALSE; - goto Exit; - } - - if (!pSubQuery->pTree) - { - uiResult = FLM_TRUE; - goto Exit; - } - - // First check the record type if necessary, then verify that there are - // search criteria to match against. - - if (pCursor->uiRecType) - { - void * pField = pRecord->root(); - - if (!pField || - pCursor->uiRecType != pRecord->getFieldID( pField)) - { - uiResult = FLM_FALSE; - goto Exit; - } - } - - pQNode = pSubQuery->pTree; - - f_memset( &Result, 0, sizeof( FQATOM)); - - eType = GET_QNODE_TYPE( pQNode); - if (IS_FLD_CB( eType, pQNode)) - { - eType = FLM_CB_FLD; - } - - if (IS_VAL( eType)) - { - uiResult = flmCurEvalTrueFalse( pQNode->pQAtom); - } - else if (eType == FLM_USER_PREDICATE) - { - if (bHaveKey) - { - // Don't want to do the callback if we only have a key - because - // the callback won't have access to all of the values from - // here. The safe thing is to just return unknown. - - uiResult = FLM_UNK; - rc = FERR_OK; - } - else - { - FLMBOOL bSavedInvisTrans; - CB_ENTER( pDb, &bSavedInvisTrans); - rc = pQNode->pQAtom->val.pPredicate->testRecord( - (HFDB)pDb, pRecord, - pRecord->getID(), &uiResult); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( rc)) - { - goto Exit; - } - } - } - else - { - if (eType == FLM_CB_FLD) - { - - // Get the first occurrence of the field. - - pOpCB = pQNode; - if (RC_BAD( rc = flmFieldIterate( pDb, &pDb->TempPool, - NO_TYPE, pQNode, pRecord, bHaveKey, FALSE, - FLM_FLD_FIRST, &Result))) - { - goto Exit; - } - if (pQNode->uiStatus & FLM_NOTTED && Result.eType == FLM_BOOL_VAL) - { - Result.val.uiBool = (Result.val.uiBool == FLM_TRUE) - ? FLM_FALSE - : FLM_TRUE; - } - } - else if (eType == FLM_FLD_PATH) - { - if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, - &pDb->TempPool, pQNode->pQAtom, pRecord, - NO_TYPE, FALSE, &Result, bHaveKey))) - { - goto Exit; - } - - // NOTE: Result could come back from this as an UNKNOWN now, - // even though we are testing for field existence. This could - // happen when we are testing a key and we have a callback, but - // the callback cannot tell if the field instance is actually - // present or not. - - if ((pQNode->uiStatus & FLM_NOTTED) && - (Result.eType == FLM_BOOL_VAL)) - { - Result.val.uiBool = (Result.val.uiBool == FLM_TRUE) - ? FLM_FALSE - : FLM_TRUE; - } - } - else if (IS_LOG_OP( eType)) - { - if (RC_BAD( rc = flmCurEvalLogicalOp( pDb, pSubQuery, pRecord, - pQNode, eType, bHaveKey, &Result))) - { - goto Exit; - } - } - else if (IS_COMPARE_OP( eType)) - { - if( RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, - pQNode, eType, bHaveKey, &Result))) - { - goto Exit; - } - } - else - { - uiResult = FLM_FALSE; - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - uiResult = flmCurEvalTrueFalse( &Result); - - if (!bHaveKey && uiResult == FLM_UNK) - { - uiResult = FLM_FALSE; - } - } - -Exit: - if (rc == FERR_EOF_HIT) - { - rc = FERR_OK; - } - - // Clean up any field callbacks. - - if (pOpCB) - { - FLMBOOL bSavedInvisTrans; - CB_ENTER( pDb, &bSavedInvisTrans); - TempRc = pOpCB->pQAtom->val.QueryFld.fnGetField( - pOpCB->pQAtom->val.QueryFld.pvUserData, - NULL, (HFDB)pDb, - pOpCB->pQAtom->val.QueryFld.puiFldPath, - FLM_FLD_RESET, NULL, NULL, NULL); - CB_EXIT( pDb, bSavedInvisTrans); - if (RC_BAD( TempRc)) - { - if (RC_OK( rc)) - { - rc = TempRc; - } - } - } - GedPoolReset( &pDb->TempPool, pTmpMark); - *puiResult = uiResult; - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Query evaluation +// Tabs: 3 +// +// Copyright (c) 1994-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fqeval.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC FLMUINT flmCurEvalTrueFalse( + FQATOM * pElm); + +FSTATIC RCODE flmCurGetAtomFromRec( + FDB * pDb, + POOL * pPool, + FQATOM * pTreeAtom, + FlmRecord * pRecord, + QTYPES eFldType, + FLMBOOL bGetAtomVals, + FQATOM * pResult, + FLMBOOL bHaveKey); + +FSTATIC RCODE flmFieldIterate( + FDB * pDb, + POOL * pPool, + QTYPES eFldType, + FQNODE * pOpCB, + FlmRecord * pRecord, + FLMBOOL bHaveKey, + FLMBOOL bGetAtomVals, + FLMUINT uiAction, + FQATOM * pResult); + +FSTATIC RCODE flmCurEvalArithOp( + FDB * pDb, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FQNODE * pQNode, + QTYPES eOp, + FLMBOOL bGetNewField, + FLMBOOL bHaveKey, + FQATOM * pResult); + +FSTATIC RCODE flmCurEvalLogicalOp( + FDB * pDb, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FQNODE * pQNode, + QTYPES eOp, + FLMBOOL bHaveKey, + FQATOM * pResult); + +FSTATIC RCODE OpSyntaxError( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUBitAND( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUBitOR( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUBitXOR( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpURMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSRMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRRMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpURDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSRDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRRDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUSMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSSMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSUMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpURPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSRPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRRPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpUSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpURMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpSRMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +FSTATIC RCODE OpRRMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult); + +#define IS_EXPORT_PTR(e) \ + ((e) == FLM_TEXT_VAL || (e) == FLM_BINARY_VAL) + +/**************************************************************************** +Desc: +****************************************************************************/ +FQ_OPERATION * FQ_DoOperation[((LAST_ARITH_OP - FIRST_ARITH_OP) + 1) * 9] = +{ + // BITAND + + OpUUBitAND, + OpUUBitAND, + OpSyntaxError, + OpUUBitAND, + OpUUBitAND, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + + // BITOR + + OpUUBitOR, + OpUUBitOR, + OpSyntaxError, + OpUUBitOR, + OpUUBitOR, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + + // BITXOR + + OpUUBitXOR, + OpUUBitXOR, + OpSyntaxError, + OpUUBitXOR, + OpUUBitXOR, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + + // MULT + + OpUUMult, + OpUSMult, + OpURMult, + OpSUMult, + OpSSMult, + OpSRMult, + OpRUMult, + OpRSMult, + OpRRMult, + + // DIV + + OpUUDiv, + OpUSDiv, + OpURDiv, + OpSUDiv, + OpSSDiv, + OpSRDiv, + OpRUDiv, + OpRSDiv, + OpRRDiv, + + // MOD + + OpUUMod, + OpUSMod, + OpSyntaxError, + OpSUMod, + OpSSMod, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + OpSyntaxError, + + // PLUS + + OpUUPlus, + OpUSPlus, + OpURPlus, + OpSUPlus, + OpSSPlus, + OpSRPlus, + OpRUPlus, + OpRSPlus, + OpRRPlus, + + // MINUS + + OpUUMinus, + OpUSMinus, + OpURMinus, + OpSUMinus, + OpSSMinus, + OpSRMinus, + OpRUMinus, + OpRSMinus, + OpRRMinus +}; + +/**************************************************************************** +Desc: Evaluates a list of QATOM elements, and returns a complex boolean + based on their contents. +Ret: FLM_TRUE if all elements have nonzero numerics or nonempty buffers. + FLM_FALSE if all contents are zero or empty. + FLM_UNK if any QATOM is of type FLM_UNKNOWN. + Any combination of the preceeding values if their corresponding + criteria are met. +****************************************************************************/ +FSTATIC FLMUINT flmCurEvalTrueFalse( + FQATOM * pQAtom) +{ + FQATOM * pTmpQAtom; + FLMUINT uiTrueFalse = 0; + + for (pTmpQAtom = pQAtom; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext) + { + if (IS_BUF_TYPE( pTmpQAtom->eType)) + { + if (pTmpQAtom->uiBufLen > 0) + { + uiTrueFalse |= FLM_TRUE; + } + else + { + uiTrueFalse |= FLM_FALSE; + } + } + else + { + switch (pTmpQAtom->eType) + { + case FLM_BOOL_VAL: + uiTrueFalse |= pTmpQAtom->val.uiBool; + break; + case FLM_UNKNOWN: + uiTrueFalse |= FLM_UNK; + break; + case FLM_INT32_VAL: + if (pTmpQAtom->val.iVal) + { + uiTrueFalse |= FLM_TRUE; + } + else + { + uiTrueFalse |= FLM_FALSE; + } + break; + case FLM_UINT32_VAL: + if (pTmpQAtom->val.uiVal) + { + uiTrueFalse |= FLM_TRUE; + } + else + { + uiTrueFalse |= FLM_FALSE; + } + break; + default: + goto Exit; + } + } + + if (uiTrueFalse == FLM_ALL_BOOL) + { + break; + } + } + +Exit: + + return (uiTrueFalse); +} + +/**************************************************************************** +Desc: Gets a value from the passed-in record field and stuffs it into the + passed-in FQATOM. +****************************************************************************/ +RCODE flmCurGetAtomVal( + FlmRecord * pRecord, + void * pField, + POOL * pPool, + QTYPES eFldType, + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FLMUINT uiType = 0; + + if (pField) + { + uiType = pRecord->getDataType( pField); + if (uiType == FLM_BLOB_TYPE) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + } + + switch (eFldType) + { + case FLM_TEXT_VAL: + { + if (!pField) + { + // Default value + + pResult->uiBufLen = 0; + pResult->val.pucBuf = NULL; + } + else + { + pResult->uiBufLen = pRecord->getDataLength( pField); + if (pResult->uiBufLen) + { + pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField); + pResult->pFieldRec = pRecord; + } + else + { + if ((pResult->val.pucBuf = (FLMBYTE *) GedPoolAlloc( + pPool, 1)) == NULL) + { + rc = RC_SET( FERR_MEM); + break; + } + + pResult->val.pucBuf[0] = 0; + } + } + + pResult->eType = FLM_TEXT_VAL; + break; + } + + case FLM_INT32_VAL: + { + if (!pField || pRecord->getDataLength( pField) == 0) + { + // Default value + + pResult->val.iVal = 0; + } + else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE) + { + if (RC_BAD( rc = pRecord->getINT( pField, &pResult->val.iVal))) + { + + // Try to get the number as an unsigned value. For purposes + // of evaluation, the 32-bit value will still be treated as + // signed. In effect, the large positive value is wrapped and + // becomes a negative value. + + if (rc == FERR_CONV_NUM_OVERFLOW) + { + rc = pRecord->getUINT( pField, &pResult->val.uiVal); + eFldType = FLM_UINT32_VAL; + } + } + } + else if (uiType == FLM_CONTEXT_TYPE) + { + rc = pRecord->getUINT( pField, &pResult->val.uiVal); + eFldType = FLM_UINT32_VAL; + } + else + { + rc = RC_SET( FERR_CONV_BAD_SRC_TYPE); + } + + if (RC_OK( rc)) + { + pResult->eType = eFldType; + } + break; + } + + case FLM_UINT32_VAL: + case FLM_REC_PTR_VAL: + { + if (!pField || pRecord->getDataLength( pField) == 0) + { + // Default value + + pResult->val.uiVal = 0; + } + else if (uiType == FLM_NUMBER_TYPE || uiType == FLM_TEXT_TYPE) + { + if (RC_BAD( rc = pRecord->getUINT( pField, &pResult->val.uiVal))) + { + + // Try to get the number as a signed value. For purposes of + // evaluation, the 32-bit value will still be treated as + // unsigned. In effect, the negative value is wrapped and + // becomes a large positive value. + + if (rc == FERR_CONV_NUM_UNDERFLOW) + { + rc = pRecord->getINT( pField, &pResult->val.iVal); + eFldType = FLM_INT32_VAL; + } + } + } + else if (uiType == FLM_CONTEXT_TYPE) + { + rc = pRecord->getUINT( pField, &(pResult->val.uiVal)); + } + else + { + rc = RC_SET( FERR_CONV_BAD_SRC_TYPE); + } + + if (RC_OK( rc)) + { + pResult->eType = eFldType; + } + break; + } + + case FLM_BINARY_VAL: + { + if (pField) + { + pResult->uiBufLen = pRecord->getDataLength( pField); + } + else + { + pResult->uiBufLen = 0; + } + + if (!pResult->uiBufLen) + { + pResult->val.pucBuf = NULL; + } + else + { + pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField); + pResult->pFieldRec = pRecord; + } + + pResult->eType = FLM_BINARY_VAL; + break; + } + + // No type -- use the type in the passed-in node. + + case NO_TYPE: + { + + // At this point, if we are attempting to get a default value, but + // don't know the type, it is because both sides of the operand are + // unknown, so we need to return no type. + + if (!pField) + { + pResult->eType = NO_TYPE; + } + else + { + switch (uiType) + { + case FLM_TEXT_TYPE: + { + pResult->uiBufLen = pRecord->getDataLength( pField); + if (pResult->uiBufLen) + { + pResult->val.pucBuf = (FLMBYTE *) pRecord->getDataPtr( pField); + pResult->pFieldRec = pRecord; + } + else + { + if ((pResult->val.pucBuf = (FLMBYTE *) GedPoolAlloc( + pPool, 1)) == NULL) + { + rc = RC_SET( FERR_MEM); + break; + } + + pResult->val.pucBuf[0] = 0; + } + + pResult->eType = FLM_TEXT_VAL; + break; + } + + case FLM_BINARY_TYPE: + { + if (pField) + { + pResult->uiBufLen = pRecord->getDataLength( pField); + } + else + { + pResult->uiBufLen = 0; + } + + if (!pResult->uiBufLen) + { + pResult->val.pucBuf = NULL; + } + else + { + pResult->val.pucBuf = + (FLMBYTE *) pRecord->getDataPtr( pField); + pResult->pFieldRec = pRecord; + } + + pResult->eType = FLM_BINARY_VAL; + break; + } + + case FLM_NUMBER_TYPE: + { + if (RC_OK( rc = pRecord->getUINT( pField, + &pResult->val.uiVal))) + { + pResult->eType = FLM_UINT32_VAL; + } + else if (RC_OK( rc = pRecord->getINT( pField, + &pResult->val.iVal))) + { + pResult->eType = FLM_INT32_VAL; + } + break; + } + + case FLM_CONTEXT_TYPE: + { + if (RC_OK( rc = pRecord->getUINT( pField, + &(pResult->val.uiVal)))) + { + pResult->eType = FLM_UINT32_VAL; + } + break; + } + } + } + break; + } + + default: + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + break; + } + } + +Exit: + + pResult->uiFlags &= + ~(FLM_IS_RIGHT_TRUNCATED_DATA | FLM_IS_LEFT_TRUNCATED_DATA); + + if (RC_OK( rc) && pField) + { + if (pRecord->isRightTruncated( pField)) + { + pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; + } + + if (pRecord->isLeftTruncated( pField)) + { + pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; + } + } + + return (rc); +} + +/**************************************************************************** +Desc: Given a list of FQATOMs containing alternate field paths, finds + those field paths in a compound record and creates a list of FQATOMs + from the contents of those paths. +****************************************************************************/ +FSTATIC RCODE flmCurGetAtomFromRec( + FDB * pDb, + POOL * pPool, + FQATOM * pTreeAtom, + FlmRecord * pRecord, + QTYPES eFldType, + FLMBOOL bGetAtomVals, + FQATOM * pResult, + FLMBOOL bHaveKey) +{ + RCODE rc = FERR_OK; + FQATOM * pTmpResult = NULL; + void * pvField; + void * pvLastLevelOneField; + FLMUINT * puiFldPath; + FLMUINT uiCurrFieldPath[ GED_MAXLVLNUM + 1]; + FLMUINT uiFieldLevel; + FLMUINT uiTmp; + FLMUINT uiLeafFldNum; + FLMUINT uiRecFldNum; + FLMBOOL bFound; + FLMBOOL bSavedInvisTrans; + FLMUINT uiResult; + FLMBOOL bPathFromRoot; + FLMBOOL bUseFieldIdLookupTable; + FLMUINT * puiPToCPath; + FLMUINT uiHighestLevel; + FLMUINT uiLevelOneFieldId; + + pResult->eType = NO_TYPE; + if (pTreeAtom->val.QueryFld.puiFldPath [0] == FLM_MISSING_FIELD_TAG) + { + goto Exit; + } + + if (!pRecord) + { + goto Exit; + } + + flmAssert( !pTreeAtom->pNext); + puiFldPath = pTreeAtom->val.QueryFld.puiFldPath; + puiPToCPath = pTreeAtom->val.QueryFld.puiPToCPath; + uiLevelOneFieldId = puiPToCPath [1]; + + // We are only going to do the path to root optimation if + // the field path is specified as having to be from the root (FLM_ROOTED_PATH) + // and it goes down to at least level 1 in the tree, and our record + // has a field id table in it. + + bPathFromRoot = (!bHaveKey && + (pTreeAtom->uiFlags & FLM_ROOTED_PATH)) + ? TRUE + : FALSE; + + bUseFieldIdLookupTable = (bPathFromRoot && + pRecord->fieldIdTableEnabled() && + uiLevelOneFieldId) + ? TRUE + : FALSE; + + if (*puiFldPath == FLM_RECID_FIELD) + { + pResult->eType = FLM_UINT32_VAL; + pResult->val.uiVal = pRecord->getID(); + goto Exit; + } + + pvField = pRecord->root(); + uiFieldLevel = 0; + + if (bPathFromRoot) + { + // Determine the highest level we need to go down to in the record. + + uiHighestLevel = 1; + while (puiPToCPath [uiHighestLevel + 1]) + { + uiHighestLevel++; + } + + if (puiPToCPath [0] != pRecord->getFieldID( pvField)) + { + goto Exit; + } + + if (bUseFieldIdLookupTable) + { + if ((pvLastLevelOneField = + pRecord->findLevelOneField( uiLevelOneFieldId, FALSE)) == NULL) + { + goto Exit; + } + + uiCurrFieldPath [0] = puiPToCPath [0]; + pvField = pvLastLevelOneField; + uiFieldLevel = 1; + } + } + + uiLeafFldNum = puiFldPath[ 0]; + for (;;) + { + uiRecFldNum = pRecord->getFieldID( pvField); + uiCurrFieldPath[ uiFieldLevel] = uiRecFldNum; + + // When we are doing path from root, we only need to traverse + // back up when we are on a field that is exactly at the highest level + // we can go down to in the tree - no need to check any others. + // If we are not doing bPathFromRoot, we check all node paths. + + if (uiRecFldNum == uiLeafFldNum && + (!bPathFromRoot || uiFieldLevel == uiHighestLevel)) + { + bFound = TRUE; + + // We already know that puiFldPath[0] matches - it is the same + // as uiLeafFldNum. Traverse back up the tree and see if + // the rest of the path matches. + + for (uiTmp = 1; puiFldPath[ uiTmp]; uiTmp++) + { + if (!uiFieldLevel) + { + bFound = FALSE; + break; + } + + uiFieldLevel--; + + if (puiFldPath[ uiTmp] != uiCurrFieldPath[ uiFieldLevel]) + { + bFound = FALSE; + break; + } + } + + // Found field in proper path. Get the value if requested, + // otherwise set the result to FLM_TRUE and exit. If a + // callback is set, do that first to see if it is REALLY + // found. + + if (bFound && pTreeAtom->val.QueryFld.fnGetField) + { + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pTreeAtom->val.QueryFld.fnGetField( + pTreeAtom->val.QueryFld.pvUserData, pRecord, + (HFDB)pDb, pTreeAtom->val.QueryFld.puiFldPath, + FLM_FLD_VALIDATE, NULL, &pvField, &uiResult); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( rc)) + { + goto Exit; + } + + if (uiResult == FLM_FALSE) + { + bFound = FALSE; + } + else if (uiResult == FLM_UNK) + { + if (bHaveKey) + { + + // bHaveKey means we are evaluating a key. There + // should only be one occurrence of the field in the + // key in this case. If the callback does not know + // if the field really exists, we must defer judgement + // on this one until we can fetch the record. Hence, + // we force the result to be UNKNOWN. Note that it + // must be set to UNKNOWN, even if this is a field exists + // predicate (!bGetAtomVals). If we set it to NO_TYPE + // and fall through to exist, it would get converted to + // a FLM_BOOL_VAL of FALSE, which is NOT what we + // want. + + pResult->eType = FLM_UNKNOWN; + pResult->uiFlags = pTreeAtom->uiFlags & + ~(FLM_IS_RIGHT_TRUNCATED_DATA | + FLM_IS_LEFT_TRUNCATED_DATA); + if (pvField) + { + if (pRecord->isRightTruncated( pvField)) + { + pResult->uiFlags |= FLM_IS_RIGHT_TRUNCATED_DATA; + } + if (pRecord->isLeftTruncated( pvField)) + { + pResult->uiFlags |= FLM_IS_LEFT_TRUNCATED_DATA; + } + } + + // Better not be multiple results in this case because + // we are evaluating a key. + + flmAssert( pResult->pNext == NULL); + pResult->pNext = NULL; + goto Exit; + } + else + { + bFound = FALSE; + } + } + } + + if (bFound) + { + if (!bGetAtomVals) + { + pResult->eType = FLM_BOOL_VAL; + pResult->val.uiBool = FLM_TRUE; + goto Exit; + } + + if (!pTmpResult) + { + pTmpResult = pResult; + } + else if (pTmpResult->eType) + { + if ((pTmpResult->pNext = + (FQATOM *)GedPoolCalloc( pPool, sizeof( FQATOM))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + pTmpResult = pTmpResult->pNext; + } + + pTmpResult->uiFlags = pTreeAtom->uiFlags; + if ((rc = flmCurGetAtomVal( pRecord, pvField, pPool, eFldType, + pTmpResult)) == FERR_CURSOR_SYNTAX) + { + goto Exit; + } + } + } + + // Get the next field to process. If bPathFromRoot is set, we will skip + // any fields that are at too high of levels in the record. + // If bUseFieldIdLookupTable is set, it means + // that when we get back up to level one fields, we should call the + // API to get the next level one field. + + for (;;) + { + if ((pvField = pRecord->next( pvField)) == NULL) + { + break; + } + + uiFieldLevel = pRecord->getLevel( pvField); + + if (!bPathFromRoot) + { + break; + } + + if (uiFieldLevel > uiHighestLevel) + { + continue; + } + + if (bUseFieldIdLookupTable && uiFieldLevel == 1) + { + pvLastLevelOneField = pvField = pRecord->nextLevelOneField( + pvLastLevelOneField); + } + + break; + } + + // If the end of the record has been reached, and the last field + // value searched for was not found, unlink it from the result list. + + if (!pvField) + { + if (pTmpResult && pTmpResult != pResult && + pTmpResult->eType == NO_TYPE) + { + FQATOM * pTmp; + + for (pTmp = pResult; + pTmp && pTmp->pNext != pTmpResult; + pTmp = pTmp->pNext) + { + ; + } + pTmp->pNext = NULL; + } + break; + } + } + +Exit: + + // If no match was found anywhere, set the result to FLM_UNKNOWN if field + // content was requested, or FLM_FALSE if field existence was to be tested. + + if (pResult->eType == NO_TYPE) + { + if (bGetAtomVals && !bHaveKey && + !pTreeAtom->val.QueryFld.fnGetField && + (pTreeAtom->uiFlags & FLM_USE_DEFAULT_VALUE)) + { + rc = flmCurGetAtomVal( pRecord, NULL, pPool, eFldType, pResult); + } + else + { + if (bGetAtomVals || bHaveKey) + { + pResult->eType = FLM_UNKNOWN; + } + else + { + pResult->eType = FLM_BOOL_VAL; + pResult->val.uiBool = FLM_FALSE; + } + pResult->uiFlags = pTreeAtom->uiFlags; + } + } + + return( rc); +} + +/**************************************************************************** +Desc: Iterate to the next occurrance of a field. +****************************************************************************/ +FSTATIC RCODE flmFieldIterate( + FDB * pDb, + POOL * pPool, + QTYPES eFldType, + FQNODE * pOpCB, + FlmRecord * pRecord, + FLMBOOL bHaveKey, + FLMBOOL bGetAtomVals, + FLMUINT uiAction, + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FlmRecord * pFieldRec = NULL; + void * pField = NULL; + FLMBOOL bSavedInvisTrans; + + if (bHaveKey) + { + + // bHaveKey is TRUE when we are evaluating a key instead of the + // full record. In this case, it will not be possible for the + // callback function to get all of the values - so we simply return + // unknown, which will be handled by the outside. If the entire + // query evaluates to unknown, FLAIM will fetch the record and + // evaluate the entire thing. This is the safe route to take in this + // case. + + pResult->eType = FLM_UNKNOWN; + } + else + { + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pOpCB->pQAtom->val.QueryFld.fnGetField( + pOpCB->pQAtom->val.QueryFld.pvUserData, pRecord, (HFDB) pDb, + pOpCB->pQAtom->val.QueryFld.puiFldPath, uiAction, + &pFieldRec, &pField, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( rc)) + { + goto Exit; + } + + if (!pField) + { + if (!bGetAtomVals) + { + pResult->eType = FLM_BOOL_VAL; + pResult->val.uiBool = FLM_FALSE; + } + else + { + if ((pOpCB->pQAtom->uiFlags & FLM_USE_DEFAULT_VALUE) && + (uiAction == FLM_FLD_FIRST)) + { + if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, NULL, pPool, + eFldType, pResult))) + { + goto Exit; + } + } + else + { + pResult->eType = FLM_UNKNOWN; + } + } + } + else + { + if (!bGetAtomVals) + { + pResult->eType = FLM_BOOL_VAL; + pResult->val.uiBool = FLM_TRUE; + } + else if (RC_BAD( rc = flmCurGetAtomVal( pFieldRec, pField, pPool, + eFldType, pResult))) + { + goto Exit; + } + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Performs arithmetic operations on stack element lists. +****************************************************************************/ +FSTATIC RCODE flmCurEvalArithOp( + FDB * pDb, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FQNODE * pQNode, + QTYPES eOp, + FLMBOOL bGetNewField, + FLMBOOL bHaveKey, + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FQNODE * pTmpQNode; + FQATOM Lhs; + FQATOM Rhs; + FQATOM * pTmpQAtom; + FQATOM * pRhs; + FQATOM * pLhs; + FQATOM * pFirstRhs; + QTYPES eType; + QTYPES eFldType = NO_TYPE; + FLMBOOL bSecondOperand = FALSE; + FQNODE * pRightOpCB = NULL; + FQNODE * pLeftOpCB = NULL; + FQNODE * pOpCB = NULL; + POOL * pTmpPool = &pDb->TempPool; + FLMBOOL bSavedInvisTrans; + RCODE TempRc; + + if ((pTmpQNode = pQNode->pChild) == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + return (rc); + } + + pLhs = &Lhs; + pRhs = &Rhs; + + pLhs->pNext = NULL; + pLhs->pFieldRec = NULL; + pLhs->eType = NO_TYPE; + pLhs->uiBufLen = 0; + pLhs->val.uiVal = 0; + + pRhs->pNext = NULL; + pRhs->pFieldRec = NULL; + pRhs->eType = NO_TYPE; + pRhs->uiBufLen = 0; + pRhs->val.uiVal = 0; + + // Get the two operands (may be multiple values per operand) + + pTmpQAtom = pLhs; + +Get_Operand: + + eType = GET_QNODE_TYPE( pTmpQNode); + if (IS_FLD_CB( eType, pTmpQNode)) + { + eType = FLM_CB_FLD; + } + + if (IS_VAL( eType)) + { + if (bSecondOperand) + { + pRhs = pTmpQNode->pQAtom; + } + else + { + pLhs = pTmpQNode->pQAtom; + } + } + else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD) + { + if (bSecondOperand) + { + eFldType = pLhs->eType; + if (eType == FLM_CB_FLD) + { + pOpCB = pRightOpCB = pTmpQNode; + } + } + else + { + if (pTmpQNode->pNextSib == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib); + + if (eType == FLM_CB_FLD) + { + pOpCB = pLeftOpCB = pTmpQNode; + } + } + + if (!IS_VAL( eFldType)) + { + eFldType = NO_TYPE; + } + + if (eType == FLM_CB_FLD) + { + + // Get the first occurrence of the field. + + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB, + pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pTmpQAtom))) + { + goto Exit; + } + } + else + { + if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool, + pTmpQNode->pQAtom, pRecord, eFldType, TRUE, pTmpQAtom, + bHaveKey))) + { + goto Exit; + } + } + } + else if (IS_ARITH_OP( eType)) + { + + // Recursive call + + if (RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, pTmpQNode, + eType, bGetNewField, bHaveKey, pTmpQAtom))) + { + goto Exit; + } + } + else + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + if (!bSecondOperand) + { + if (eOp == FLM_NEG_OP) + { + pResult = pTmpQAtom; + flmCurDoNeg( pResult); + goto Exit; + } + else + { + if (pTmpQNode->pNextSib == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + pTmpQNode = pTmpQNode->pNextSib; + pTmpQAtom = pRhs; + bSecondOperand = TRUE; + goto Get_Operand; + } + } + + // Now do the operation using our operators + + pFirstRhs = pRhs; + pTmpQAtom = pResult; + + for (;;) + { + if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN) + { + pTmpQAtom->eType = FLM_UNKNOWN; + } + else + { + int opPos = (eOp - FIRST_ARITH_OP) * 9; + QTYPES lhType = (QTYPES) (pLhs->eType - FLM_UINT32_VAL); + QTYPES rhType = (QTYPES) (pRhs->eType - FLM_UINT32_VAL); + + if (lhType > 2 || rhType > 2) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + opPos += (lhType * 3) + rhType; + + // Call through a table the operation handling routine. + + rc = (FQ_DoOperation[opPos]) (pLhs, pRhs, pTmpQAtom); + } + + // Doing contextless, do them all - loop through right hand + // operands, then left hand operands. + // + // Get the next right hand operand. + + if (!pRightOpCB) + { + pRhs = pRhs->pNext; + } + else if (pRhs->eType == FLM_UNKNOWN) + { + pRhs = NULL; + } + else + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pRightOpCB, + pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pRhs))) + { + goto Exit; + } + + if (pRhs->eType == FLM_UNKNOWN) + { + pRhs = NULL; + } + } + + // If no more right hand side, get the next left hand side, and + // reset the right hand side. + + if (!pRhs) + { + if (!pLeftOpCB) + { + pLhs = pLhs->pNext; + } + else if (pLhs->eType == FLM_UNKNOWN) + { + pLhs = NULL; + } + else + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, + pLeftOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pLhs))) + { + goto Exit; + } + + if (pLhs->eType == FLM_UNKNOWN) + { + pLhs = NULL; + } + } + + if (!pLhs) + { + break; + } + + // Reset the right hand side back to first. + + if (pRightOpCB) + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, + pRightOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pRhs + ))) + { + goto Exit; + } + } + else + { + pRhs = pFirstRhs; + } + } + + // Set up for next result + + if ((pTmpQAtom->pNext = (FQATOM *) GedPoolCalloc( + pTmpPool, sizeof( FQATOM))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pTmpQAtom = pTmpQAtom->pNext; + } + +Exit: + + // Clean up any field callbacks. + + if (pLeftOpCB) + { + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField( + pLeftOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, + NULL, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( TempRc)) + { + if (RC_OK( rc)) + { + rc = TempRc; + } + } + } + + if (pRightOpCB) + { + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField( + pRightOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pRightOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, + NULL, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( TempRc)) + { + if (RC_OK( rc)) + { + rc = TempRc; + } + } + } + + return (rc); +} + +/**************************************************************************** +Desc: Performs a comparison operation on two operands, one or both of + which can be FLM_UNKNOWN. +****************************************************************************/ +void flmCompareOperands( + FLMUINT uiLang, + FQATOM * pLhs, + FQATOM * pRhs, + QTYPES eOp, + FLMBOOL bResolveUnknown, + FLMBOOL bForEvery, + FLMBOOL bNotted, + FLMBOOL bHaveKey, + FLMUINT * puiTrueFalse) +{ + if (pLhs->eType == FLM_UNKNOWN || pRhs->eType == FLM_UNKNOWN) + { + + // If we are not resolving predicates with unknown operands, return + // FLM_UNK. + + if (bHaveKey || !bResolveUnknown) + { + *puiTrueFalse = FLM_UNK; + } + else if (bNotted) + { + + // If bNotted is TRUE, the result will be inverted on the + // outside, so we need to set it to the opposite of what we want + // it to ultimately be. + + *puiTrueFalse = (bForEvery ? FLM_FALSE : FLM_TRUE); + } + else + { + *puiTrueFalse = (bForEvery ? FLM_TRUE : FLM_FALSE); + } + } + + // At this point, both operands are known to be present. The + // comparison will therefore be performed according to the operator + // specified. + + else + { + switch (eOp) + { + case FLM_EQ_OP: + { + + // OPTIMIZATION: for UINT32 compares avoid func call by doing + // compare here! + + if (pLhs->eType == FLM_UINT32_VAL && pRhs->eType == FLM_UINT32_VAL) + { + *puiTrueFalse = + (FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal) == 0) + ? FLM_TRUE : FLM_FALSE; + } + else + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) == 0) + ? FLM_TRUE : FLM_FALSE; + } + + break; + } + + case FLM_MATCH_OP: + { + if ((pLhs->uiFlags & FLM_WILD) || (pRhs->uiFlags & FLM_WILD)) + { + *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, FALSE, FALSE); + } + else + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) == 0) + ? FLM_TRUE : FLM_FALSE; + } + + break; + } + + case FLM_MATCH_BEGIN_OP: + { + *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, FALSE, TRUE); + break; + } + + case FLM_MATCH_END_OP: + { + *puiTrueFalse = flmCurDoMatchOp( pLhs, pRhs, uiLang, TRUE, FALSE); + break; + } + + case FLM_NE_OP: + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) != 0) + ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_LT_OP: + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) < 0) + ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_LE_OP: + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) <= 0) + ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_GT_OP: + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) > 0) + ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_GE_OP: + { + *puiTrueFalse = + (flmCurDoRelationalOp( pLhs, pRhs, uiLang) >= 0) + ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_CONTAINS_OP: + { + *puiTrueFalse = flmCurDoContainsOp( pLhs, pRhs, uiLang); + break; + } + + default: + { + // Syntax error. + + *puiTrueFalse = 0; + flmAssert( 0); + break; + } + } + } +} + +/**************************************************************************** +Desc: Performs relational operations on stack elements. +****************************************************************************/ +RCODE flmCurEvalCompareOp( + FDB * pDb, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FQNODE * pQNode, + QTYPES eOp, + FLMBOOL bHaveKey, + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FQNODE * pTmpQNode; + FQATOM * pTmpQAtom; + FQATOM * pLhs; + FQATOM * pRhs; + FQATOM * pFirstRhs; + FQATOM Lhs; + FQATOM Rhs; + QTYPES wTmpOp = eOp; + QTYPES eType; + QTYPES eFldType = NO_TYPE; + FLMUINT uiTrueFalse = 0; + FLMBOOL bSecondOperand; + FLMBOOL bSwitchOperands = FALSE; + FLMBOOL bGetNewField = FALSE; + FLMBOOL bRightTruncated = FALSE; + FLMBOOL bNotted = (pQNode->uiStatus & FLM_NOTTED) ? TRUE : FALSE; + FLMBOOL bResolveUnknown = (pQNode->uiStatus & FLM_RESOLVE_UNK) ? TRUE : FALSE; + FLMBOOL bForEvery = (pQNode->uiStatus & FLM_FOR_EVERY) ? TRUE : FALSE; + FQNODE * pRightOpCB = NULL; + FQNODE * pLeftOpCB = NULL; + FQNODE * pOpCB = NULL; + RCODE TempRc; + FLMBOOL bSavedInvisTrans; + POOL * pTmpPool = &pDb->TempPool; + void * pvMark = GedPoolMark( pTmpPool); + + pResult->eType = FLM_BOOL_VAL; + pResult->pNext = NULL; + pResult->val.uiBool = 0; + if (pQNode->pChild == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + pLhs = &Lhs; + pRhs = &Rhs; + + pTmpQNode = pQNode->pChild; + bSecondOperand = FALSE; + f_memset( &Lhs, 0, sizeof(FQATOM)); + f_memset( &Rhs, 0, sizeof(FQATOM)); + pLhs->eType = pRhs->eType = NO_TYPE; + + // Get the two operands from the stack or passed-in record node + + pTmpQAtom = pLhs; + +Get_Operand: + + eType = GET_QNODE_TYPE( pTmpQNode); + if (IS_FLD_CB( eType, pTmpQNode)) + { + eType = FLM_CB_FLD; + } + + if (IS_VAL( eType)) + { + if (bSecondOperand) + { + pRhs = pTmpQNode->pQAtom; + } + else + { + pLhs = pTmpQNode->pQAtom; + bSwitchOperands = TRUE; + } + } + else if (eType == FLM_FLD_PATH || eType == FLM_CB_FLD) + { + if (bSecondOperand) + { + eFldType = pLhs->eType; + if (eType == FLM_CB_FLD) + { + pOpCB = pRightOpCB = pTmpQNode; + } + } + else + { + if (pTmpQNode->pNextSib == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + eFldType = GET_QNODE_TYPE( pTmpQNode->pNextSib); + if (eType == FLM_CB_FLD) + { + pOpCB = pLeftOpCB = pTmpQNode; + } + } + + if (!IS_VAL( eFldType)) + { + eFldType = NO_TYPE; + } + + if (eType == FLM_CB_FLD) + { + + // Get the first occurrence of the field. + + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pOpCB, + pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pTmpQAtom))) + { + goto Exit; + } + + if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) + { + bRightTruncated = TRUE; + } + } + else + { + if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, pTmpPool, + pTmpQNode->pQAtom, pRecord, eFldType, TRUE, pTmpQAtom, + bHaveKey))) + { + goto Exit; + } + + if (pTmpQAtom->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) + { + bRightTruncated = TRUE; + } + } + + // Check to see if this field is a substring field in the index. If + // it is, and it is not the first substring value in the field, and + // we are doing a match begin or match operator, return FLM_FALSE - + // we cannot evaluate anything except first substrings in these two + // cases. NOTE: If we are evaluating a key and this is a callback + // field, we don't need to worry about this condition, because the + // CB field will have been set up to return unknown. + + if (bHaveKey && + (pTmpQAtom->uiFlags & FLM_IS_LEFT_TRUNCATED_DATA) && + (eOp == FLM_MATCH_OP || eOp == FLM_MATCH_BEGIN_OP)) + { + pResult->val.uiBool = FLM_FALSE; + goto Exit; + } + } + else if (IS_ARITH_OP( eType)) + { + if (RC_BAD( rc = flmCurEvalArithOp( pDb, pSubQuery, pRecord, pTmpQNode, + eType, bGetNewField, bHaveKey, pTmpQAtom))) + { + goto Exit; + } + } + else + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + if (!bSecondOperand) + { + if (pTmpQNode->pNextSib == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + pTmpQNode = pTmpQNode->pNextSib; + pTmpQAtom = pRhs; + bSecondOperand = TRUE; + goto Get_Operand; + } + + // If necessary, reverse the operator to render the expression in the + // form . + + if (bSwitchOperands) + { + if (REVERSIBLE( eOp)) + { + wTmpOp = DO_REVERSE( eOp); + pLhs = &Rhs; + pRhs = &Lhs; + } + else + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + } + + // Now do the operation using our operators. + + pFirstRhs = pRhs; + for (;;) + { + FLMBOOL bDoComp = TRUE; + + // If this key piece is truncated, and the selection criteria can't + // be evaluated as a result, read the record and start again. NOTE: + // this will only happen if the field type is text or binary. + + if (bHaveKey && + bRightTruncated && + pRhs->eType != FLM_UNKNOWN && + pLhs->eType != FLM_UNKNOWN) + { + + // VISIT: We should optimized to flunk or pass text compares. + // The problems come with comparing only up to the first + // wildcard. + + if (pLhs->eType != FLM_BINARY_VAL) + { + uiTrueFalse = FLM_UNK; + } + else + { + FLMINT iCompVal; + + // We better only compare binary types here. + + flmAssert( pRhs->eType == FLM_BINARY_VAL); + + iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, + f_min( pLhs->uiBufLen, pRhs->uiBufLen)); + + if (!iCompVal) + { + + // Lhs is the truncated key. If its length is <= to the + // length of the Rhs, comparison must continue by fetching + // the record. So, we set uiTrueFalse to FLM_UNK. + // Otherwise, we know that the Lhs length is greater than + // the Rhs, so we are able to complete the comparison even + // though the key is truncated. + + if (pLhs->uiBufLen <= pRhs->uiBufLen) + { + uiTrueFalse = FLM_UNK; + } + else + { + iCompVal = 1; + } + } + + // iCompVal == 0 has been handled above. This means that + // uiTrueFalse has been set to FLM_UNK. + + if (iCompVal) + { + switch (eOp) + { + case FLM_NE_OP: + { + + // We know that iCompVal != 0 + + uiTrueFalse = FLM_TRUE; + break; + } + + case FLM_GT_OP: + case FLM_GE_OP: + { + uiTrueFalse = (iCompVal > 0) ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_LT_OP: + case FLM_LE_OP: + { + uiTrueFalse = (iCompVal < 0) ? FLM_TRUE : FLM_FALSE; + break; + } + + case FLM_EQ_OP: + default: + { + // We know that iCompVal != 0 + + uiTrueFalse = FLM_FALSE; + break; + } + } + } + + bDoComp = FALSE; + } + } + else + { + flmCompareOperands( pSubQuery->uiLanguage, pLhs, pRhs, eOp, + bResolveUnknown, bForEvery, bNotted, bHaveKey, + &uiTrueFalse); + } + + if (bNotted) + { + uiTrueFalse = (uiTrueFalse == FLM_TRUE) + ? FLM_FALSE + : (uiTrueFalse == FLM_FALSE) + ? FLM_TRUE + : FLM_UNK; + } + + // For index keys - validate that the field is correct if the + // compare returned true. Otherwise, set the result to unknown. + // VISIT: This will not work for index keys that have more than one + // field that needs to be validated. + + if (bDoComp && eType == FLM_FLD_PATH && + uiTrueFalse == FLM_TRUE && bHaveKey) + { + FQATOM * pTreeAtom = pTmpQNode->pQAtom; + FLMUINT uiResult; + void * pField = NULL; + + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pTreeAtom->val.QueryFld.fnGetField( + pTreeAtom->val.QueryFld.pvUserData, pRecord, (HFDB) pDb, + pTreeAtom->val.QueryFld.puiFldPath, FLM_FLD_VALIDATE, NULL, + &pField, &uiResult); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( rc)) + { + goto Exit; + } + else if (uiResult == FLM_UNK) + { + uiTrueFalse = FLM_UNK; + } + else if (uiResult == FLM_FALSE) + { + uiTrueFalse = FLM_FALSE; + } + } + + pResult->val.uiBool = uiTrueFalse; + + // Doing contextless, see if we need to process any more. If the + // FOR EVERY flag is TRUE (universal quantifier), we quit when we + // see a FALSE. If the FOR EVERY flag is FALSE (existential + // quantifier), we quit when we see a TRUE. + + if ((bForEvery && uiTrueFalse == FLM_FALSE) || + (!bForEvery && uiTrueFalse == FLM_TRUE)) + { + break; + } + + // Get the next right hand operand. + + if (!pRightOpCB) + { + pRhs = pRhs->pNext; + } + else if (pRhs->eType == FLM_UNKNOWN) + { + pRhs = NULL; + } + else + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, pRightOpCB, + pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pRhs))) + { + goto Exit; + } + + if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) + { + bRightTruncated = TRUE; + } + + if (pRhs->eType == FLM_UNKNOWN) + { + pRhs = NULL; + } + } + + // If no more right hand side, get the next left hand side, and + // reset the right hand side. + + if (!pRhs) + { + if (!pLeftOpCB) + { + pLhs = pLhs->pNext; + } + else if (pLhs->eType == FLM_UNKNOWN) + { + pLhs = NULL; + } + else + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, + pLeftOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_NEXT, pLhs))) + { + goto Exit; + } + + if (pLhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) + { + bRightTruncated = TRUE; + } + + if (pLhs->eType == FLM_UNKNOWN) + { + pLhs = NULL; + } + } + + if (!pLhs) + { + break; + } + + // Reset the right hand side to the first. + + if (pRightOpCB) + { + if (RC_BAD( rc = flmFieldIterate( pDb, pTmpPool, eFldType, + pRightOpCB, pRecord, bHaveKey, TRUE, FLM_FLD_FIRST, pRhs))) + { + goto Exit; + } + + if (pRhs->uiFlags & FLM_IS_RIGHT_TRUNCATED_DATA) + { + bRightTruncated = TRUE; + } + } + else + { + pRhs = pFirstRhs; + } + } + } + +Exit: + + // Clean up any field callbacks. + + if (pLeftOpCB) + { + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pLeftOpCB->pQAtom->val.QueryFld.fnGetField( + pLeftOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pLeftOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, + NULL, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( TempRc)) + { + if (RC_OK( rc)) + { + rc = TempRc; + } + } + } + + if (pRightOpCB) + { + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pRightOpCB->pQAtom->val.QueryFld.fnGetField( + pRightOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pRightOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, + NULL, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + if (RC_BAD( TempRc)) + { + if (RC_OK( rc)) + { + rc = TempRc; + } + } + } + + GedPoolReset( pTmpPool, pvMark); + return (rc); +} + +/**************************************************************************** +Desc: Performs logical AND or OR operations +****************************************************************************/ +FSTATIC RCODE flmCurEvalLogicalOp( + FDB * pDb, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FQNODE * pQNode, + QTYPES eOp, + FLMBOOL bHaveKey, + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FQATOM TmpQAtom; + FQNODE * pTmpQNode; + FQATOM * pTmpQAtom; + QTYPES eType; + FLMBOOL bSavedInvisTrans; + FLMUINT uiTrueFalse; + RCODE TempRc; + + pResult->eType = FLM_BOOL_VAL; + pResult->pNext = NULL; + pResult->val.uiBool = 0; + + if (pQNode->pChild == NULL) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + FLM_SET_RESULT( pQNode->uiStatus, 0); + pTmpQNode = pQNode->pChild; + +Get_Operand: + + // Get the operand to process + + pTmpQAtom = &TmpQAtom; + pTmpQAtom->pNext = NULL; + pTmpQAtom->pFieldRec = NULL; + pTmpQAtom->eType = NO_TYPE; + pTmpQAtom->uiBufLen = 0; + pTmpQAtom->val.uiVal = 0; + + eType = GET_QNODE_TYPE( pTmpQNode); + if (IS_FLD_CB( eType, pTmpQNode)) + { + eType = FLM_CB_FLD; + } + + if (IS_VAL( eType)) + { + pTmpQAtom = pTmpQNode->pQAtom; + } + else if (eType == FLM_CB_FLD) + { + + // Get the first occurrence of the field. + + if (RC_OK( rc = flmFieldIterate( pDb, &pDb->TempPool, NO_TYPE, pTmpQNode, + pRecord, bHaveKey, FALSE, FLM_FLD_FIRST, pTmpQAtom))) + { + if (pTmpQNode->uiStatus & FLM_NOTTED && + pTmpQAtom->eType == FLM_BOOL_VAL) + { + pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE) + ? FLM_FALSE + : FLM_TRUE; + } + } + + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pTmpQNode->pQAtom->val.QueryFld.fnGetField( + pTmpQNode->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pTmpQNode->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, + NULL, NULL); + CB_EXIT( pDb, bSavedInvisTrans); + + if (RC_BAD( TempRc) && RC_OK( rc)) + { + rc = TempRc; + } + + if (RC_BAD( rc)) + { + goto Exit; + } + } + else if (eType == FLM_FLD_PATH) + { + if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, &pDb->TempPool, + pTmpQNode->pQAtom, pRecord, NO_TYPE, FALSE, pTmpQAtom, bHaveKey + ))) + { + goto Exit; + } + + // NOTE: pTmpQAtom could come back from this as an UNKNOWN now, + // even though we are testing for field existence. This could happen + // when we are testing a key and we have a callback, but the + // callback cannot tell if the field instance is actually present or + // not. + + if ((pTmpQNode->uiStatus & FLM_NOTTED) && + (pTmpQAtom->eType == FLM_BOOL_VAL)) + { + pTmpQAtom->val.uiBool = (pTmpQAtom->val.uiBool == FLM_TRUE) + ? FLM_FALSE + : FLM_TRUE; + } + } + else if (IS_LOG_OP( eType)) + { + + // Traverse down the tree. + + pQNode = pTmpQNode; + eOp = eType; + FLM_SET_RESULT( pQNode->uiStatus, 0); + pTmpQNode = pTmpQNode->pChild; + goto Get_Operand; + } + else if (IS_COMPARE_OP( eType)) + { + if (RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, pTmpQNode, + eType, bHaveKey, pTmpQAtom))) + { + goto Exit; + } + } + else if (eType == FLM_USER_PREDICATE) + { + if (bHaveKey) + { + + // Don't want to do the callback if we only have a key - because + // the callback won't have access to all of the values from here. + // The safe thing is to just return unknown. + + pResult->eType = FLM_UNKNOWN; + goto Exit; + } + else + { + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pTmpQNode->pQAtom->val.pPredicate->testRecord( + (HFDB) pDb, pRecord, pRecord->getID(), &pTmpQAtom->val.uiBool); + CB_EXIT( pDb, bSavedInvisTrans); + if (RC_BAD( rc)) + { + goto Exit; + } + + pTmpQAtom->eType = FLM_BOOL_VAL; + } + } + else + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + // See what our TRUE/FALSE result is. + + uiTrueFalse = flmCurEvalTrueFalse( pTmpQAtom); + + // Traverse back up the tree, ORing or ANDing or NOTing this result as + // necessary. + + for (;;) + { + + // If ANDing and we have a FALSE result or ORing and we have a TRUE + // result, the result can simply be propagated up the tree. + + if ((eOp == FLM_AND_OP && uiTrueFalse == FLM_FALSE) || + (eOp == FLM_OR_OP && uiTrueFalse == FLM_TRUE)) + { + + // We are done if we can go no higher in the tree. + + pTmpQNode = pQNode; + if ((pQNode = pQNode->pParent) == NULL) + { + break; + } + + eOp = GET_QNODE_TYPE( pQNode); + } + else if (pTmpQNode->pNextSib) + { + + // Can only be one operand of a NOT operator. + + flmAssert( eOp != FLM_NOT_OP); + + // Save the left-hand side result into pQNode->uiStatus + + FLM_SET_RESULT( pQNode->uiStatus, uiTrueFalse); + pTmpQNode = pTmpQNode->pNextSib; + goto Get_Operand; + } + else // Processing results of right hand operand + { + FLMUINT uiRhs; + + if (eOp == FLM_AND_OP) + { + + // FALSE case for AND operator has already been handled up + // above. + + flmAssert( uiTrueFalse != FLM_FALSE); + + // AND the results from the left-hand side. Get left-hand + // side result from pQNode. + + uiRhs = uiTrueFalse; + uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus); + + // Perform logical AND operation. + + if (uiRhs & FLM_FALSE) + { + uiTrueFalse |= FLM_FALSE; + } + + if (uiRhs & FLM_UNK) + { + uiTrueFalse |= FLM_UNK; + } + + // If both left hand side and right hand side do not have + // FLM_TRUE set, we must turn it off. + + if ((uiTrueFalse & FLM_TRUE) && (!(uiRhs & FLM_TRUE))) + { + uiTrueFalse &= (~(FLM_TRUE)); + } + } + else if (eOp == FLM_OR_OP) + { + + // TRUE case for OR operator better have been handled up + // above. + + flmAssert( uiTrueFalse != FLM_TRUE); + + // OR the results from the left hand side. Get left-hand side + // result from pQNode. + + uiRhs = uiTrueFalse; + uiTrueFalse = FLM_GET_RESULT( pQNode->uiStatus); + + // Perform logical OR operation. + + if (uiRhs & FLM_TRUE) + { + uiTrueFalse |= FLM_TRUE; + } + + if (uiRhs & FLM_UNK) + { + uiTrueFalse |= FLM_UNK; + } + + // If both left hand side and right hand side do not have + // FLM_FALSE set, we must turn it off. + + if ((uiTrueFalse & FLM_FALSE) && (!(uiRhs & FLM_FALSE))) + { + uiTrueFalse &= (~(FLM_FALSE)); + } + } + else // (eOp == FLM_NOT_OP) + { + flmAssert( eOp == FLM_NOT_OP); + + // NOT the result + + if (uiTrueFalse == FLM_TRUE) + { + uiTrueFalse = FLM_FALSE; + } + else if (uiTrueFalse == FLM_FALSE) + { + uiTrueFalse = FLM_TRUE; + } + else if (uiTrueFalse == (FLM_UNK | FLM_TRUE)) + { + uiTrueFalse = FLM_FALSE | FLM_UNK; + } + else if (uiTrueFalse == (FLM_UNK | FLM_FALSE)) + { + uiTrueFalse = FLM_TRUE | FLM_UNK; + } + } + + // Traverse back up to the parent with this result. + + pTmpQNode = pQNode; + + // We are done if we are at the top of the tree. + + if ((pQNode = pQNode->pParent) == NULL) + { + break; + } + + eOp = GET_QNODE_TYPE( pQNode); + } + } + + // At this point, we are done, because there is no higher to traverse + // back up in the tree. + + pResult->val.uiBool = uiTrueFalse; + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Checks a record that has been retrieved from the database + to see if it matches the criteria specified in the query + stack. +****************************************************************************/ +RCODE flmCurEvalCriteria( + CURSOR * pCursor, + SUBQUERY * pSubQuery, + FlmRecord * pRecord, + FLMBOOL bHaveKey, + FLMUINT * puiResult) +{ + RCODE rc = FERR_OK; + FQATOM Result; + QTYPES eType; + FDB * pDb = pCursor->pDb; + FQNODE * pQNode; + void * pTmpMark = GedPoolMark( &pDb->TempPool); + FLMUINT uiResult = 0; + FQNODE * pOpCB = NULL; + RCODE TempRc; + + // By definition, a NULL record doesn't match selection criteria. + + if (!pRecord) + { + uiResult = FLM_FALSE; + goto Exit; + } + + // Record's container ID must match the cursor's + + if (pRecord->getContainerID() != pCursor->uiContainer) + { + uiResult = FLM_FALSE; + goto Exit; + } + + if (!pSubQuery->pTree) + { + uiResult = FLM_TRUE; + goto Exit; + } + + // First check the record type if necessary, then verify that there + // are search criteria to match against. + + if (pCursor->uiRecType) + { + void * pField = pRecord->root(); + + if (!pField || pCursor->uiRecType != pRecord->getFieldID( pField)) + { + uiResult = FLM_FALSE; + goto Exit; + } + } + + pQNode = pSubQuery->pTree; + + f_memset( &Result, 0, sizeof(FQATOM)); + + eType = GET_QNODE_TYPE( pQNode); + if (IS_FLD_CB( eType, pQNode)) + { + eType = FLM_CB_FLD; + } + + if (IS_VAL( eType)) + { + uiResult = flmCurEvalTrueFalse( pQNode->pQAtom); + } + else if (eType == FLM_USER_PREDICATE) + { + if (bHaveKey) + { + + // Don't want to do the callback if we only have a key - because + // the callback won't have access to all of the values from here. + // The safe thing is to just return unknown. + + uiResult = FLM_UNK; + rc = FERR_OK; + } + else + { + FLMBOOL bSavedInvisTrans; + CB_ENTER( pDb, &bSavedInvisTrans); + rc = pQNode->pQAtom->val.pPredicate->testRecord( + (HFDB) pDb, pRecord, pRecord->getID(), &uiResult); + CB_EXIT( pDb, bSavedInvisTrans); + if (RC_BAD( rc)) + { + goto Exit; + } + } + } + else + { + if (eType == FLM_CB_FLD) + { + + // Get the first occurrence of the field. + + pOpCB = pQNode; + if (RC_BAD( rc = flmFieldIterate( pDb, &pDb->TempPool, NO_TYPE, pQNode, + pRecord, bHaveKey, FALSE, FLM_FLD_FIRST, &Result))) + { + goto Exit; + } + + if (pQNode->uiStatus & FLM_NOTTED && Result.eType == FLM_BOOL_VAL) + { + Result.val.uiBool = (Result.val.uiBool == FLM_TRUE) + ? FLM_FALSE + : FLM_TRUE; + } + } + else if (eType == FLM_FLD_PATH) + { + if (RC_BAD( rc = flmCurGetAtomFromRec( pDb, &pDb->TempPool, + pQNode->pQAtom, pRecord, NO_TYPE, FALSE, &Result, + bHaveKey))) + { + goto Exit; + } + + // NOTE: Result could come back from this as an UNKNOWN now, + // even though we are testing for field existence. This could + // happen when we are testing a key and we have a callback, but + // the callback cannot tell if the field instance is actually + // present or not. + + if ((pQNode->uiStatus & FLM_NOTTED) && (Result.eType == FLM_BOOL_VAL)) + { + Result.val.uiBool = (Result.val.uiBool == FLM_TRUE) + ? FLM_FALSE + : FLM_TRUE; + } + } + else if (IS_LOG_OP( eType)) + { + if (RC_BAD( rc = flmCurEvalLogicalOp( pDb, pSubQuery, pRecord, pQNode, + eType, bHaveKey, &Result))) + { + goto Exit; + } + } + else if (IS_COMPARE_OP( eType)) + { + if (RC_BAD( rc = flmCurEvalCompareOp( pDb, pSubQuery, pRecord, pQNode, + eType, bHaveKey, &Result))) + { + goto Exit; + } + } + else + { + uiResult = FLM_FALSE; + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + + uiResult = flmCurEvalTrueFalse( &Result); + + if (!bHaveKey && uiResult == FLM_UNK) + { + uiResult = FLM_FALSE; + } + } + +Exit: + + if (rc == FERR_EOF_HIT) + { + rc = FERR_OK; + } + + // Clean up any field callbacks. + + if (pOpCB) + { + FLMBOOL bSavedInvisTrans; + CB_ENTER( pDb, &bSavedInvisTrans); + TempRc = pOpCB->pQAtom->val.QueryFld.fnGetField( + pOpCB->pQAtom->val.QueryFld.pvUserData, NULL, (HFDB) pDb, + pOpCB->pQAtom->val.QueryFld.puiFldPath, FLM_FLD_RESET, NULL, NULL, + NULL); + CB_EXIT( pDb, bSavedInvisTrans); + if (RC_BAD( TempRc)) + { + if (RC_OK( rc)) + { + rc = TempRc; + } + } + } + + GedPoolReset( &pDb->TempPool, pTmpMark); + *puiResult = uiResult; + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSyntaxError( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + F_UNREFERENCED_PARM( pLhs); + F_UNREFERENCED_PARM( pRhs); + F_UNREFERENCED_PARM( pResult); + + return (RC_SET( FERR_CURSOR_SYNTAX)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUBitAND( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.uiVal = pLhs->val.uiVal & pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUBitOR( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.uiVal = pLhs->val.uiVal | pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUBitXOR( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.uiVal = pLhs->val.uiVal ^ pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.uiVal = pLhs->val.uiVal * pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.iVal = (FLMINT) pLhs->val.uiVal * pRhs->val.iVal; + pResult->eType = FLM_INT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.iVal = pLhs->val.iVal * pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.iVal = pLhs->val.iVal * (FLMINT) pRhs->val.uiVal; + pResult->eType = FLM_INT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpURMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRUMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSRMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRSMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRRMult( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.uiVal) + { + pResult->val.uiVal = pLhs->val.uiVal / pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + // Divide by ZERO case. + + pResult->val.uiVal = 0; + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.iVal) + { + pResult->val.iVal = (FLMINT) pLhs->val.uiVal / pRhs->val.iVal; + pResult->eType = FLM_INT32_VAL; + } + else + { + // Divide by ZERO case. + + pResult->val.uiVal = 0; + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.iVal) + { + pResult->val.iVal = pLhs->val.iVal / pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + else + { + pResult->val.uiVal = 0; // divide by ZERO case + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.uiVal) + { + pResult->val.iVal = pLhs->val.iVal / (FLMINT) pRhs->val.uiVal; + pResult->eType = FLM_INT32_VAL; + } + else // Divide by ZERO case - let's try not to crash. + { + pResult->val.uiVal = 0; + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpURDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRUDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSRDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRSDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRRDiv( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.uiVal != 0) + { + pResult->val.uiVal = pLhs->val.uiVal % pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.uiVal = 0; // MOD by ZERO case. + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUSMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.iVal != 0) + { + pResult->val.iVal = (FLMINT) pLhs->val.uiVal / pRhs->val.iVal; + pResult->eType = FLM_INT32_VAL; + } + else + { + pResult->val.uiVal = 0; // MOD by ZERO case + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSSMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.iVal != 0) + { + pResult->val.iVal = pLhs->val.iVal % pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + else + { + // MOD by ZERO case + + pResult->val.uiVal = 0; + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSUMod( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.uiVal != 0) + { + pResult->val.iVal = pLhs->val.iVal % ((FLMINT) pRhs->val.uiVal); + pResult->eType = FLM_INT32_VAL; + } + else + { + // Divide by ZERO case. + + pResult->val.uiVal = 0; + pResult->eType = FLM_UNKNOWN; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.uiVal = pLhs->val.uiVal + pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if ((pRhs->val.iVal >= 0) || (pLhs->val.uiVal > MAX_SIGNED_VAL)) + { + pResult->val.uiVal = pLhs->val.uiVal + (FLMUINT) pRhs->val.iVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.iVal = (FLMINT) pLhs->val.uiVal + pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + pResult->val.iVal = pLhs->val.iVal + pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if ((pLhs->val.iVal >= 0) || (pRhs->val.uiVal > MAX_SIGNED_VAL)) + { + pResult->val.uiVal = (FLMUINT) pLhs->val.iVal + pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.iVal = pLhs->val.iVal + (FLMINT) pRhs->val.uiVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpURPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRUPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSRPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRSPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRRPlus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pLhs->val.uiVal >= pRhs->val.uiVal) + { + pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.uiVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.iVal = (FLMINT) (pLhs->val.uiVal - pRhs->val.uiVal); + pResult->eType = FLM_INT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpUSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + + if (pRhs->val.iVal < 0) + { + pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.iVal; + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.iVal = (FLMINT) pLhs->val.uiVal - pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if ((pLhs->val.iVal > 0) && (pRhs->val.iVal < 0)) + { + pResult->val.uiVal = (FLMUINT) (pLhs->val.iVal - pRhs->val.iVal); + pResult->eType = FLM_UINT32_VAL; + } + else + { + pResult->val.iVal = pLhs->val.iVal - pRhs->val.iVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + if (pRhs->val.uiVal > MAX_SIGNED_VAL) + { + pResult->val.iVal = (pLhs->val.iVal - MAX_SIGNED_VAL) - + (FLMINT) (pRhs->val.uiVal - MAX_SIGNED_VAL); + pResult->eType = FLM_INT32_VAL; + } + else + { + pResult->val.iVal = pLhs->val.iVal - (FLMINT) pRhs->val.uiVal; + pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpURMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRUMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpSRMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRSMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FSTATIC RCODE OpRRMinus( + FQATOM * pLhs, + FQATOM * pRhs, + FQATOM * pResult) +{ + return (OpSyntaxError( pLhs, pRhs, pResult)); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE flmCurDoNeg( + FQATOM * pResult) +{ + RCODE rc = FERR_OK; + FQATOM * pTmpQAtom; + + // Perform operation on list according to operand types + + for (pTmpQAtom = pResult; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext) + { + if (IS_UNSIGNED( pTmpQAtom->eType)) + { + if (pTmpQAtom->val.uiVal >= MAX_SIGNED_VAL) + { + pTmpQAtom->eType = NO_TYPE; + } + else + { + pTmpQAtom->val.iVal = -((FLMINT) (pTmpQAtom->val.uiVal)); + pTmpQAtom->eType = FLM_INT32_VAL; + } + } + else if (IS_SIGNED( pTmpQAtom->eType)) + { + pTmpQAtom->val.iVal *= -1; + } + else if (pTmpQAtom->eType != FLM_UNKNOWN) + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + break; + } + } + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT flmCurDoMatchOp( + FQATOM * pLhs, + FQATOM * pRhs, + FLMUINT uiLang, + FLMBOOL bLeadingWildCard, + FLMBOOL bTrailingWildCard) +{ + FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; + FLMUINT uiTrueFalse = 0; + + // Verify operand types - non-text and non-binary return false + + if (!IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType)) + { + goto Exit; + } + + // If one of the operands is binary, simply do a byte comparison of the + // two values without regard to case or wildcards. + + if ((pLhs->eType == FLM_BINARY_VAL) || (pRhs->eType == FLM_BINARY_VAL)) + { + FLMUINT uiLen1; + FLMUINT uiLen2; + + uiLen1 = pLhs->uiBufLen; + uiLen2 = pRhs->uiBufLen; + flmAssert( !bLeadingWildCard); + if ((bTrailingWildCard) && (uiLen2 > uiLen1)) + { + uiLen2 = uiLen1; + } + + uiTrueFalse = (FLMUINT) + ( + ( + (uiLen1 == uiLen2) && + (f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, uiLen1) == 0) + ) ? (FLMUINT) FLM_TRUE : (FLMUINT) FLM_FALSE + ); + goto Exit; + } + + // If wildcards are set, do a string search, first making necessary + // adjustments for case sensitivity. ; + // + // NOTE: THIS IS MATCH BEGIN CASE WITHOUT WILD CARD. The non-wild case + // for bMatchEntire (DO_MATCH) does NOT come through this section of + // code. Rather, flmCurDoEQ is called instead of this routine in that + // case. + + if (pLhs->eType == FLM_TEXT_VAL && pRhs->eType == FLM_TEXT_VAL) + { + + // Always true if there is a wild card. + + uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen, + pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags, + bLeadingWildCard, bTrailingWildCard, uiLang); + } + else + { + uiTrueFalse = FLM_FALSE; + } + +Exit: + + return (uiTrueFalse); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT flmCurDoContainsOp( + FQATOM * pLhs, + FQATOM * pRhs, + FLMUINT uiLang) +{ + FLMBYTE * pResult = NULL; + FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; + FLMUINT uiTrueFalse = 0; + + // Verify operands -- both should be buffered types + + if (!IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType)) + { + goto Exit; + } + + // If one of the operands is binary, simply do a byte comparison of the + // two values without regard to case or wildcards. + + if ((pLhs->eType == FLM_BINARY_VAL) || (pRhs->eType == FLM_BINARY_VAL)) + { + uiTrueFalse = FLM_FALSE; + for (pResult = pLhs->val.pucBuf; + (FLMUINT) (pResult - pLhs->val.pucBuf) < pLhs->uiBufLen; + pResult++) + { + if ((*pResult == pRhs->val.pucBuf[0]) && + (f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, + pRhs->uiBufLen) == 0)) + { + uiTrueFalse = FLM_TRUE; + goto Exit; + } + } + + goto Exit; + } + + uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen, + pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags, + TRUE, TRUE, uiLang); +Exit: + + return (uiTrueFalse); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMINT flmCurDoRelationalOp( + FQATOM * pLhs, + FQATOM * pRhs, + FLMUINT uiLang) +{ + FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; + FLMINT iCompVal = 0; + + switch (pLhs->eType) + { + case FLM_TEXT_VAL: + { + flmAssert( pRhs->eType == FLM_TEXT_VAL); + iCompVal = flmTextCompare( pLhs->val.pucBuf, pLhs->uiBufLen, + pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags, + uiLang); + break; + } + + case FLM_UINT32_VAL: + { + switch (pRhs->eType) + { + case FLM_UINT32_VAL: + { + iCompVal = FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal); + break; + } + + case FLM_INT32_VAL: + { + if (pRhs->val.iVal < 0) + { + iCompVal = 1; + } + else + { + iCompVal = FQ_COMPARE( pLhs->val.uiVal, + (FLMUINT) pRhs->val.iVal); + } + break; + } + + default: + { + flmAssert( 0); + break; + } + + } + break; + } + + case FLM_INT32_VAL: + { + switch (pRhs->eType) + { + case FLM_INT32_VAL: + { + iCompVal = FQ_COMPARE( pLhs->val.iVal, pRhs->val.iVal); + break; + } + + case FLM_UINT32_VAL: + { + if (pLhs->val.iVal < 0) + { + iCompVal = -1; + } + else + { + iCompVal = FQ_COMPARE( (FLMUINT) pLhs->val.iVal, + pRhs->val.uiVal); + } + break; + } + + default: + { + flmAssert( 0); + break; + } + } + break; + } + + case FLM_REC_PTR_VAL: + { + flmAssert( pRhs->eType == FLM_REC_PTR_VAL || + pRhs->eType == FLM_UINT32_VAL); + + iCompVal = FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal); + break; + } + + case FLM_BINARY_VAL: + { + flmAssert( (pRhs->eType == FLM_BINARY_VAL) || + (pRhs->eType == FLM_TEXT_VAL)); + + if ((iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, + ((pLhs->uiBufLen > pRhs->uiBufLen) + ? pRhs->uiBufLen + : pLhs->uiBufLen))) == 0) + { + if (pLhs->uiBufLen < pRhs->uiBufLen) + { + iCompVal = -1; + } + else if (pLhs->uiBufLen > pRhs->uiBufLen) + { + iCompVal = 1; + } + } + + break; + } + + default: + { + flmAssert( 0); + break; + } + } + + return (iCompVal); +} diff --git a/flaim/src/fqeval2.cpp b/flaim/src/fqeval2.cpp deleted file mode 100644 index 2830db1..0000000 --- a/flaim/src/fqeval2.cpp +++ /dev/null @@ -1,1031 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Query evaluation -// Tabs: 3 -// -// Copyright (c) 1993-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fqeval2.cpp 12271 2006-01-19 14:48:13 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE OpSyntaxError( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUBitAND( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUBitOR( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUBitXOR( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpURMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSRMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRRMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpURDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSRDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRRDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUSMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSSMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSUMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpURPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSRPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRRPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpUSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpURMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpSRMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - -FSTATIC RCODE OpRRMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult); - - -/**************************************************************************** -Desc: Returns a syntax error on the operation. The combined values are - not allowed in the operation. -Ret: FERR_CURSOR_SYNTAX -****************************************************************************/ -FSTATIC RCODE OpSyntaxError( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - F_UNREFERENCED_PARM( pLhs); - F_UNREFERENCED_PARM( pRhs); - F_UNREFERENCED_PARM( pResult ); - return( RC_SET( FERR_CURSOR_SYNTAX)); -} - -/**************************************************************************** -Desc: Performs the bit AND operation on signed and unsigned values. - Used for UtoU, UtoSigned, SignedToU and SignedToSigned. -Notes: The signed and unsigned values better take up the same location - in the union. I (Scott) am a little concerned that we are even - working on signed values. I think that a uniary cast to an - unsigned in the query would be better. -****************************************************************************/ - -FSTATIC RCODE OpUUBitAND( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.uiVal = pLhs->val.uiVal & pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - return( FERR_OK); -} - -/**************************************************************************** -Desc: Performs the bit OR operation on signed and unsigned values. -Notes: The signed and unsigned values better take up the same location - in the union. -****************************************************************************/ - -FSTATIC RCODE OpUUBitOR( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.uiVal = pLhs->val.uiVal | pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - return( FERR_OK); -} - -/**************************************************************************** -Desc: Performs the bit XOR operation on signed and unsigned values. -Notes: The signed and unsigned values better take up the same location - in the union. -****************************************************************************/ - -FSTATIC RCODE OpUUBitXOR( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.uiVal = pLhs->val.uiVal ^ pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - return( FERR_OK); -} - -/**************************************************************************** -Desc: Performs the multiply operation on unsigned, signed and real values. -Notes: Overflow conditions are not checked for. For the most part, - a signed value is usually a negative value - otherwise it would - be an unsigned value. -****************************************************************************/ - -FSTATIC RCODE OpUUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.uiVal = pLhs->val.uiVal * pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpUSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - - pResult->val.iVal = (FLMINT)pLhs->val.uiVal * pRhs->val.iVal; - pResult->eType = FLM_INT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpSSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.iVal = pLhs->val.iVal * pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) ? FLM_INT32_VAL : FLM_UINT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpSUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.iVal = pLhs->val.iVal * (FLMINT)pRhs->val.uiVal; - pResult->eType = FLM_INT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpURMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.uiVal * pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} -FSTATIC RCODE OpRUMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real * (FLMLREAL) pRhs->val.uiVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpSRMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.iVal * pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} -FSTATIC RCODE OpRSMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real * (FLMLREAL) pRhs->val.iVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} -FSTATIC RCODE OpRRMult( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real * pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -/**************************************************************************** -Desc: Performs the divide operation on unsigned, signed and real values. - Divide on signed and unsigned values will result in a signed or - unsigned value that is floored down to an integer. -Notes: Divide by zero is checked for, but the result is 0 unsigned. - For the most part, a signed value is usually a negative value. -VISIT: There are problems in casting large unsigned values into a signed - value. We should be treating INT32_VAL as a negative bit and - always working with unsigned values. I hate to change too much - though. -VISIT: Need to visit the divide/mod by zero cases. -****************************************************************************/ - -FSTATIC RCODE OpUUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.uiVal) - { - pResult->val.uiVal = pLhs->val.uiVal / pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.uiVal = 0; // Divide by ZERO case. - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpUSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.iVal) - { - pResult->val.iVal = (FLMINT)pLhs->val.uiVal / pRhs->val.iVal; - pResult->eType = FLM_INT32_VAL; - } - else // Divide by ZERO case - let's try not to crash. - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.iVal) - { - pResult->val.iVal = pLhs->val.iVal / pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - else - { - pResult->val.uiVal = 0; // divide by ZERO case - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.uiVal) - { - pResult->val.iVal = pLhs->val.iVal / (FLMINT)pRhs->val.uiVal; - pResult->eType = FLM_INT32_VAL; - } - else // Divide by ZERO case - let's try not to crash. - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpURDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - if( pRhs->val.Real) - { - pResult->val.Real = (FLMLREAL)pLhs->val.uiVal / pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - } - else - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRUDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - if( pRhs->val.uiVal) - { - pResult->val.Real = pLhs->val.Real / (FLMLREAL)pRhs->val.uiVal; - pResult->eType = FLM_REAL_VAL; - } - else - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpSRDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - if( pRhs->val.Real) - { - pResult->val.Real = (FLMLREAL)pLhs->val.iVal / pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - } - else - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRSDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - if( pRhs->val.iVal) - { - pResult->val.Real = pLhs->val.Real / (FLMLREAL)pRhs->val.iVal; - pResult->eType = FLM_REAL_VAL; - } - else - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRRDiv( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - if( pRhs->val.Real) - { - pResult->val.Real = pLhs->val.Real / pRhs->val.Real; - pLhs->eType = FLM_REAL_VAL; - } - else - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -#endif -} - -/**************************************************************************** -Desc: Performs the modulo operation on unsigned, signed and real values. -Notes: Mod by zero is checked for, but the result is 0 unsigned. - For the most part, a signed value is usually a negative value. -****************************************************************************/ -FSTATIC RCODE OpUUMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.uiVal != 0) - { - pResult->val.uiVal = pLhs->val.uiVal % pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.uiVal = 0; // MOD by ZERO case. - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpUSMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.iVal != 0) - { - pResult->val.iVal = (FLMINT)pLhs->val.uiVal / pRhs->val.iVal; - pResult->eType = FLM_INT32_VAL; - } - else - { - pResult->val.uiVal = 0; // MOD by ZERO case - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSSMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.iVal != 0) - { - pResult->val.iVal = pLhs->val.iVal % pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - else - { - pResult->val.uiVal = 0; // MOD by ZERO case - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSUMod( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.uiVal != 0) - { - pResult->val.iVal = pLhs->val.iVal % ((FLMINT)pRhs->val.uiVal); - pResult->eType = FLM_INT32_VAL; - } - else // Divide by ZERO case - let's try not to crash. - { - pResult->val.uiVal = 0; - pResult->eType = FLM_UNKNOWN; - } - return( FERR_OK); -} - - -/**************************************************************************** -Desc: Performs an addition operation on unsigned, signed and real values. -Notes: Underflow and overflow conditions are not checked. In addition, - casting unsigned values to signed could lose data. Casting - ANYTHING to real will always lose some data. -****************************************************************************/ - -FSTATIC RCODE OpUUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.uiVal = pLhs->val.uiVal + pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpUSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( ( pRhs->val.iVal >= 0) || - ( pLhs->val.uiVal > MAX_SIGNED_VAL)) - { - pResult->val.uiVal = pLhs->val.uiVal + (FLMUINT)pRhs->val.iVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.iVal = (FLMINT)pLhs->val.uiVal + pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - pResult->val.iVal = pLhs->val.iVal + pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - return( FERR_OK); -} - -FSTATIC RCODE OpSUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( ( pLhs->val.iVal >= 0) || - ( pRhs->val.uiVal > MAX_SIGNED_VAL)) - { - pResult->val.uiVal = (FLMUINT)pLhs->val.iVal + pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.iVal = pLhs->val.iVal + (FLMINT)pRhs->val.uiVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpURPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.uiVal + pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRUPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real + (FLMLREAL)pRhs->val.uiVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpSRPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.iVal + pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRSPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real + (FLMLREAL)pRhs->val.iVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRRPlus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real + pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -/**************************************************************************** -Desc: Performs a subtraction operation on unsigned, signed and real values. -Notes: Underflow and overflow conditions are not checked. In addition, - casting unsigned values to signed could lose data. Casting - ANYTHING to real will always lose some data. -****************************************************************************/ -FSTATIC RCODE OpUUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pLhs->val.uiVal >= pRhs->val.uiVal) - { - pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.uiVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.iVal = (FLMINT)(pLhs->val.uiVal - pRhs->val.uiVal); - pResult->eType = FLM_INT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpUSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - /* VISIT: The original code had... - if(( pRhs->val.iVal < 0) || ( pRhs->val.uiVal < pLhs->val.uiVal)) - I don't know what the second part means. - */ - - if( pRhs->val.iVal < 0) - { - pResult->val.uiVal = pLhs->val.uiVal - pRhs->val.iVal; - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.iVal = (FLMINT)pLhs->val.uiVal - pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if(( pLhs->val.iVal > 0) && ( pRhs->val.iVal < 0)) - { - pResult->val.uiVal = (FLMUINT)( pLhs->val.iVal - pRhs->val.iVal); - pResult->eType = FLM_UINT32_VAL; - } - else - { - pResult->val.iVal = pLhs->val.iVal - pRhs->val.iVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpSUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ - if( pRhs->val.uiVal > MAX_SIGNED_VAL) - { - pResult->val.iVal = ( pLhs->val.iVal - MAX_SIGNED_VAL) - - (FLMINT)(pRhs->val.uiVal - MAX_SIGNED_VAL); - pResult->eType = FLM_INT32_VAL; - } - else - { - pResult->val.iVal = pLhs->val.iVal - (FLMINT)pRhs->val.uiVal; - pResult->eType = (pResult->val.iVal < 0) - ? FLM_INT32_VAL : FLM_UINT32_VAL; - } - return( FERR_OK); -} - -FSTATIC RCODE OpURMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.uiVal - pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRUMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real - (FLMLREAL)pRhs->val.uiVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpSRMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = (FLMLREAL)pLhs->val.iVal - pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRSMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real - (FLMLREAL)pRhs->val.iVal; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FSTATIC RCODE OpRRMinus( - FQATOM_p pLhs, - FQATOM_p pRhs, - FQATOM_p pResult) -{ -#ifndef FLM_REAL - return( OpSyntaxError( pLhs, pRhs, pResult)); -#else - pResult->val.Real = pLhs->val.Real - pRhs->val.Real; - pResult->eType = FLM_REAL_VAL; - return( FERR_OK); -#endif -} - -FQ_OPERATION * FQ_DoOperation [ - ((LAST_ARITH_OP - FIRST_ARITH_OP) + 1) * 9 ] = -{ -/* U = Unsigned S = Signed R = Real - U + U U + S U + R - S + U S + S S + R - R + U R + S R + R */ -/* BITAND */ OpUUBitAND, OpUUBitAND, OpSyntaxError, - OpUUBitAND, OpUUBitAND, OpSyntaxError, - OpSyntaxError, OpSyntaxError, OpSyntaxError, -/* BITOR */ OpUUBitOR, OpUUBitOR, OpSyntaxError, - OpUUBitOR, OpUUBitOR, OpSyntaxError, - OpSyntaxError, OpSyntaxError, OpSyntaxError, -/* BITXOR */ OpUUBitXOR, OpUUBitXOR, OpSyntaxError, - OpUUBitXOR, OpUUBitXOR, OpSyntaxError, - OpSyntaxError, OpSyntaxError, OpSyntaxError, -/* MULT */ OpUUMult, OpUSMult, OpURMult, - OpSUMult, OpSSMult, OpSRMult, - OpRUMult, OpRSMult, OpRRMult, -/* DIV */ OpUUDiv, OpUSDiv, OpURDiv, - OpSUDiv, OpSSDiv, OpSRDiv, - OpRUDiv, OpRSDiv, OpRRDiv, -/* MOD */ OpUUMod, OpUSMod, OpSyntaxError, - OpSUMod, OpSSMod, OpSyntaxError, - OpSyntaxError, OpSyntaxError, OpSyntaxError, -/* PLUS */ OpUUPlus, OpUSPlus, OpURPlus, - OpSUPlus, OpSSPlus, OpSRPlus, - OpRUPlus, OpRSPlus, OpRRPlus, -/* MINUS */ OpUUMinus, OpUSMinus, OpURMinus, - OpSUMinus, OpSSMinus, OpSRMinus, - OpRUMinus, OpRSMinus, OpRRMinus -}; diff --git a/flaim/src/fqeval3.cpp b/flaim/src/fqeval3.cpp deleted file mode 100644 index c6e7413..0000000 --- a/flaim/src/fqeval3.cpp +++ /dev/null @@ -1,277 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Query evaluation -// Tabs: 3 -// -// Copyright (c) 1993-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fqeval3.cpp 12271 2006-01-19 14:48:13 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: Performs unary minus operation on list of query atoms. -****************************************************************************/ -RCODE flmCurDoNeg( - FQATOM_p pResult) -{ - RCODE rc = FERR_OK; - FQATOM_p pTmpQAtom; - - /* Perform operation on list according to operand types */ - - for( pTmpQAtom = pResult; pTmpQAtom; pTmpQAtom = pTmpQAtom->pNext) - { - if( IS_UNSIGNED( pTmpQAtom->eType)) - { - if( pTmpQAtom->val.uiVal >= MAX_SIGNED_VAL) - pTmpQAtom->eType = NO_TYPE; - else - { - pTmpQAtom->val.iVal = -((FLMINT)(pTmpQAtom->val.uiVal)); - pTmpQAtom->eType = FLM_INT32_VAL; - } - } - else if( IS_SIGNED( pTmpQAtom->eType)) - { - pTmpQAtom->val.iVal *= -1; - } - else if( pTmpQAtom->eType != FLM_UNKNOWN) - { - rc = RC_SET( FERR_CURSOR_SYNTAX); - break; - } - } - return( rc); -} - - -/**************************************************************************** -Desc: Performs match begin operation on two stack elements of buffered type. - Will do a MATCH or MATCH_BEGIN, depending on the bMatchEntire flag. - When bMatchEntire is TRUE, we are doing the MATCH operation. -****************************************************************************/ -FLMUINT flmCurDoMatchOp( - FQATOM_p pLhs, - FQATOM_p pRhs, - FLMUINT uiLang, - FLMBOOL bLeadingWildCard, - FLMBOOL bTrailingWildCard) -{ - FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; - FLMUINT uiTrueFalse = 0; - - /* Verify operand types - non-text and non-binary return false */ - if( !IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType)) - goto Exit; - - /* If one of the operands is binary, simply do a byte comparison of the two - values without regard to case or wildcards. */ - if(( pLhs->eType == FLM_BINARY_VAL) || ( pRhs->eType == FLM_BINARY_VAL)) - { - FLMUINT uiLen1; - FLMUINT uiLen2; - - uiLen1 = pLhs->uiBufLen; - uiLen2 = pRhs->uiBufLen; - flmAssert( !bLeadingWildCard); - if ((bTrailingWildCard) && (uiLen2 > uiLen1)) - { - uiLen2 = uiLen1; - } - - uiTrueFalse = (FLMUINT)(((uiLen1 == uiLen2) && - (f_memcmp( pLhs->val.pucBuf, - pRhs->val.pucBuf, uiLen1) == 0)) - ? (FLMUINT)FLM_TRUE - : (FLMUINT)FLM_FALSE); - goto Exit; - } - - /* If wildcards are set, do a string search, first making necessary - adjustments for case sensitivity. */ - - /* - NOTE: THIS IS MATCH BEGIN CASE WITHOUT WILD CARD. - - The non-wild case for bMatchEntire (DO_MATCH) does NOT - come through this section of code. Rather, flmCurDoEQ is called - instead of this routine in that case. - */ - - if( pLhs->eType == FLM_TEXT_VAL && pRhs->eType == FLM_TEXT_VAL) - { - // Always true if there is a wild card. - uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen, - pRhs->val.pucBuf, pRhs->uiBufLen, - uiFlags, bLeadingWildCard, bTrailingWildCard, - uiLang ); - } - else - { - uiTrueFalse = FLM_FALSE; - } - -Exit: - - return uiTrueFalse; -} - - -/**************************************************************************** -Desc: Performs 'contains' operation on stack elements of buffered type. -Note: Wildcards and case insensitive searches are not allowed yet on - binary values. -VISIT: Changed to take the OR bits from the left and right wFlags instead - of just taking the left if it had a value otherwise right. -VISIT: Don't like ALWAYS setting spaces to space and converting to upper. - We should have a flag so that if the ?hs is used again it doesn't - parse through the data again. -****************************************************************************/ -FLMUINT flmCurDoContainsOp( - FQATOM_p pLhs, - FQATOM_p pRhs, - FLMUINT uiLang - ) -{ - FLMBYTE * pResult = NULL; - FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; - FLMUINT uiTrueFalse = 0; // set for invalid response. - - /* Verify operands -- both should be buffered types */ - if( !IS_BUF_TYPE( pLhs->eType) || !IS_BUF_TYPE( pRhs->eType)) - goto Exit; - - /* If one of the operands is binary, simply do a byte comparison of the two - values without regard to case or wildcards. */ - if(( pLhs->eType == FLM_BINARY_VAL) || ( pRhs->eType == FLM_BINARY_VAL)) - { - uiTrueFalse = FLM_FALSE; - for( pResult = pLhs->val.pucBuf; - (FLMUINT)(pResult - pLhs->val.pucBuf) < pLhs->uiBufLen; - pResult++) - { - if(( *pResult == pRhs->val.pucBuf[0]) && - ( f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, pRhs->uiBufLen) == 0)) - { - uiTrueFalse = FLM_TRUE; - goto Exit; - } - } - goto Exit; - } - - uiTrueFalse = flmTextMatch( pLhs->val.pucBuf, pLhs->uiBufLen, - pRhs->val.pucBuf, pRhs->uiBufLen, - uiFlags, TRUE, // Leading wild card. - TRUE, // trailing WC - uiLang ); -Exit: - - return uiTrueFalse; -} - - -/**************************************************************************** -Desc: Performs a compare on two operands. Strings are matched fully. -****************************************************************************/ -FLMINT flmCurDoRelationalOp( - FQATOM_p pLhs, - FQATOM_p pRhs, - FLMUINT uiLang) // Language for text -{ - FLMUINT uiFlags = pLhs->uiFlags | pRhs->uiFlags; // String flags. - FLMINT iCompVal = 0; - - /* Do operation according to operand types */ - switch( pLhs->eType) - { - case FLM_TEXT_VAL: - flmAssert( pRhs->eType == FLM_TEXT_VAL); - iCompVal = flmTextCompare( pLhs->val.pucBuf, pLhs->uiBufLen, - pRhs->val.pucBuf, pRhs->uiBufLen, uiFlags, uiLang); - break; - - case FLM_UINT32_VAL: - switch( pRhs->eType) - { - case FLM_UINT32_VAL: - iCompVal = FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal); - break; - - case FLM_INT32_VAL: - if( pRhs->val.iVal < 0) - iCompVal = 1; - else - iCompVal = FQ_COMPARE( pLhs->val.uiVal, (FLMUINT)pRhs->val.iVal); - break; - - default: - flmAssert( 0); // Shouldn't happen - break; - } - break; - - case FLM_INT32_VAL: - switch( pRhs->eType) - { - case FLM_INT32_VAL: - iCompVal = FQ_COMPARE( pLhs->val.iVal, pRhs->val.iVal); - break; - - case FLM_UINT32_VAL: - if( pLhs->val.iVal < 0) - iCompVal = -1; - else - iCompVal = FQ_COMPARE((FLMUINT)pLhs->val.iVal, pRhs->val.uiVal); - break; - - default: - flmAssert( 0); // Shouldn't happen - break; - } - break; - - case FLM_REC_PTR_VAL: - flmAssert( pRhs->eType == FLM_REC_PTR_VAL || pRhs->eType == FLM_UINT32_VAL); - iCompVal = FQ_COMPARE( pLhs->val.uiVal, pRhs->val.uiVal); - break; - - case FLM_BINARY_VAL: - flmAssert( (pRhs->eType == FLM_BINARY_VAL) || (pRhs->eType == FLM_TEXT_VAL)); - if ((iCompVal = f_memcmp( pLhs->val.pucBuf, pRhs->val.pucBuf, - ((pLhs->uiBufLen > pRhs->uiBufLen) - ? pRhs->uiBufLen - : pLhs->uiBufLen))) == 0) - { - if (pLhs->uiBufLen < pRhs->uiBufLen) - { - iCompVal = -1; - } - else if (pLhs->uiBufLen > pRhs->uiBufLen) - { - iCompVal = 1; - } - } - break; - default: - flmAssert( 0); // Shouldn't happen - break; - } - return iCompVal; -} diff --git a/flaim/src/fqget.cpp b/flaim/src/fqget.cpp index ddf4b01..a343e65 100644 --- a/flaim/src/fqget.cpp +++ b/flaim/src/fqget.cpp @@ -25,7 +25,7 @@ #include "flaimsys.h" FSTATIC RCODE flmCurCSTestRec( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDrn, FlmRecord * pTestRec, FLMBOOL * pbIsMatchRV); @@ -35,7 +35,7 @@ Desc: Makes a SET_DEL from a record. ****************************************************************************/ RCODE flmCurMakeKeyFromRec( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, POOL * pPool, FlmRecord * pRec, FLMBYTE ** ppucKeyBuffer, @@ -111,17 +111,17 @@ Exit: Desc: Sets a query's position from a passed-in DRN. ****************************************************************************/ RCODE flmCurSetPosFromDRN( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDRN ) { RCODE rc = FERR_OK; FlmRecord * pRec = NULL; POOL * pTempPool; - FDB_p pDb = NULL; - IXD_p pIxd; + FDB * pDb = NULL; + IXD * pIxd; LFILE * pLFile; - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; FLMBOOL bPositioned; FLMBYTE * pucKeyBuffer = NULL; FLMUINT uiKeyLen; @@ -303,9 +303,9 @@ Exit: return( pCursor->rc = rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Given a cursor and two DRNs, this API does the following: -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorCompareDRNs( HFCURSOR hCursor, FLMUINT uiDRN1, @@ -316,8 +316,8 @@ FLMEXP RCODE FLMAPI FlmCursorCompareDRNs( FLMUINT * puiCount) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; - FDB_p pDb = NULL; + CURSOR * pCursor = (CURSOR *)hCursor; + FDB * pDb = NULL; POOL * pTempPool; FLMBYTE * pucKey1; FLMUINT uiKey1Len; @@ -325,7 +325,7 @@ FLMEXP RCODE FLMAPI FlmCursorCompareDRNs( FLMUINT uiKey2Len; FlmRecord * pRec1 = NULL; FlmRecord * pRec2 = NULL; - IXD_p pIxd; + IXD * pIxd; FSIndexCursor * pTmpFSIndexCursor = NULL; FSIndexCursor * pSaveFSIndexCursor = NULL; FLMUINT uiSaveTimeLimit = 0; @@ -693,14 +693,14 @@ Desc: Does FlmCursorTestRec and FlmCursorTestDRN over the client/server line. ****************************************************************************/ FSTATIC RCODE flmCurCSTestRec( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDrn, FlmRecord * pTestRec, FLMBOOL * pbIsMatchRV ) { RCODE rc = FERR_OK; - CS_CONTEXT_p pCSContext = pCursor->pCSContext; + CS_CONTEXT * pCSContext = pCursor->pCSContext; FCL_WIRE Wire( pCSContext); // If there is no VALID id for the cursor, get one. @@ -768,23 +768,22 @@ Transmission_Error: } -/*API~*********************************************************************** -Desc : Checks a record that has been retrieved from the database to see if - satisfies the cursor selection criteria. - IMPORTANT NOTE: pRec's containerID better be set to the container it - came from, because flmCurEvalCriteria verifies that the record's - container number matches the cursor's container number. -*END************************************************************************/ +/**************************************************************************** +Desc: Checks a record that has been retrieved from the database to see if + satisfies the cursor selection criteria. + IMPORTANT NOTE: pRec's containerID better be set to the container it + came from, because flmCurEvalCriteria verifies that the record's + container number matches the cursor's container number. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorTestRec( HFCURSOR hCursor, FlmRecord * pRec, - FLMBOOL * pbIsMatch - ) + FLMBOOL * pbIsMatch) { - RCODE rc = FERR_OK; - FDB_p pDb = NULL; - CURSOR_p pCursor = (CURSOR *)hCursor; - SUBQUERY_p pSubQuery; + RCODE rc = FERR_OK; + FDB * pDb = NULL; + CURSOR * pCursor = (CURSOR *)hCursor; + SUBQUERY * pSubQuery; flmAssert( pCursor != NULL); *pbIsMatch = FALSE; @@ -862,23 +861,22 @@ Exit2: return( rc); } -/*API~*********************************************************************** -Desc : Retrieves the record identified by the passed-in DRN and checks it to - see if it satisfies the cursor selection criteria. -Notes: This function is designed for use with cursors having only one - associated source. Multiple sources are not supported. -*END************************************************************************/ +/**************************************************************************** +Desc: Retrieves the record identified by the passed-in DRN and checks it + to see if it satisfies the cursor selection criteria. +Notes: This function is designed for use with cursors having only one + associated source. Multiple sources are not supported. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorTestDRN( HFCURSOR hCursor, FLMUINT uiDrn, - FLMBOOL * pbIsMatch - ) + FLMBOOL * pbIsMatch) { - RCODE rc = FERR_OK; - FDB_p pDb = NULL; - CURSOR_p pCursor = (CURSOR *)hCursor; - SUBQUERY_p pSubQuery; - FlmRecord * pRec = NULL; + RCODE rc = FERR_OK; + FDB * pDb = NULL; + CURSOR * pCursor = (CURSOR *)hCursor; + SUBQUERY * pSubQuery; + FlmRecord * pRec = NULL; flmAssert( pCursor != NULL); *pbIsMatch = FALSE; diff --git a/flaim/src/fqkeys.cpp b/flaim/src/fqkeys.cpp index 90ccf91..2e05938 100644 --- a/flaim/src/fqkeys.cpp +++ b/flaim/src/fqkeys.cpp @@ -24,56 +24,119 @@ #include "flaimsys.h" -#define DOMAIN_TO_DRN(uiDomain) (FLMUINT)(((uiDomain) + 1) * 256 + 1) -#define DRN_TO_DOMAIN(uiDrn) (FLMUINT)(((uiDrn) - 1) / 256 - 1) +#define DOMAIN_TO_DRN(uiDomain) \ + (FLMUINT)(((uiDomain) + 1) * 256 + 1) + +#define DRN_TO_DOMAIN(uiDrn) \ + (FLMUINT)(((uiDrn) - 1) / 256 - 1) FSTATIC FLMINT flmPosKeyCompare( - POS_KEY_p pKey1, - POS_KEY_p pKey2); + POS_KEY * pKey1, + POS_KEY * pKey2); FSTATIC RCODE flmLoadPosKeys( - CURSOR_p pCursor, - POS_KEY_p pKeys, - FLMUINT uiNumKeys, - FLMBOOL bLeafLevel); + CURSOR * pCursor, + POS_KEY * pKeys, + FLMUINT uiNumKeys, + FLMBOOL bLeafLevel); FSTATIC RCODE flmKeyIsMatch( - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, FLMBYTE * pucKey, FLMUINT uiKeyLen, FLMUINT uiDrn, - POS_KEY_p * ppKeys, + POS_KEY * * ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize, FLMUINT uiKeyArrayGrowSize); FSTATIC RCODE flmExamineBlock( - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, FLMBYTE * pucBlk, FSIndexCursor * pFSIndexCursor, FLMUINT ** ppuiChildBlockAddresses, FLMUINT * puiNumChildBlocks, FLMUINT * puiBlkAddressArrayAllocSize, - POS_KEY_p * ppKeys, + POS_KEY * * ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize, FLMBOOL * pbHighKeyInRange); FSTATIC RCODE flmGetLastKey( FDB * pDb, - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, LFILE * pLFile, FLMUINT uiBlockAddress, - POS_KEY_p * ppKeys, + POS_KEY ** ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize); FSTATIC RCODE flmCurGetPosKeys( - FDB * pDb, - CURSOR_p pCursor); + FDB * pDb, + CURSOR * pCursor); + +FSTATIC FLMBOOL flmFindWildcard( + FLMBYTE * pValue, + FLMUINT * puiCharPos); + +FSTATIC RCODE flmAddKeyPiece( + FLMUINT uiMaxKeySize, + IFD * pIfd, + FLMBOOL bDoMatchBegin, + FLMBYTE * pFromKey, + FLMUINT * puiFromKeyPos, + FLMBOOL bFromAtFirst, + FLMBYTE * pUntilKey, + FLMUINT * puiUntilKeyPos, + FLMBOOL bUntilAtEnd, + FLMBYTE * pBuf, + FLMUINT uiBufLen, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbDoneBuilding); + +FSTATIC RCODE flmAddTextPiece( + FLMUINT uiMaxKeySize, + IFD * pIfd, + FLMBOOL bCaseInsensitive, + FLMBOOL bDoMatchBegin, + FLMBOOL bDoFirstSubstring, + FLMBOOL bTrailingWildcard, + FLMBYTE * pFromKey, + FLMUINT * puiFromKeyPos, + FLMBOOL bFromAtFirst, + FLMBYTE * pUntilKey, + FLMUINT * puiUntilKeyPos, + FLMBOOL bUntilAtEnd, + FLMBYTE * pBuf, + FLMUINT uiBufLen, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbDoneBuilding, + FLMBOOL * pbOriginalCharsLost); + +FSTATIC FLMBOOL flmSelectBestSubstr( + FLMBYTE ** ppValue, + FLMUINT * puiValueLen, + FLMUINT uiIfdFlags, + FLMBOOL * pbTrailingWildcard); + +FSTATIC FLMUINT flmCountCharacters( + FLMBYTE * pValue, + FLMUINT uiValueLen, + FLMUINT uiMaxToCount, + FLMUINT uiIfdFlags); + +FSTATIC void flmUintToBCD( + FLMUINT uiValue, + FLMBYTE * pNumberBuf, + FLMUINT * puiValueLen); + +FSTATIC void flmIntToBCD( + FLMINT iValue, + FLMBYTE * pNumberBuf, + FLMUINT * puiValueLen); /**************************************************************************** Desc: Compares the contents of the key buffers for two cursor positioning keys, @@ -83,8 +146,8 @@ Desc: Compares the contents of the key buffers for two cursor positioning keys, >0 Indicates that the first key is greater then the second. ****************************************************************************/ FSTATIC FLMINT flmPosKeyCompare( - POS_KEY_p pKey1, - POS_KEY_p pKey2 + POS_KEY * pKey1, + POS_KEY * pKey2 ) { FLMINT iCmp; @@ -134,8 +197,8 @@ Desc: Loads a set of positioning keys into a subquery's array, allocating it if necessary. ****************************************************************************/ FSTATIC RCODE flmLoadPosKeys( - CURSOR_p pCursor, - POS_KEY_p pKeys, + CURSOR * pCursor, + POS_KEY * pKeys, FLMUINT uiNumKeys, FLMBOOL bLeafLevel ) @@ -261,23 +324,23 @@ Desc: Evaluates an index key against selection criteria, and adds it to the passed-in key array. ****************************************************************************/ FSTATIC RCODE flmKeyIsMatch( - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, FLMBYTE * pucKey, FLMUINT uiKeyLen, FLMUINT uiDrn, - POS_KEY_p * ppKeys, + POS_KEY * * ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize, FLMUINT uiKeyArrayGrowSize ) { RCODE rc = FERR_OK; - SUBQUERY_p pSubQuery = pCursor->pSubQueryList; + SUBQUERY * pSubQuery = pCursor->pSubQueryList; FlmRecord * pKey = NULL; FLMBOOL bHaveMatch = FALSE; FLMUINT uiResult; - POS_KEY_p pPosKey; + POS_KEY * pPosKey; // If pSubQuery->bDoKeyMatch is FALSE, the selection criteria for this // query are satisfied by a contiguous set of index keys. Therefore, @@ -357,14 +420,14 @@ Visit:This code NEEDS to use the b-tree routines and NOT use the low level level of the b-tree. ****************************************************************************/ FSTATIC RCODE flmExamineBlock( - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, FLMBYTE * pucBlk, FSIndexCursor * pFSIndexCursor, FLMUINT ** ppuiChildBlockAddresses, FLMUINT * puiNumChildBlocks, FLMUINT * puiBlkAddressArrayAllocSize, - POS_KEY_p * ppKeys, + POS_KEY * * ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize, FLMBOOL * pbHighKeyInRange @@ -651,11 +714,11 @@ Visit:This routine must be rewritten to get rid of the low level BTREE ****************************************************************************/ FSTATIC RCODE flmGetLastKey( FDB * pDb, - CURSOR_p pCursor, - IXD_p pIxd, + CURSOR * pCursor, + IXD * pIxd, LFILE * pLFile, FLMUINT uiBlockAddress, - POS_KEY_p * ppKeys, + POS_KEY * * ppKeys, FLMUINT * puiNumKeys, FLMUINT * puiKeyArrayAllocSize ) @@ -666,7 +729,7 @@ FSTATIC RCODE flmGetLastKey( FLMUINT uiEndDrn = 0; BTSK stack; FLMBYTE ucKeyBuf [MAX_KEY_SIZ]; - BTSK_p pStack = &stack; + BTSK * pStack = &stack; FLMUINT uiEndOfBlock; FLMUINT uiCurrElmOffset; FLMUINT uiBlkType; @@ -845,7 +908,7 @@ Exit: Desc: Frees the allocations associated with a subquery's array. ****************************************************************************/ void flmCurFreePosKeys( - CURSOR_p pCursor + CURSOR * pCursor ) { FLMUINT uiLoopCnt; @@ -869,23 +932,23 @@ Desc: Gets a set of positioning keys for a particular subquery. ****************************************************************************/ FSTATIC RCODE flmCurGetPosKeys( FDB * pDb, - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; BTSK stack [BH_MAX_LEVELS]; FLMBYTE ucKeyBuf [MAX_KEY_SIZ]; - BTSK_p pStack = stack; + BTSK * pStack = stack; LFILE * pLFile; LFILE TmpLFile; - IXD_p pIxd; - SUBQUERY_p pSubQuery; + IXD * pIxd; + SUBQUERY * pSubQuery; FLMUINT * puiChildBlockAddresses = NULL; FLMUINT * puiTmpBlocks = NULL; FLMUINT uiNumChildBlocks = 0; FLMUINT uiNumTmpBlks; FLMUINT uiBlkAddressArrayAllocSize = 0; - POS_KEY_p pKeys = NULL; + POS_KEY * pKeys = NULL; FLMUINT uiNumKeys = 0; FLMUINT uiKeyArrayAllocSize = 0; FLMBOOL bHighKeyInRange = FALSE; @@ -1074,11 +1137,11 @@ Exit: Desc: Gets a set of positioning keys for a particular subquery. ****************************************************************************/ RCODE flmCurSetupPosKeyArray( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; + FDB * pDb = NULL; // Optimize the subqueries as necessary @@ -1117,14 +1180,14 @@ Desc: Gets the approximate percentage position of a passed-in key within a cursor's result set. ****************************************************************************/ RCODE flmCurGetPercentPos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiPrcntPos ) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; - IXD_p pIxd; - POS_KEY_p pPosKeyArray; + FDB * pDb = NULL; + IXD * pIxd; + POS_KEY * pPosKeyArray; POS_KEY CompKey; FLMUINT uiLowOffset; FLMUINT uiMidOffset; @@ -1348,17 +1411,17 @@ Desc: Sets a query's position to a percentage represented by one of an array of positioning keys. ****************************************************************************/ RCODE flmCurSetPercentPos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiPrcntPos ) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; + FDB * pDb = NULL; FLMUINT uiPrcntOffs; FLMUINT uiIntervalSize; FLMUINT uiRFactor; - SUBQUERY_p pSubQuery = NULL; - POS_KEY_p pPosKey; + SUBQUERY * pSubQuery = NULL; + POS_KEY * pPosKey; // Optimize the subqueries as necessary @@ -1538,3 +1601,1437 @@ Exit: return( rc); } + +/**************************************************************************** +Desc: Build the from and until keys given a field list with operators and + values and an index. +Note: The knowledge of query definitions is limited in these routines. +****************************************************************************/ +RCODE flmBuildFromAndUntilKeys( + IXD * pIxd, + QPREDICATE ** ppQPredicate, + FLMBYTE * pFromKey, + FLMUINT * puiFromKeyLen, + FLMBYTE * pUntilKey, + FLMUINT * puiUntilKeyLen, + FLMBOOL * pbDoRecMatch, + FLMBOOL * pbDoKeyMatch, + FLMBOOL * pbExclusiveUntilKey) +{ + RCODE rc = FERR_OK; + QPREDICATE * pCurPred; + IFD * pIfd = pIxd->pFirstIfd; + FLMUINT uiLanguage = pIxd->uiLanguage; + FLMUINT uiIfdCnt = pIxd->uiNumFlds; + FLMUINT uiFromKeyPos = 0; + FLMUINT uiUntilKeyPos = 0; + FLMBOOL bFromAtFirst; + FLMBOOL bUntilAtEnd; + FLMBOOL bDataTruncated; + FLMBOOL bDoneBuilding; + FLMBOOL bMustNotDoKeyMatch = FALSE; + FLMBOOL bDoKeyMatch = FALSE; + FLMBOOL bOriginalCharsLost; + FLMBOOL bDBCSLanguage; + FLMBYTE pNumberBuf[8]; + FLMUINT uiTempLen; + FLMUINT uiMaxKeySize; + + bDataTruncated = FALSE; + bDoneBuilding = FALSE; + *puiFromKeyLen = 0; + *puiUntilKeyLen = 0; + uiFromKeyPos = 0; + uiUntilKeyPos = 0; + *pbExclusiveUntilKey = TRUE; + + bDBCSLanguage = (uiLanguage >= FIRST_DBCS_LANG) && + (uiLanguage <= LAST_DBCS_LANG) + ? TRUE + : FALSE; + + uiMaxKeySize = (pIxd->uiContainerNum) + ? MAX_KEY_SIZ + : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); + + for (; !bDoneBuilding && uiIfdCnt--; ppQPredicate++, pIfd++) + { + + // Add the compound marker if not the first piece. + + if (pIfd->uiCompoundPos) + { + IFD * pPrevIfd = (pIfd - 1); + + // Add the compound markers for this key piece. + + if (bDBCSLanguage && + (IFD_GET_FIELD_TYPE( pPrevIfd) == FLM_TEXT_TYPE) && + (!((pPrevIfd)->uiFlags & IFD_CONTEXT))) + { + pFromKey[uiFromKeyPos++] = 0; + pUntilKey[uiUntilKeyPos++] = 0; + } + + pFromKey[uiFromKeyPos++] = COMPOUND_MARKER; + pUntilKey[uiUntilKeyPos++] = COMPOUND_MARKER; + } + + bFromAtFirst = bUntilAtEnd = FALSE; + pCurPred = *ppQPredicate; + + if (!pCurPred) + { + + // There is not a predicate that matches this compound key piece. + // + // Done processing, yet may need to look for a predicate that + // will force a doKeyMatch or a doRecMatch. + + if (RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, pFromKey, + &uiFromKeyPos, TRUE, pUntilKey, &uiUntilKeyPos, TRUE, NULL, + 0, &bDataTruncated, &bDoneBuilding))) + { + goto Exit; + } + + continue; + } + + // Handle special cases for indexing context and/or exists + // predicate. + + else if (pIfd->uiFlags & IFD_CONTEXT) + { + + // Indexed only the TAG. Simple to set the tag as the key. + + if (RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, pFromKey, + &uiFromKeyPos, FALSE, pUntilKey, &uiUntilKeyPos, FALSE, + NULL, 0, &bDataTruncated, &bDoneBuilding))) + { + goto Exit; + } + + // If we don't have an exists predicate we need to read the + // record. + + if (pCurPred->eOperator != FLM_EXISTS_OP) + { + bMustNotDoKeyMatch = TRUE; + } + + continue; + } + else + { + FLMBOOL bMatchedBadOperator = FALSE; + + switch (pCurPred->eOperator) + { + case FLM_EXISTS_OP: + case FLM_NE_OP: + { + bMatchedBadOperator = TRUE; + bUntilAtEnd = TRUE; + bFromAtFirst = TRUE; + break; + } + + default: + { + if (pCurPred->bNotted) + { + bMatchedBadOperator = TRUE; + bUntilAtEnd = TRUE; + bFromAtFirst = TRUE; + } + break; + } + } + + if (bMatchedBadOperator) + { + + // Does exist is a FIRST to LAST for this piece. + + if (RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, + pFromKey, &uiFromKeyPos, bFromAtFirst, pUntilKey, + &uiUntilKeyPos, bUntilAtEnd, NULL, 0, &bDataTruncated, + &bDoneBuilding))) + { + goto Exit; + } + + continue; + } + } + + switch (IFD_GET_FIELD_TYPE( pIfd)) + { + + // Build TEXT type piece + + case FLM_TEXT_TYPE: + { + FLMBOOL bCaseInsensitive; + FLMBOOL bDoFirstSubstring; + FLMBOOL bDoMatchBegin; + FLMBOOL bDoSubstringSearch; + FLMBOOL bTrailingWildcard; + FLMBYTE * pValue = (FLMBYTE *) pCurPred->pVal->val.pucBuf; + FLMUINT uiValueLen = pCurPred->pVal->uiBufLen; + + bCaseInsensitive = (FLMBOOL)((pCurPred->pVal->uiFlags & FLM_NOCASE) + ? TRUE + : FALSE); + + bDoFirstSubstring = (FLMBOOL)((pIfd->uiFlags & IFD_SUBSTRING) + ? TRUE + : FALSE); + + + bDoMatchBegin = FALSE; + bDoSubstringSearch = FALSE; + bTrailingWildcard = FALSE; + + switch (pCurPred->eOperator) + { + + // The difference between MATCH and EQ_OP is that EQ does not + // support wildcards inbedded in the search key. + + case FLM_MATCH_OP: + case FLM_MATCH_BEGIN_OP: + { + if (pCurPred->eOperator == FLM_MATCH_BEGIN_OP) + { + bDoKeyMatch = bDoMatchBegin = TRUE; + } + + if (pCurPred->pVal->uiFlags & FLM_WILD) + { + if (!bDoFirstSubstring) + { + FLMBOOL bFoundWildcard = flmFindWildcard( pValue, + &uiValueLen); + + bDoKeyMatch = TRUE; + + if (pCurPred->eOperator == FLM_MATCH_OP) + { + bTrailingWildcard = bDoMatchBegin = bFoundWildcard; + } + else + { + bTrailingWildcard = bDoMatchBegin = TRUE; + } + } + else + { + + // If this is a substring index look for a better + // 'contains' string to search for. We don't like + // "A*BCDEFG" searches. + + bTrailingWildcard = + (pCurPred->eOperator == FLM_MATCH_BEGIN_OP) + ? TRUE + : FALSE; + + if (flmSelectBestSubstr( &pValue, &uiValueLen, + pIfd->uiFlags, &bTrailingWildcard)) + { + bDoMatchBegin = bTrailingWildcard; + bMustNotDoKeyMatch = TRUE; + bDoFirstSubstring = FALSE; + } + else if (bTrailingWildcard) + { + bDoKeyMatch = bDoMatchBegin = TRUE; + } + } + } + break; + } + + case FLM_CONTAINS_OP: + case FLM_MATCH_END_OP: + { + + // Normal text index this piece goes from first to last. + + if (!bDoFirstSubstring) + { + bFromAtFirst = TRUE; + bUntilAtEnd = TRUE; + } + else + { + bDoFirstSubstring = TRUE; + bDoSubstringSearch = TRUE; + + // SPACE/Hyphen rules on SUBSTRING index. If the search + // string starts with " _asdf" then we must do a record + // match so "Z asdf" matches and "Zasdf" doesn't. We + // won't touch key match even though it MAY return + // FLM_TRUE when in fact the key may or may not match. + // + // VISIT: MatchBegin and Contains could also optimize + // the trailing space by adding the space ONLY to the + // UNTIL key. + + if (uiValueLen && + ((*pValue == ASCII_SPACE && + (pIfd->uiFlags & IFD_MIN_SPACES)) || + (*pValue == ASCII_UNDERSCORE && + (pIfd->uiFlags & IFD_NO_UNDERSCORE)))) + { + *pbDoRecMatch = TRUE; + } + + // Take the flags from the pVal and NOT from the + // predicate. + + if (pCurPred->pVal->uiFlags & FLM_WILD) + { + + // Select the best substring. The case of + // "A*BCD*E*FGHIJKLMNOP" will look for "FGHIJKLMNOP". + // and TURN OFF doKeyMatch and SET doRecMatch. + + bTrailingWildcard = + (pCurPred->eOperator == FLM_CONTAINS_OP) + ? TRUE + : FALSE; + + if (flmSelectBestSubstr( &pValue, &uiValueLen, + pIfd->uiFlags, &bTrailingWildcard)) + { + bDoMatchBegin = bTrailingWildcard; + bMustNotDoKeyMatch = TRUE; + bDoFirstSubstring = FALSE; + } + + if (bTrailingWildcard) + { + bDoKeyMatch = bDoMatchBegin = TRUE; + } + } + + if (bDoFirstSubstring) + { + + // Setting bDoMatchBegin creates a UNTIL key with + // trailing 0xFF values. + + if (pCurPred->eOperator == FLM_CONTAINS_OP) + { + bDoKeyMatch = TRUE; + bDoMatchBegin = TRUE; + } + } + + // Special case: Single character contains/MEnd in a + // substr ix. + + if (!bDBCSLanguage && + flmCountCharacters( pValue, uiValueLen, 2, + pIfd->uiFlags) < 2) + { + bDoKeyMatch = bFromAtFirst = bUntilAtEnd = TRUE; + } + } + + break; + } + + // No wild card support for the operators below. + + case FLM_EQ_OP: + { + break; + } + + case FLM_GE_OP: + case FLM_GT_OP: + { + bUntilAtEnd = TRUE; + break; + } + + case FLM_LE_OP: + { + bFromAtFirst = TRUE; + break; + } + + case FLM_LT_OP: + { + bFromAtFirst = TRUE; + *pbExclusiveUntilKey = TRUE; + break; + } + + default: + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + } + + // If index is case insensitive, but search is case sensitive + // we must NOT do a key match - we would fail things we should + // not be failing. + + if ((pIfd->uiFlags & IFD_UPPER) && !bCaseInsensitive) + { + bMustNotDoKeyMatch = TRUE; + } + + if (RC_BAD( rc = flmAddTextPiece( uiMaxKeySize, pIfd, + bCaseInsensitive, bDoMatchBegin, bDoFirstSubstring, + bTrailingWildcard, pFromKey, &uiFromKeyPos, bFromAtFirst, + pUntilKey, &uiUntilKeyPos, bUntilAtEnd, pValue, + uiValueLen, &bDataTruncated, &bDoneBuilding, + &bOriginalCharsLost))) + { + goto Exit; + } + + if (bOriginalCharsLost) + { + bMustNotDoKeyMatch = TRUE; + } + break; + } + + // Build NUMBER or CONTEXT type piece VISIT: Add a true number type + // so we don't have to build a NODE. + + case FLM_NUMBER_TYPE: + case FLM_CONTEXT_TYPE: + { + switch (pCurPred->pVal->eType) + { + case FLM_INT32_VAL: + { + FLMINT iValue = pCurPred->pVal->val.iVal; + if (pCurPred->eOperator == FLM_GT_OP) + { + iValue++; + } + + if (IFD_GET_FIELD_TYPE( pIfd) == FLM_NUMBER_TYPE) + { + flmIntToBCD( iValue, pNumberBuf, &uiTempLen); + } + else + { + UD2FBA( iValue, pNumberBuf); + uiTempLen = 4; + } + break; + } + + case FLM_UINT32_VAL: + case FLM_REC_PTR_VAL: + { + FLMUINT uiValue = pCurPred->pVal->val.uiVal; + if (pCurPred->eOperator == FLM_GT_OP) + { + uiValue++; + } + + if (IFD_GET_FIELD_TYPE( pIfd) == FLM_NUMBER_TYPE) + { + flmUintToBCD( uiValue, pNumberBuf, &uiTempLen); + } + else + { + UD2FBA( uiValue, pNumberBuf); + uiTempLen = 4; + } + break; + } + + default: + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + } + + switch (pCurPred->eOperator) + { + case FLM_EQ_OP: + { + break; + } + + case FLM_GE_OP: + case FLM_GT_OP: + { + bUntilAtEnd = TRUE; + break; + } + + case FLM_LE_OP: + { + bFromAtFirst = TRUE; + break; + } + + case FLM_LT_OP: + { + bFromAtFirst = TRUE; + *pbExclusiveUntilKey = TRUE; + break; + } + + default: + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + } + + if (RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, + pFromKey, &uiFromKeyPos, bFromAtFirst, pUntilKey, + &uiUntilKeyPos, bUntilAtEnd, (FLMBYTE*) pNumberBuf, + uiTempLen, &bDataTruncated, &bDoneBuilding))) + { + goto Exit; + } + + break; + } + + case FLM_BINARY_TYPE: + { + FLMBOOL bMatchBegin = FALSE; + + switch (pCurPred->eOperator) + { + case FLM_MATCH_BEGIN_OP: + { + bMatchBegin = TRUE; + break; + } + + case FLM_EQ_OP: + { + break; + } + + case FLM_GE_OP: + { + bUntilAtEnd = TRUE; + break; + } + + case FLM_GT_OP: + { + bUntilAtEnd = TRUE; + bDoKeyMatch = TRUE; + break; + } + + case FLM_LE_OP: + { + bFromAtFirst = TRUE; + break; + } + + case FLM_LT_OP: + { + bFromAtFirst = TRUE; + *pbExclusiveUntilKey = TRUE; + break; + } + + default: + { + rc = RC_SET( FERR_CURSOR_SYNTAX); + goto Exit; + } + } + + if (RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, bMatchBegin, + pFromKey, &uiFromKeyPos, bFromAtFirst, pUntilKey, + &uiUntilKeyPos, bUntilAtEnd, pCurPred->pVal->val.pucBuf, + pCurPred->pVal->uiBufLen, &bDataTruncated, + &bDoneBuilding))) + { + goto Exit; + } + + break; + } + + default: + { + flmAssert( 0); + break; + } + } + + if (bDataTruncated) + { + bMustNotDoKeyMatch = TRUE; + } + } + + // Really rare case where FROM/UNTIL keys are exactly the same. + + if (!bDoneBuilding && (uiIfdCnt + 1 == 0) && + uiUntilKeyPos < uiMaxKeySize - 2) + { + + // Always make the until key exclusive. pbExclusiveUntilKey = FALSE; + + pUntilKey[uiUntilKeyPos++] = 0xFF; + pUntilKey[uiUntilKeyPos++] = 0xFF; + } + +Exit: + + if (bMustNotDoKeyMatch) + { + *pbDoKeyMatch = FALSE; + *pbDoRecMatch = TRUE; + } + else if (bDoKeyMatch || !pIxd->uiContainerNum) + { + *pbDoKeyMatch = TRUE; + } + + // Special case for building FIRST/LAST keys. + + if (!uiFromKeyPos) + { + *pFromKey = '\0'; + uiFromKeyPos = 1; + } + + if (!uiUntilKeyPos) + { + f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); + uiUntilKeyPos = uiMaxKeySize - 2; + } + + *puiFromKeyLen = uiFromKeyPos; + *puiUntilKeyLen = uiUntilKeyPos; + + return (rc); +} + +/**************************************************************************** +Desc: Truncate the length of the text buffer on the first wild card. +****************************************************************************/ +FSTATIC FLMBOOL flmFindWildcard( + FLMBYTE * pVal, + FLMUINT * puiCharPos) +{ + FLMBOOL bHaveChar = FALSE; + FLMBYTE * pSaveVal = pVal; + FLMUINT uiObjLength; + FLMUINT uiLen = *puiCharPos; + + for (; *pVal; pVal += uiObjLength, uiLen = (uiObjLength < uiLen) + ? uiLen - uiObjLength + : 0) + { + switch ((FLMUINT) (flmTextObjType( *pVal))) + { + case ASCII_CHAR_CODE: // 0nnnnnnn + { + if (*pVal == ASCII_WILDCARD) + { + bHaveChar = TRUE; + goto Exit; + } + + uiObjLength = 1; + + // Check for '*' or '\\' after an escape character. + + if (*pVal == ASCII_BACKSLASH && + (*(pVal + 1) == ASCII_WILDCARD || + *(pVal + 1) == ASCII_BACKSLASH)) + { + uiObjLength++; + } + + break; + } + + case WHITE_SPACE_CODE: // 110nnnnn + { + uiObjLength = 1; + break; + } + + case CHAR_SET_CODE: // 10nnnnnn + case UNK_EQ_1_CODE: + case OEM_CODE: + { + uiObjLength = 2; + break; + } + + case UNICODE_CODE: // Unconvertable UNICODE code + case EXT_CHAR_CODE: + { + uiObjLength = 3; + break; + } + + case UNK_GT_255_CODE: + { + uiObjLength = 1 + sizeof(FLMUINT16) + FB2UW( pVal + 1); + break; + } + + case UNK_LE_255_CODE: + { + uiObjLength = 2 + (FLMUINT16) * (pVal + 1); + break; + } + + default: + { + // should NEVER happen: bug if does + + flmAssert( 0); + uiObjLength = 1; + break; + } + } + } + +Exit: + + *puiCharPos = (FLMUINT) (pVal - pSaveVal); + return (bHaveChar); +} + +/**************************************************************************** +Desc: Add a key piece to the from and until key. Text fields are not + handled in this routine because of their complexity. +Note: The goal of this code is to build a the collated compound piece for + the 'from' and 'until' key only once instead of twice. +****************************************************************************/ +FSTATIC RCODE flmAddKeyPiece( + FLMUINT uiMaxKeySize, + IFD * pIfd, + FLMBOOL bDoMatchBegin, + FLMBYTE * pFromKey, + FLMUINT * puiFromKeyPos, + FLMBOOL bFromAtFirst, + FLMBYTE * pUntilKey, + FLMUINT * puiUntilKeyPos, + FLMBOOL bUntilAtEnd, + FLMBYTE * pBuf, + FLMUINT uiBufLen, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbDoneBuilding) +{ + RCODE rc = FERR_OK; + FLMUINT uiFromKeyPos = *puiFromKeyPos; + FLMUINT uiUntilKeyPos = *puiUntilKeyPos; + FLMBYTE * pDestKey; + FLMUINT uiDestKeyLen; + + if (pIfd->uiCompoundPos == 0 && bFromAtFirst && bUntilAtEnd) + { + + // Special case for the first piece - FIRST to LAST - zero length + // keys. so that the caller can get the number of references for the + // entire index. VISIT: May want to set the from key to have 1 byte + // and set high values for the until key. This way the caller never + // checks this special case. + + *pbDoneBuilding = TRUE; + goto Exit; + } + + // Handle the CONTEXT exception here - this is not done in kyCollate. + + if (pIfd->uiFlags & IFD_CONTEXT) + { + pFromKey[uiFromKeyPos] = KY_CONTEXT_PREFIX; + flmUINT16ToBigEndian( (FLMUINT16) pIfd->uiFldNum, &pFromKey[uiFromKeyPos + 1]); + uiFromKeyPos += KY_CONTEXT_LEN; + + if (uiUntilKeyPos + KY_CONTEXT_LEN < uiMaxKeySize) + { + pUntilKey[uiUntilKeyPos] = KY_CONTEXT_PREFIX; + flmUINT16ToBigEndian( (FLMUINT16) pIfd->uiFldNum, &pUntilKey[uiUntilKeyPos + 1]); + uiUntilKeyPos += KY_CONTEXT_LEN; + } + + goto Exit; + } + + if (bFromAtFirst) + { + if (bUntilAtEnd) + { + + // Not the first piece and need to go from first to last. + + *pbDoneBuilding = TRUE; + + if (uiUntilKeyPos < uiMaxKeySize - 2) + { + if (uiUntilKeyPos > 0) + { + + // Instead of filling the key with 0xFF, increment the + // marker. + + pUntilKey[uiUntilKeyPos - 1]++; + } + else + { + f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); + uiUntilKeyPos = uiMaxKeySize - 2; + } + } + + goto Exit; + } + + if (uiUntilKeyPos >= uiMaxKeySize - 2) + { + goto Exit; + } + + // Have a LAST key but no FROM key. + + pDestKey = pUntilKey + uiUntilKeyPos; + uiDestKeyLen = uiMaxKeySize - uiUntilKeyPos; + } + else + { + pDestKey = pFromKey + uiFromKeyPos; + uiDestKeyLen = uiMaxKeySize - uiFromKeyPos; + } + + rc = KYCollateValue( pDestKey, &uiDestKeyLen, (FLMBYTE*) pBuf, uiBufLen, + pIfd->uiFlags, pIfd->uiLimit, NULL, NULL, 0, TRUE, FALSE, + FALSE, pbDataTruncated); + + if (rc == FERR_CONV_DEST_OVERFLOW) + { + rc = FERR_OK; + } + else if (RC_BAD( rc)) + { + goto Exit; + } + + // If we just built the FROM key, we may want to copy to the UNTIL key. + + if (pDestKey == pFromKey + uiFromKeyPos) + { + uiFromKeyPos += uiDestKeyLen; + + // Unless the UNTIL key is full, the length is at or less than FROM + // key. + + if (!bUntilAtEnd) + { + if (uiUntilKeyPos + uiDestKeyLen <= uiMaxKeySize) + { + f_memcpy( &pUntilKey[uiUntilKeyPos], pDestKey, uiDestKeyLen); + uiUntilKeyPos += uiDestKeyLen; + } + + if (bDoMatchBegin) + { + flmAssert( IFD_GET_FIELD_TYPE( pIfd) == FLM_BINARY_TYPE); + + if (uiUntilKeyPos < MAX_KEY_SIZ - 2) + { + + // Optimization - only need to set a single byte to 0xFF. + // We can do this because this routine does not deal with + // text key pieces and binary, number and context will + // never have 0xFF bytes. + + pUntilKey[uiUntilKeyPos++] = 0xFF; + } + + // We don't need to set *pbDoneBuilding = TRUE, because we + // may be able to continue building the from key + + } + } + else + { + if (uiUntilKeyPos > 0) + { + + // Instead of filling the key with 0xFF, increment the marker. + + pUntilKey[uiUntilKeyPos - 1]++; + } + else + { + + // Optimization - only need to set a single byte to 0xFF. We + // can do this because this routine does not deal with text + // key pieces and binary, number and context will never have + // 0xFF bytes. + + flmAssert( IFD_GET_FIELD_TYPE( pIfd) != FLM_TEXT_TYPE); + + *pUntilKey = 0xFF; + uiUntilKeyPos++; + } + } + } + else + { + uiUntilKeyPos += uiDestKeyLen; + } + +Exit: + + // Set the FROM and UNTIL key length return values. + + *puiFromKeyPos = uiFromKeyPos; + *puiUntilKeyPos = uiUntilKeyPos; + return (rc); +} + +/**************************************************************************** +Desc: Add a text piece to the from and until key. +****************************************************************************/ +FSTATIC RCODE flmAddTextPiece( + FLMUINT uiMaxKeySize, + IFD * pIfd, + FLMBOOL bCaseInsensitive, + FLMBOOL bDoMatchBegin, + FLMBOOL bDoFirstSubstring, + FLMBOOL bTrailingWildcard, + FLMBYTE * pFromKey, + FLMUINT * puiFromKeyPos, + FLMBOOL bFromAtFirst, + FLMBYTE * pUntilKey, + FLMUINT * puiUntilKeyPos, + FLMBOOL bUntilAtEnd, + FLMBYTE * pBuf, + FLMUINT uiBufLen, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbDoneBuilding, + FLMBOOL * pbOriginalCharsLost) +{ + RCODE rc = FERR_OK; + FLMUINT uiFromKeyPos = *puiFromKeyPos; + FLMUINT uiUntilKeyPos = *puiUntilKeyPos; + FLMUINT uiLanguage = pIfd->pIxd->uiLanguage; + FLMBYTE * pDestKey; + FLMUINT uiDestKeyLen; + FLMUINT uiCollationLen = 0; + FLMUINT uiCaseLen; + FLMBOOL bIsDBCS; + + bIsDBCS = (uiLanguage >= FIRST_DBCS_LANG && uiLanguage <= LAST_DBCS_LANG) + ? TRUE + : FALSE; + *pbOriginalCharsLost = FALSE; + if (pIfd->uiCompoundPos == 0 && bFromAtFirst && bUntilAtEnd) + { + + // Special case for the first piece - FIRST to LAST - zero length + // keys. so that the caller can get the number of references for the + // entire index. VISIT: May want to set the from key to have 1 byte + // and set high values for the until key. This way the caller never + // checks this special case. + + *pbDoneBuilding = TRUE; + goto Exit; + } + + if (bFromAtFirst) + { + if (bUntilAtEnd) + { + + // Not the first piece and need to go from first to last. + + *pbDoneBuilding = TRUE; + + if (uiUntilKeyPos < uiMaxKeySize - 2) + { + + // Instead of filling the key with 0xFF, increment the marker. + + pUntilKey[uiUntilKeyPos - 1]++; + } + + goto Exit; + } + + if (uiUntilKeyPos >= uiMaxKeySize - 2) + { + goto Exit; + } + + // Have a LAST key but no FROM key. + + pDestKey = pUntilKey + uiUntilKeyPos; + uiDestKeyLen = uiMaxKeySize - uiUntilKeyPos; + } + else // Handle below if UNTIL key is LAST. + { + pDestKey = pFromKey + uiFromKeyPos; + uiDestKeyLen = uiMaxKeySize - uiFromKeyPos; + } + + // Add IFD_ESC_CHAR to the ifd flags because the search string must + // have BACKSLASHES and '*' escaped. + + rc = KYCollateValue( pDestKey, &uiDestKeyLen, (FLMBYTE*) pBuf, uiBufLen, + pIfd->uiFlags | IFD_ESC_CHAR, pIfd->uiLimit, + &uiCollationLen, &uiCaseLen, uiLanguage, TRUE, + bDoFirstSubstring, bTrailingWildcard, pbDataTruncated, + pbOriginalCharsLost); + + if (rc == FERR_CONV_DEST_OVERFLOW) + { + rc = FERR_OK; + } + else if (RC_BAD( rc)) + { + goto Exit; + } + + if (pIfd->uiFlags & IFD_POST) + { + uiDestKeyLen -= uiCaseLen; + } + else + { + + // Special case: The index is NOT an upper index and the search is + // case-insensitive. The FROM key must have lower case values and + // the UNTIL must be the upper case values. This will be true for + // Asian indexes also. + + if (uiDestKeyLen && + (bIsDBCS || (!(pIfd->uiFlags & IFD_UPPER) && bCaseInsensitive))) + { + + // Subtract off all but the case marker. Remember that for DBCS + // (Asian) the case marker is two bytes. + + uiDestKeyLen -= (uiCaseLen - ((FLMUINT) (bIsDBCS ? 2 : 1))); + + // NOTE: SC_LOWER is only used in GREEK indexes, which is why we + // use it here instead of SC_MIXED. + + pDestKey[uiDestKeyLen - 1] = + (FLMBYTE) ((uiLanguage != (FLMUINT) GR_LANG) + ? COLL_MARKER | SC_MIXED + : COLL_MARKER | SC_LOWER); + + // Once the FROM key has been approximated, we are done building. + + *pbDoneBuilding = TRUE; + } + } + + // Copy or move pieces of the FROM key into the UNTIL key. + + if (pDestKey == pFromKey + uiFromKeyPos) + { + if (uiUntilKeyPos < uiMaxKeySize - 2) + { + if (!bUntilAtEnd) + { + if (bDoMatchBegin) + { + if (uiCollationLen) + { + f_memcpy( &pUntilKey[uiUntilKeyPos], pDestKey, uiCollationLen); + uiUntilKeyPos += uiCollationLen; + } + + // Fill the rest of the key with high values. + + f_memset( &pUntilKey[uiUntilKeyPos], 0xFF, + (uiMaxKeySize - 2) - uiUntilKeyPos); + uiUntilKeyPos = uiMaxKeySize - 2; + + // Don't need to set the done building flag to TRUE. + + } + else if (uiDestKeyLen) + { + if (!bDoFirstSubstring) + { + f_memcpy( &pUntilKey[uiUntilKeyPos], pDestKey, uiDestKeyLen); + uiUntilKeyPos += uiDestKeyLen; + } + else + { + + // Do two copies so that the first substring byte is + // gone. + + f_memcpy( &pUntilKey[uiUntilKeyPos], pDestKey, uiCollationLen); + uiUntilKeyPos += uiCollationLen; + if (bIsDBCS) + { + uiCollationLen++; + } + + uiCollationLen++; + f_memcpy( &pUntilKey[uiUntilKeyPos], pDestKey + uiCollationLen, + uiDestKeyLen - uiCollationLen); + uiUntilKeyPos += (uiDestKeyLen - uiCollationLen); + } + + // Special case again : raw case in index and search + // comparison. Case has already been completely removed if + // it is a post index, so no need to change the marker + // byte. + + if (!(pIfd->uiFlags & IFD_POST) && (bIsDBCS || + (!(pIfd->uiFlags & IFD_UPPER) && bCaseInsensitive))) + { + + // Add 1 to make sure the until key is higher than the + // upper value. + + pUntilKey[uiUntilKeyPos - 1] = (COLL_MARKER | SC_UPPER) + 1; + } + } + } + else + { + if (uiUntilKeyPos > 0) + { + + // Instead of filling the key with 0xFF, increment the + // marker. + + pUntilKey[uiUntilKeyPos - 1]++; + } + else + { + + // Keys can have 0xFF values in them, so it is not + // sufficient to set only uiDestKeyLen bytes to 0xFF. We + // must set the entire key. + + f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); + uiUntilKeyPos = uiMaxKeySize - 2; + } + } + } + + uiFromKeyPos += uiDestKeyLen; + } + else + { + + // We just built the UNTIL key. The FROM key doesn't need to be + // built. + + uiUntilKeyPos += uiDestKeyLen; + } + +Exit: + + // Set the FROM and UNTIL keys + + *puiFromKeyPos = uiFromKeyPos; + *puiUntilKeyPos = uiUntilKeyPos; + return (rc); +} + +/**************************************************************************** +Desc: Select the best substring for a CONTAINS or MATCH_END search. Look + below for the algorithm. +****************************************************************************/ +FSTATIC FLMBOOL flmSelectBestSubstr( + FLMBYTE ** ppValue, + FLMUINT * puiValueLen, + FLMUINT uiIfdFlags, + FLMBOOL * pbTrailingWildcard) +{ + FLMBYTE * pValue = *ppValue; + FLMBYTE * pCurValue; + FLMBYTE * pBest; + FLMBOOL bBestTerminatesWithWildCard = *pbTrailingWildcard; + FLMUINT uiCurLen; + FLMUINT uiBestNumChars; + FLMUINT uiBestValueLen; + FLMUINT uiWildcardPos = 0; + FLMUINT uiTargetNumChars; + FLMUINT uiNumChars; + FLMBOOL bNotUsingFirstOfString = FALSE; + + #define GOOD_ENOUGH_CHARS 16 + + // There may not be any wildcards at all. Find the first one. + + if (flmFindWildcard( pValue, &uiWildcardPos)) + { + bBestTerminatesWithWildCard = TRUE; + pBest = pValue; + pCurValue = pValue + uiWildcardPos + 1; + uiCurLen = *puiValueLen - (uiWildcardPos + 1); + + uiBestValueLen = uiWildcardPos; + uiBestNumChars = flmCountCharacters( pValue, uiWildcardPos, + GOOD_ENOUGH_CHARS, uiIfdFlags); + uiTargetNumChars = uiBestNumChars + uiBestNumChars; + + while (uiBestNumChars < GOOD_ENOUGH_CHARS && *pCurValue) + { + if (flmFindWildcard( pCurValue, &uiWildcardPos)) + { + uiNumChars = flmCountCharacters( pCurValue, uiWildcardPos, + GOOD_ENOUGH_CHARS, uiIfdFlags); + if (uiNumChars >= uiTargetNumChars) + { + pBest = pCurValue; + uiBestValueLen = uiWildcardPos; + uiBestNumChars = uiNumChars; + uiTargetNumChars = uiNumChars + uiNumChars; + } + else + { + uiTargetNumChars += 2; + } + + pCurValue = pCurValue + uiWildcardPos + 1; + uiCurLen -= uiWildcardPos + 1; + } + else + { + + // Check the last section that may or may not have trailing *. + + uiNumChars = flmCountCharacters( pCurValue, uiCurLen, + GOOD_ENOUGH_CHARS, uiIfdFlags); + if (uiNumChars >= uiTargetNumChars) + { + pBest = pCurValue; + uiBestValueLen = uiCurLen; + bBestTerminatesWithWildCard = *pbTrailingWildcard; + } + break; + } + } + + if (pBest != *ppValue) + { + bNotUsingFirstOfString = TRUE; + } + + *ppValue = pBest; + *puiValueLen = uiBestValueLen; + *pbTrailingWildcard = bBestTerminatesWithWildCard; + } + + return (bNotUsingFirstOfString); +} + +/**************************************************************************** +Desc: Returns true if this text will generate a single characater key. +****************************************************************************/ +FSTATIC FLMUINT flmCountCharacters( + FLMBYTE * pValue, + FLMUINT uiValueLen, + FLMUINT uiMaxToCount, + FLMUINT uiIfdFlags) +{ + FLMUINT uiNumChars = 0; + FLMUINT uiObjLength; + + for (uiObjLength = 0; + uiNumChars <= uiMaxToCount && uiValueLen; + pValue += uiObjLength, uiValueLen = + (uiValueLen >= uiObjLength) ? uiValueLen - uiObjLength : 0) + { + switch ((FLMUINT) (flmTextObjType( *pValue))) + { + case ASCII_CHAR_CODE: // 0nnnnnnn + { + uiObjLength = 1; + if (*pValue == ASCII_SPACE) + { + + // Ignore if using space rules. VISIT: Need to address ending + // spaces before a wildcard. + + if (uiIfdFlags & (IFD_MIN_SPACES | IFD_NO_SPACE)) + { + break; + } + + uiNumChars++; + } + else if (*pValue == ASCII_UNDERSCORE) + { + + // Ignore if using the underscore space rules. VISIT: Need to + // address ending spaces before a wildcard. + + if (uiIfdFlags & IFD_NO_UNDERSCORE) + { + break; + } + + uiNumChars++; + } + else if (*pValue == ASCII_DASH) + { + if (uiIfdFlags & IFD_NO_DASH) + { + break; + } + + uiNumChars++; + } + else if (*pValue == ASCII_BACKSLASH && + (*(pValue + 1) == ASCII_WILDCARD || + *(pValue + 1) == ASCII_BACKSLASH)) + { + uiObjLength++; + uiNumChars++; + } + else + { + uiNumChars++; + } + + break; + } + + case WHITE_SPACE_CODE: // 110nnnnn + { + uiObjLength = 1; + uiNumChars++; + break; + } + + case CHAR_SET_CODE: // 10nnnnnn + case UNK_EQ_1_CODE: + case OEM_CODE: + { + uiObjLength = 2; + uiNumChars++; + break; + } + + case UNICODE_CODE: // Unconvertable UNICODE code + case EXT_CHAR_CODE: + { + uiObjLength = 3; + uiNumChars++; + break; + } + + case UNK_GT_255_CODE: + { + uiObjLength = 1 + sizeof(FLMUINT16) + FB2UW( pValue + 1); + break; + } + + case UNK_LE_255_CODE: + { + uiObjLength = 2 + (FLMUINT16) * (pValue + 1); + break; + } + + default: + { + // should NEVER happen: bug if does + + flmAssert( 0); + uiObjLength = 1; + break; + } + } + } + + return (uiNumChars); +} + +/**************************************************************************** +Desc: Cheating routine to blast out an internal number without using the + pool to allocate space. +****************************************************************************/ +FSTATIC void flmUintToBCD( + FLMUINT uiNum, + FLMBYTE * pNumberBuf, + FLMUINT * puiValueLen) +{ + FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; + FLMBYTE * pucNibStk; + + pucNibStk = &ucNibStk[1]; + *pucNibStk++ = 0x0F; + + while (uiNum >= 10) + { + *pucNibStk++ = (FLMBYTE) (uiNum % 10); + uiNum /= 10; + } + + *pucNibStk++ = (FLMBYTE) uiNum; + *puiValueLen = (pucNibStk - ucNibStk) >> 1; + + do + { + *pNumberBuf++ = (FLMBYTE) ((pucNibStk[-1] << 4) | pucNibStk[-2]); + } while ((pucNibStk -= 2) > &ucNibStk[1]); +} + +/**************************************************************************** +Desc: Cheating routine to blast out an internal number without using the + pool to allocate space. Code taken from gnbcd.cpp. +****************************************************************************/ +FSTATIC void flmIntToBCD( + FLMINT iNum, + FLMBYTE * pNumberBuf, + FLMUINT * puiValueLen) +{ + FLMUINT uiNum; + FLMBYTE ucNibStk[F_MAX_NUM_BUF + 1]; + FLMBYTE * pucNibStk; + FLMINT iNegFlag; + + ucNibStk[0] = 0; + ucNibStk[1] = 0x0F; + pucNibStk = &ucNibStk[2]; + uiNum = ((iNegFlag = iNum < 0) != 0) ? -iNum : iNum; + + while (uiNum >= 10) + { + *pucNibStk++ = (FLMBYTE) (uiNum % 10); + uiNum /= 10; + } + + *pucNibStk++ = (FLMBYTE) uiNum; + + if (iNegFlag) + { + *pucNibStk++ = 0x0B; + } + + *puiValueLen = (pucNibStk - ucNibStk) >> 1; + + do + { + *pNumberBuf++ = (FLMBYTE) ((pucNibStk[-1] << 4) | pucNibStk[-2]); + } while ((pucNibStk -= 2) > &ucNibStk[1]); +} diff --git a/flaim/src/fqlog.cpp b/flaim/src/fqlog.cpp index b1f6935..3e9e003 100644 --- a/flaim/src/fqlog.cpp +++ b/flaim/src/fqlog.cpp @@ -331,7 +331,7 @@ FSTATIC void flmLogText( } ucChar = *pucBuf; - uiObjType = GedTextObjType( ucChar); + uiObjType = flmTextObjType( ucChar); switch (uiObjType) { case ASCII_CHAR_CODE: // 0nnnnnnn @@ -546,7 +546,7 @@ FSTATIC void flmLogSubQuery( SUBQUERY * pSubQuery ) { - FQNODE_p pQNode; + FQNODE * pQNode; QTYPES eCurrentOp; QTYPES eTmpParentOp; FLMBYTE * pucFromKey; @@ -623,7 +623,7 @@ FSTATIC void flmLogSubQuery( bIndentOptInfo = FALSE; pLogMsg->newline(); uiIndent += 2; - flmLogQuery( pLogMsg, uiIndent, (CURSOR_p)hCursor); + flmLogQuery( pLogMsg, uiIndent, (CURSOR *)hCursor); uiIndent -= 2; flmLogIndent( pLogMsg, uiIndent); flmLogOperator( pLogMsg, FLM_RPAREN_OP, FALSE); @@ -844,7 +844,7 @@ Desc: This routine logs the query criteria for a cursor. void flmLogQuery( F_LogMessage * pLogMsg, FLMUINT uiIndent, - CURSOR_p pCursor + CURSOR * pCursor ) { SUBQUERY * pSubQuery; diff --git a/flaim/src/fqopt.cpp b/flaim/src/fqopt.cpp index 1f55ad3..0861e90 100644 --- a/flaim/src/fqopt.cpp +++ b/flaim/src/fqopt.cpp @@ -96,8 +96,8 @@ FINLINE FLMBOOL DoValAndDictTypesMatch( Desc: Clips a SUBQUERY from a list, and frees memory associated with it. */ FINLINE void flmClipSubQuery( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery + CURSOR * pCursor, + SUBQUERY * pSubQuery ) { if( pSubQuery == pCursor->pSubQueryList) @@ -122,15 +122,15 @@ FSTATIC RCODE flmAllocIndexInfo( IXD * pIxd); FSTATIC RCODE flmSQGetDrnRanges( - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, QTYPES eOperator, FLMUINT uiVal); FSTATIC RCODE flmSQGenPredicateList( FDB * pDb, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, POOL * pPool, - QPREDICATE_p * ppPredicateList, + QPREDICATE * * ppPredicateList, FLMUINT * puiTotalPredicates, FLMBOOL * pbHaveUserPredicates); @@ -151,14 +151,14 @@ FSTATIC FLMBOOL flmIxFldPathSuitable( FSTATIC RCODE flmSQGetSuitableIndexes( FDB * pDb, FLMUINT uiForceIndex, - CURSOR_p pCursor, - SUBQUERY_p pSubQuery, + CURSOR * pCursor, + SUBQUERY * pSubQuery, FLMUINT uiContainer, POOL * pPool, QPREDICATE * pPredicateList, FLMUINT uiTotalPredicates, FLMBOOL bHaveUserPredicates, - QINDEX_p * ppIndexList, + QINDEX * * ppIndexList, FLMUINT * puiMaxIfds); FSTATIC RCODE flmSQEvaluateCurrIndexKey( @@ -171,27 +171,27 @@ FSTATIC RCODE flmSQEvaluateCurrIndexKey( FSTATIC RCODE flmCheckUserPredicateCosts( FDB * pDb, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMBOOL bOkToOptimizeWithPredicate); FSTATIC RCODE flmMergeSubQueries( - CURSOR_p pCursor, - SUBQUERY_p * ppFromSubQuery, - SUBQUERY_p pIntoSubQuery, + CURSOR * pCursor, + SUBQUERY * * ppFromSubQuery, + SUBQUERY * pIntoSubQuery, FLMBOOL bFromSubQuerySubsumed); FSTATIC RCODE flmSQSetupFullContainerScan( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery); + CURSOR * pCursor, + SUBQUERY * pSubQuery); FSTATIC RCODE flmSQChooseBestIndex( - CURSOR_p pCursor, + CURSOR * pCursor, FDB * pDb, FLMUINT uiForceIndex, FLMUINT bForceFirstToLastKey, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, POOL * pTempPool, - QPREDICATE_p pPredicateList, + QPREDICATE * pPredicateList, FLMUINT uiTotalPredicates, FLMBOOL bHaveUserPredicates); @@ -199,7 +199,7 @@ FSTATIC RCODE flmSQChooseBestIndex( Desc: Keep track of DRN ranges for a subquery. ****************************************************************************/ FSTATIC RCODE flmSQGetDrnRanges( - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, QTYPES eOperator, FLMUINT uiVal ) @@ -316,9 +316,9 @@ Desc: Generate the predicate list for a sub-query. ****************************************************************************/ FSTATIC RCODE flmSQGenPredicateList( FDB * pDb, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, POOL * pPool, - QPREDICATE_p * ppPredicateList, + QPREDICATE * * ppPredicateList, FLMUINT * puiTotalPredicates, FLMBOOL * pbHaveUserPredicates) { @@ -358,7 +358,7 @@ FSTATIC RCODE flmSQGenPredicateList( // Better be a parent node that is the operator for // this field. - if ((pPredicate = (QPREDICATE_p)GedPoolCalloc( pPool, + if ((pPredicate = (QPREDICATE *)GedPoolCalloc( pPool, sizeof( QPREDICATE))) == NULL) { rc = RC_SET( FERR_MEM); @@ -829,14 +829,14 @@ Desc: Generate the list of suitable indexes for a sub-query. Rank each FSTATIC RCODE flmSQGetSuitableIndexes( FDB * pDb, FLMUINT uiForceIndex, - CURSOR_p pCursor, + CURSOR * pCursor, SUBQUERY * pSubQuery, FLMUINT uiContainer, POOL * pPool, QPREDICATE * pPredicateList, FLMUINT uiTotalPredicates, FLMBOOL bHaveUserPredicates, - QINDEX_p * ppIndexList, + QINDEX * * ppIndexList, FLMUINT * puiMaxIfds) { RCODE rc = FERR_OK; @@ -1523,8 +1523,8 @@ Exit: Desc: Set up a sub-query to do a full container scan. ****************************************************************************/ FSTATIC RCODE flmSQSetupFullContainerScan( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery + CURSOR * pCursor, + SUBQUERY * pSubQuery ) { RCODE rc = FERR_OK; @@ -1587,19 +1587,19 @@ Exit: Desc: Chooses a best index to use for a sub-query. ****************************************************************************/ FSTATIC RCODE flmSQChooseBestIndex( - CURSOR_p pCursor, + CURSOR * pCursor, FDB * pDb, FLMUINT uiForceIndex, FLMUINT bForceFirstToLastKey, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, POOL * pTempPool, - QPREDICATE_p pPredicateList, + QPREDICATE * pPredicateList, FLMUINT uiTotalPredicates, FLMBOOL bHaveUserPredicates) { RCODE rc = FERR_OK; - QINDEX_p pIndexList; - QINDEX_p pIndex; + QINDEX * pIndexList; + QINDEX * pIndex; FLMUINT uiCurrIfd; FLMUINT uiMaxIfds; QFIELD_PREDICATE ** ppFieldCurrPredicate = NULL; @@ -1923,12 +1923,12 @@ Desc: Gets scores for any embedded user predicate. ****************************************************************************/ FSTATIC RCODE flmCheckUserPredicateCosts( FDB * pDb, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMBOOL bOkToOptimizeWithPredicate ) { RCODE rc = FERR_OK; - FQNODE_p pQNode = pSubQuery->pTree; + FQNODE * pQNode = pSubQuery->pTree; FLMUINT uiCost; FLMUINT uiDrnCost; FlmUserPredicate * pPredicate; @@ -2099,9 +2099,9 @@ Exit: Desc: Merges two SUBQUERY structures. ****************************************************************************/ FSTATIC RCODE flmMergeSubQueries( - CURSOR_p pCursor, - SUBQUERY_p * ppFromSubQuery, - SUBQUERY_p pIntoSubQuery, + CURSOR * pCursor, + SUBQUERY * * ppFromSubQuery, + SUBQUERY * pIntoSubQuery, FLMBOOL bFromSubQuerySubsumed ) { @@ -2333,17 +2333,17 @@ Exit: Desc: Optimizes the passed-in query. ****************************************************************************/ RCODE flmCurOptimize( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bStratified) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; - SUBQUERY_p pSubQuery; - SUBQUERY_p pTmpSubQuery; - SUBQUERY_p pContainerScanSubQuery = NULL; + FDB * pDb = NULL; + SUBQUERY * pSubQuery; + SUBQUERY * pTmpSubQuery; + SUBQUERY * pContainerScanSubQuery = NULL; FLMBOOL bChoosingIndex; DB_STATS * pDbStats; - QPREDICATE_p pPredicateList = NULL; + QPREDICATE * pPredicateList = NULL; FLMUINT uiTotalPredicates = 0; POOL * pTempPool; void * pvMark; diff --git a/flaim/src/fqparse.cpp b/flaim/src/fqparse.cpp index 4d518df..1b213ae 100644 --- a/flaim/src/fqparse.cpp +++ b/flaim/src/fqparse.cpp @@ -1266,9 +1266,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Parse a query criteria string and populate an HFCURSOR from it. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmParseQuery( HFCURSOR hCursor, F_NameTable * pNameTable, diff --git a/flaim/src/fqprep.cpp b/flaim/src/fqprep.cpp index ee907e0..e18e456 100644 --- a/flaim/src/fqprep.cpp +++ b/flaim/src/fqprep.cpp @@ -27,45 +27,45 @@ POOL_STATS g_SubQueryOptPoolStats = {0,0}; FSTATIC void flmCurPruneNode( - FQNODE_p pQNode); + FQNODE * pQNode); FSTATIC RCODE flmCurAddSubQuery( - CURSOR_p pCursor, - FQNODE_p pQNode); + CURSOR * pCursor, + FQNODE * pQNode); FSTATIC RCODE flmCurDivideQTree( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmCurCreateSQList( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC void flmCurClipNode( - FQNODE_p pQNode); + FQNODE * pQNode); FSTATIC void flmCurReplaceNode( - FQNODE_p pNodeToReplace, - FQNODE_p pReplacementNode); + FQNODE * pNodeToReplace, + FQNODE * pReplacementNode); FSTATIC RCODE flmCurDoDeMorgan( - CURSOR_p pCursor); + CURSOR * pCursor); FSTATIC RCODE flmCurCopyQTree( - FQNODE_p pSrcTree, - FQNODE_p * ppDestTree, + FQNODE * pSrcTree, + FQNODE * * ppDestTree, POOL * pPool); FSTATIC RCODE flmCurStratify( - CURSOR_p pCursor, + CURSOR * pCursor, POOL * pPool, FLMBOOL * pbStratified, - FQNODE_p * ppTree); + FQNODE * * ppTree); /**************************************************************************** Desc: Prunes an FQNODE, along with its children, from a query tree. Ret: ****************************************************************************/ FSTATIC void flmCurPruneNode( - FQNODE_p pQNode + FQNODE * pQNode ) { // If necessary, unlink the node from any parent or siblings @@ -98,13 +98,13 @@ Desc: Allocates space for a subquery, initializes certain members, and adds Ret: ****************************************************************************/ FSTATIC RCODE flmCurAddSubQuery( - CURSOR_p pCursor, - FQNODE_p pQNode ) + CURSOR * pCursor, + FQNODE * pQNode ) { RCODE rc = FERR_OK; - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; - if ((pSubQuery = (SUBQUERY_p)GedPoolCalloc( &pCursor->SQPool, + if ((pSubQuery = (SUBQUERY *)GedPoolCalloc( &pCursor->SQPool, sizeof( SUBQUERY))) == NULL) { rc = RC_SET( FERR_MEM); @@ -121,7 +121,7 @@ FSTATIC RCODE flmCurAddSubQuery( } else { - SUBQUERY_p pTmpSubQuery; + SUBQUERY * pTmpSubQuery; for( pTmpSubQuery = pCursor->pSubQueryList; pTmpSubQuery->pNext; @@ -140,12 +140,12 @@ Desc: Scans a query tree and breaks it into a set of conjunct subqueries. ****************************************************************************/ FSTATIC RCODE flmCurDivideQTree( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - FQNODE_p pQNode; - FQNODE_p pParent; + FQNODE * pQNode; + FQNODE * pParent; // Caller has already verified that pCursor->pTree is non-NULL. @@ -208,7 +208,7 @@ Desc: Scans a query tree and breaks it into a set of Ret: ****************************************************************************/ FSTATIC RCODE flmCurCreateSQList( - CURSOR_p pCursor) + CURSOR * pCursor) { RCODE rc = FERR_OK; @@ -240,9 +240,9 @@ FSTATIC RCODE flmCurCreateSQList( Desc: Clips an FQNODE from a query tree, grafting its children to its parent. ****************************************************************************/ FSTATIC void flmCurClipNode( - FQNODE_p pQNode) + FQNODE * pQNode) { - FQNODE_p pTmpQNode; + FQNODE * pTmpQNode; // If necessary, unlink pQNode from its parent, children and siblings @@ -298,11 +298,11 @@ FSTATIC void flmCurClipNode( Desc: Replace one node with another node in the tree. ****************************************************************************/ FSTATIC void flmCurReplaceNode( - FQNODE_p pNodeToReplace, - FQNODE_p pReplacementNode + FQNODE * pNodeToReplace, + FQNODE * pReplacementNode ) { - FQNODE_p pParentNode; + FQNODE * pParentNode; FLMBOOL bLinkAsFirst = (pNodeToReplace->pNextSib) ? TRUE : FALSE; pParentNode = pNodeToReplace->pParent; @@ -326,11 +326,11 @@ Desc: Applies DeMorgan's laws to get rid of NOT operators in a tree - this is necessary to do before we optimize the query. ****************************************************************************/ FSTATIC RCODE flmCurDoDeMorgan( - CURSOR_p pCursor + CURSOR * pCursor ) { RCODE rc = FERR_OK; - FQNODE_p pQNode; + FQNODE * pQNode; FLMBOOL bNotted; QTYPES eOp; @@ -454,7 +454,7 @@ FSTATIC RCODE flmCurDoDeMorgan( if (pQNode->eOpType == FLM_NOT_OP) { - FQNODE_p pKeepNode; + FQNODE * pKeepNode; bNotted = !bNotted; @@ -480,9 +480,9 @@ FSTATIC RCODE flmCurDoDeMorgan( { FLMUINT uiLeftBoolVal = 0; FLMUINT uiRightBoolVal = 0; - FQNODE_p pLeftNode = pQNode->pChild; - FQNODE_p pRightNode = pLeftNode->pNextSib; - FQNODE_p pReplacementNode = NULL; + FQNODE * pLeftNode = pQNode->pChild; + FQNODE * pRightNode = pLeftNode->pNextSib; + FQNODE * pReplacementNode = NULL; if (pLeftNode->eOpType == FLM_BOOL_VAL) { @@ -598,9 +598,9 @@ Desc: Copies a passed-in query node into a new node, using the passed-in memory pool. ****************************************************************************/ RCODE flmCurCopyQNode( - FQNODE_p pSrcNode, - QTINFO_p pDestQTInfo, - FQNODE_p * ppDestNode, + FQNODE * pSrcNode, + QTINFO * pDestQTInfo, + FQNODE * * ppDestNode, POOL * pPool) { RCODE rc = FERR_OK; @@ -612,7 +612,7 @@ RCODE flmCurCopyQNode( FLMUINT uiLen; FLMUINT uiFlags; FLMUINT uiCnt; - FQNODE_p pDestNd; + FQNODE * pDestNd; if( IS_OP( pSrcNode->eOpType)) { @@ -800,14 +800,14 @@ Desc: Copies a passed-in query tree into a new tree, using the passed-in memory pool. ****************************************************************************/ FSTATIC RCODE flmCurCopyQTree( - FQNODE_p pSrcTree, - FQNODE_p * ppDestTree, + FQNODE * pSrcTree, + FQNODE * * ppDestTree, POOL * pPool) { RCODE rc = FERR_OK; - FQNODE_p pQNode; - FQNODE_p pDestNode; - FQNODE_p pParentNode; + FQNODE * pQNode; + FQNODE * pDestNode; + FQNODE * pParentNode; // Don't try to copy a NULL tree. @@ -881,26 +881,26 @@ Desc: Applies associativity to logical operators in a query tree to render Ret: ****************************************************************************/ FSTATIC RCODE flmCurStratify( - CURSOR_p pCursor, + CURSOR * pCursor, POOL * pPool, FLMBOOL * pbStratified, - FQNODE_p * ppTree) + FQNODE * * ppTree) { RCODE rc = FERR_OK; QTYPES eOp; QTYPES eLeftOp; QTYPES eRightOp; - FQNODE_p pTree = *ppTree; - FQNODE_p pOrOp; - FQNODE_p pOtherAndOp; - FQNODE_p pOtherAndOpCopy = NULL; - FQNODE_p pOrLeftOp; - FQNODE_p pOrRightOp; - FQNODE_p pNewAndOp1; - FQNODE_p pNewAndOp2; - FQNODE_p pNewOrOp; - FQNODE_p pAndParent; - FQNODE_p pCurrNode; + FQNODE * pTree = *ppTree; + FQNODE * pOrOp; + FQNODE * pOtherAndOp; + FQNODE * pOtherAndOpCopy = NULL; + FQNODE * pOrLeftOp; + FQNODE * pOrRightOp; + FQNODE * pNewAndOp1; + FQNODE * pNewAndOp2; + FQNODE * pNewOrOp; + FQNODE * pAndParent; + FQNODE * pCurrNode; FLMBOOL bStratified = TRUE; void * pvMark = GedPoolMark( pPool); FLMUINT uiCount = 0; @@ -1081,7 +1081,7 @@ Desc: Prepares a query for subsequent use by partitioning it and optimizing its subqueries. ****************************************************************************/ RCODE flmCurPrep( - CURSOR_p pCursor) + CURSOR * pCursor) { RCODE rc = FERR_OK; FLMBOOL bStratified; diff --git a/flaim/src/fqread.cpp b/flaim/src/fqread.cpp index 2e570cb..b350bad 100644 --- a/flaim/src/fqread.cpp +++ b/flaim/src/fqread.cpp @@ -25,14 +25,14 @@ #include "flaimsys.h" FSTATIC RCODE flmCurCSPerformRead( - CURSOR_p pCursor, + CURSOR * pCursor, eFlmFuncs eFlmFuncId, FlmRecord ** ppRecordRV, FLMUINT * puiDrnRV, FLMUINT * puiCountRV); FSTATIC RCODE flmCurGetDRNRec( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDRN, FlmRecord ** ppRecord); @@ -40,13 +40,13 @@ FSTATIC RCODE flmCurGetDRNRec( Desc: Gets the requested record, DRN, or count over the CS line. ****************************************************************************/ FSTATIC RCODE flmCurCSPerformRead( - CURSOR_p pCursor, + CURSOR * pCursor, eFlmFuncs eFlmFuncId, FlmRecord ** ppRecordRV, FLMUINT * puiDrnRV, FLMUINT * puiCountRV) { - CS_CONTEXT_p pCSContext = pCursor->pCSContext; + CS_CONTEXT * pCSContext = pCursor->pCSContext; FCL_WIRE Wire( pCSContext); void * pvMark = GedPoolMark( &pCSContext->pool); RCODE rc = FERR_OK; @@ -329,12 +329,12 @@ Exit: Desc: Gets the requested record given a DRN. ****************************************************************************/ FSTATIC RCODE flmCurGetDRNRec( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDRN, FlmRecord ** ppRecord) { RCODE rc = FERR_OK; - FDB_p pDb = NULL; + FDB * pDb = NULL; LFILE * pLFile; if (pCursor->pCSContext) @@ -391,16 +391,15 @@ Exit: return( rc); } -/*API~*********************************************************************** -Desc : Retrieves the record currently pointed to by a cursor. -*END************************************************************************/ +/**************************************************************************** +Desc: Retrieves the record currently pointed to by a cursor. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorCurrent( HFCURSOR hCursor, - FlmRecord ** ppRecord - ) + FlmRecord ** ppRecord) { - RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; + RCODE rc = FERR_OK; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -408,6 +407,7 @@ FLMEXP RCODE FLMAPI FlmCursorCurrent( rc = RC_SET( FERR_INVALID_PARM); goto Exit; } + *ppRecord = NULL; if (pCursor->uiLastRecID == 0) @@ -431,19 +431,19 @@ FLMEXP RCODE FLMAPI FlmCursorCurrent( } Exit: + return( rc); } -/*API~*********************************************************************** -Desc : Retrieves the DRN of the current record in a set defined by a cursor. -*END************************************************************************/ +/**************************************************************************** +Desc: Retrieves the DRN of the current record in a set defined by a cursor. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorCurrentDRN( HFCURSOR hCursor, - FLMUINT * puiDrn - ) + FLMUINT * puiDrn) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -472,27 +472,27 @@ FLMEXP RCODE FLMAPI FlmCursorCurrentDRN( } Exit: + return( rc); } -/*API~*********************************************************************** -Desc : Positions the cursor to a next or previous item at an offset relative - to the current item and retrieves that item from the database. -Notes: Requests that position beyond the end of the result set will - cause an EOF_HIT error to be returned. Likewise, requests that - position before the beginning of the result set will cause a - BOF_HIT error to be returned. Passing a relative position of 0 is - invalid and will cause ILLEGAL_OP to be returned. -*END************************************************************************/ +/**************************************************************************** +Desc: Positions the cursor to a next or previous item at an offset relative + to the current item and retrieves that item from the database. +Note: Requests that position beyond the end of the result set will + cause an EOF_HIT error to be returned. Likewise, requests that + position before the beginning of the result set will cause a + BOF_HIT error to be returned. Passing a relative position of 0 is + invalid and will cause ILLEGAL_OP to be returned. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorMoveRelative( HFCURSOR hCursor, FLMINT * piPosition, - FlmRecord ** ppRecord - ) + FlmRecord ** ppRecord) { - RCODE rc = FERR_OK; - FLMINT iPosition; - FLMUINT uiTmpPos; + RCODE rc = FERR_OK; + FLMINT iPosition; + FLMUINT uiTmpPos; if ((iPosition = *piPosition) == 0) { @@ -516,19 +516,18 @@ Exit: return( rc); } -/*API~*********************************************************************** -Desc : Returns the number of records in a set defined by a cursor. -*END************************************************************************/ +/**************************************************************************** +Desc: Returns the number of records in a set defined by a cursor. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorRecCount( - HFCURSOR hCursor, - FLMUINT * puiCount - ) + HFCURSOR hCursor, + FLMUINT * puiCount) { - RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; - RCODE TmpRc; - FDB * pDb = NULL; - FLMBOOL bSavedPosition = FALSE; + RCODE rc = FERR_OK; + CURSOR * pCursor = (CURSOR *)hCursor; + RCODE TmpRc; + FDB * pDb = NULL; + FLMBOOL bSavedPosition = FALSE; if (!pCursor) { diff --git a/flaim/src/fqsrch.cpp b/flaim/src/fqsrch.cpp index f4c7c73..4f45f1a 100644 --- a/flaim/src/fqsrch.cpp +++ b/flaim/src/fqsrch.cpp @@ -29,56 +29,56 @@ #define STATUS_CB_INTERVAL 1 FSTATIC RCODE flmCurSetSubQuery( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery); + CURSOR * pCursor, + SUBQUERY * pSubQuery); FSTATIC RCODE flmCurRecValidate( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, - SUBQUERY_p pSubQuery, + CURSOR * pCursor, + SUBQUERY * pSubQuery, FLMUINT * puiSkipCount, FLMUINT * puiCount, FLMBOOL * pbReturnRecOK); FSTATIC RCODE flmCurRetrieveRec( - FDB_p pDb, - SUBQUERY_p pSubQuery, + FDB * pDb, + SUBQUERY * pSubQuery, FLMUINT uiContainer); FSTATIC RCODE flmCurSearchIndex( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount, FLMBOOL bGettingRecord); FSTATIC RCODE flmCurSearchPredicate( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount); FSTATIC RCODE flmCurSearchContainer( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount); FSTATIC RCODE flmCurEvalSingleRec( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount); @@ -87,8 +87,8 @@ Desc: This routine will do all the setup needed to establish a sub-query as the current subquery for the query. ****************************************************************************/ FSTATIC RCODE flmCurSetSubQuery( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery + CURSOR * pCursor, + SUBQUERY * pSubQuery ) { RCODE rc = FERR_OK; @@ -126,8 +126,8 @@ Desc: Validate a record that has passed the search criteria. This routine ****************************************************************************/ FSTATIC RCODE flmCurRecValidate( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, - SUBQUERY_p pSubQuery, + CURSOR * pCursor, + SUBQUERY * pSubQuery, FLMUINT * puiSkipCount, FLMUINT * puiCount, FLMBOOL * pbReturnRecOK @@ -257,8 +257,8 @@ Exit: Desc: Does the actual reading of a record from cache or disk. ****************************************************************************/ FSTATIC RCODE flmCurRetrieveRec( - FDB_p pDb, - SUBQUERY_p pSubQuery, + FDB * pDb, + SUBQUERY * pSubQuery, FLMUINT uiContainer ) { @@ -289,17 +289,17 @@ Desc: Searches an index for matching record. ****************************************************************************/ FSTATIC RCODE flmCurSearchIndex( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount, FLMBOOL bGettingRecord ) { RCODE rc = FERR_OK; - FDB_p pDb = pCursor->pDb; + FDB * pDb = pCursor->pDb; FSIndexCursor * pFSIndexCursor = pSubQuery->pFSIndexCursor; FLMUINT uiCBTimer = 0; FLMUINT uiCurrCBTime; @@ -683,16 +683,16 @@ Desc: Searches a user predicate for matching record. ****************************************************************************/ FSTATIC RCODE flmCurSearchPredicate( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount ) { RCODE rc = FERR_OK; - FDB_p pDb = pCursor->pDb; + FDB * pDb = pCursor->pDb; FlmUserPredicate * pPredicate = pSubQuery->pPredicate; FLMBOOL bSavedInvisTrans; FLMUINT uiCBTimer = 0; @@ -848,16 +848,16 @@ Desc: Searches a container for matching record. ****************************************************************************/ FSTATIC RCODE flmCurSearchContainer( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount ) { RCODE rc = FERR_OK; - FDB_p pDb = pCursor->pDb; + FDB * pDb = pCursor->pDb; FSDataCursor * pFSDataCursor = pSubQuery->pFSDataCursor; FLMUINT uiCBTimer = 0; FLMUINT uiCurrCBTime; @@ -1001,16 +1001,16 @@ Desc: Retrieves a single record and evaluates it. ****************************************************************************/ FSTATIC RCODE flmCurEvalSingleRec( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMUINT * puiCount, FLMUINT * puiSkipCount ) { RCODE rc = FERR_OK; - FDB_p pDb = pCursor->pDb; + FDB * pDb = pCursor->pDb; FLMBOOL bReturnRecOK; FLMUINT uiRecMatch; @@ -1080,7 +1080,7 @@ Desc: Performs the search operation. ****************************************************************************/ RCODE flmCurSearch( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, FLMUINT * puiCount, @@ -1093,7 +1093,7 @@ RCODE flmCurSearch( FDB * pDb; DB_STATS * pDbStats; RCODE TmpRc; - SUBQUERY_p pSubQuery = pCursor->pCurrSubQuery; + SUBQUERY * pSubQuery = pCursor->pCurrSubQuery; FLMBOOL bSavedInvisTrans; pDb = pCursor->pDb; @@ -1236,7 +1236,7 @@ RCODE flmCurSearch( // Reached BOF/EOF in the current subquery. Move on to the next one. - pSubQuery = (SUBQUERY_p)((bReadForward) + pSubQuery = (SUBQUERY *)((bReadForward) ? pSubQuery->pNext : pSubQuery->pPrev); if (!pSubQuery) diff --git a/flaim/src/fqstack.cpp b/flaim/src/fqstack.cpp index cfe6198..2df4d42 100644 --- a/flaim/src/fqstack.cpp +++ b/flaim/src/fqstack.cpp @@ -58,9 +58,9 @@ static FLMUINT PrecedenceTable [FLM_USER_PREDICATE - FLM_AND_OP + 1] = ? PrecedenceTable [(e) - FLM_AND_OP] \ : (FLMUINT)0) -/*API~*********************************************************************** +/**************************************************************************** Desc : Adds an operator to the selection criteria of a given cursor. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddOp( HFCURSOR hCursor, QTYPES eOperator, @@ -68,10 +68,10 @@ FLMEXP RCODE FLMAPI FlmCursorAddOp( ) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR *)hCursor; - FQNODE_p pTmpQNode; - FQNODE_p pTmpGraftNode; - FQNODE_p pTmpChildNode; + CURSOR * pCursor = (CURSOR *)hCursor; + FQNODE * pTmpQNode; + FQNODE * pTmpGraftNode; + FQNODE * pTmpChildNode; FLMBOOL bDecrementNestLvl = FALSE; FLMUINT uiFlags = bResolveUnknown ? FLM_RESOLVE_UNK : 0; @@ -253,7 +253,7 @@ Exit: Desc: Add a reference to an embedded user predicate. ****************************************************************************/ RCODE flmCurAddRefPredicate( - QTINFO_p pQTInfo, + QTINFO * pQTInfo, FlmUserPredicate * pPredicate ) { @@ -304,17 +304,17 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Adds an embedded user predicate. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddUserPredicate( HFCURSOR hCursor, FlmUserPredicate * pPredicate ) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR_p)hCursor; - FQNODE_p pQNode; + CURSOR * pCursor = (CURSOR *)hCursor; + FQNODE * pQNode; QTYPES eOperator; if (!pCursor || !pPredicate) @@ -394,11 +394,11 @@ Exit: Desc: Links one FQNODE as the first child of another. ****************************************************************************/ void flmCurLinkFirstChild( - FQNODE_p pParent, - FQNODE_p pChild + FQNODE * pParent, + FQNODE * pChild ) { - FQNODE_p pTmpQNode; + FQNODE * pTmpQNode; // If necessary, unlink the child from a sibling list and link it back in // as the first child. @@ -443,11 +443,11 @@ void flmCurLinkFirstChild( Desc: Links one FQNODE as the last child of another. ****************************************************************************/ void flmCurLinkLastChild( - FQNODE_p pParent, - FQNODE_p pChild + FQNODE * pParent, + FQNODE * pChild ) { - FQNODE_p pTmpQNode; + FQNODE * pTmpQNode; // If necessary, unlink the child from any parent or siblings @@ -508,7 +508,7 @@ RCODE flmPutValInAtom( ) { RCODE rc = FERR_OK; - FQATOM_p pQAtom = (FQATOM_p)pAtom; + FQATOM * pQAtom = (FQATOM *)pAtom; pQAtom->uiFlags = uiFlags; pQAtom->eType = eValType; @@ -549,7 +549,7 @@ RCODE flmCurMakeQNode( void * pVal, FLMUINT uiValLen, FLMUINT uiFlags, - FQNODE_p * ppQNode) + FQNODE * * ppQNode) { FLMUINT * puiTmpPath; FLMUINT * puiPToCPath; @@ -562,7 +562,7 @@ RCODE flmCurMakeQNode( FQNODE * pQNode; FQATOM * pQAtom; - if ((*ppQNode = pQNode = (FQNODE_p)GedPoolCalloc( pPool, + if ((*ppQNode = pQNode = (FQNODE *)GedPoolCalloc( pPool, sizeof( FQNODE))) == NULL) { rc = RC_SET( FERR_MEM); @@ -577,7 +577,7 @@ RCODE flmCurMakeQNode( pQNode->uiStatus = uiFlags; goto Exit; } - if ((pQNode->pQAtom = pQAtom = (FQATOM_p)GedPoolCalloc( pPool, + if ((pQNode->pQAtom = pQAtom = (FQATOM *)GedPoolCalloc( pPool, sizeof( FQATOM))) == NULL) { rc = RC_SET( FERR_MEM); @@ -668,11 +668,11 @@ Ret: ****************************************************************************/ RCODE flmCurGraftNode( POOL * pPool, - FQNODE_p pQNode, + FQNODE * pQNode, QTYPES eGraftOp, - FQNODE_p * ppQTree) + FQNODE * * ppQTree) { - FQNODE_p pTmpQNode; + FQNODE * pTmpQNode; RCODE rc = FERR_OK; if (*ppQTree == NULL) @@ -695,9 +695,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Adds a value to the selection criteria of a given cursor. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddValue( HFCURSOR hCursor, QTYPES eValType, @@ -709,7 +709,7 @@ FLMEXP RCODE FLMAPI FlmCursorAddValue( FLMINT iVal; FLMUINT uiVal; void * pTmpVal = pVal; - CURSOR_p pCursor = (CURSOR *)hCursor; + CURSOR * pCursor = (CURSOR *)hCursor; FLMBOOL bPoolInitialized = FALSE; POOL pool; @@ -854,18 +854,17 @@ Exit: return( rc); } -/*API~*********************************************************************** -Desc : Adds a field ID to the selection criteria of a given cursor. -*END************************************************************************/ +/**************************************************************************** +Desc: Adds a field ID to the selection criteria of a given cursor. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddField( HFCURSOR hCursor, FLMUINT uiFldId, - FLMUINT uiFlags - ) + FLMUINT uiFlags) { RCODE rc = FERR_OK; - CURSOR_p pCursor = (CURSOR_p)hCursor; - FQNODE_p pTmpQNode; + CURSOR * pCursor = (CURSOR *)hCursor; + FQNODE * pTmpQNode; FLMUINT uiPath [2]; if (!pCursor) @@ -926,20 +925,18 @@ Exit: return( rc); } - -/*API~*********************************************************************** -Desc : Adds a field path to the selection criteria of a given cursor. A - field path is the fully qualified context of a field within a record. -*END************************************************************************/ +/**************************************************************************** +Desc: Adds a field path to the selection criteria of a given cursor. A + field path is the fully qualified context of a field within a record. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddFieldPath( HFCURSOR hCursor, FLMUINT * puiFldPath, - FLMUINT uiFlags - ) + FLMUINT uiFlags) { RCODE rc = FERR_OK; - FQNODE_p pTmpQNode; - CURSOR_p pCursor = (CURSOR_p)hCursor; + FQNODE * pTmpQNode; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -990,10 +987,10 @@ Exit: return( rc); } -/*API~*********************************************************************** -Desc : Adds a field path to the selection criteria of a given cursor - with - a callback to retrieve the field. -*END************************************************************************/ +/**************************************************************************** +Desc: Adds a field path to the selection criteria of a given cursor - with + a callback to retrieve the field. +****************************************************************************/ FLMEXP RCODE FLMAPI FlmCursorAddFieldCB( HFCURSOR hCursor, FLMUINT * puiFldPath, @@ -1001,12 +998,11 @@ FLMEXP RCODE FLMAPI FlmCursorAddFieldCB( FLMBOOL bValidateOnly, CURSOR_GET_FIELD_CB fnGetField, void * pvUserData, - FLMUINT uiUserDataLen - ) + FLMUINT uiUserDataLen) { RCODE rc = FERR_OK; - FQNODE_p pTmpQNode; - CURSOR_p pCursor = (CURSOR_p)hCursor; + FQNODE * pTmpQNode; + CURSOR * pCursor = (CURSOR *)hCursor; if (!pCursor) { @@ -1038,7 +1034,7 @@ FLMEXP RCODE FLMAPI FlmCursorAddFieldCB( puiFldPath, 0, pCursor->QTInfo.uiFlags, &pTmpQNode))) { - FQATOM_p pQAtom = pTmpQNode->pQAtom; + FQATOM * pQAtom = pTmpQNode->pQAtom; pQAtom->val.QueryFld.fnGetField = fnGetField; pQAtom->val.QueryFld.bValidateOnly = bValidateOnly; diff --git a/flaim/src/fqtextc.cpp b/flaim/src/fqtextc.cpp deleted file mode 100644 index ca5f6b7..0000000 --- a/flaim/src/fqtextc.cpp +++ /dev/null @@ -1,1423 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Query text comparison -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fqtextc.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -// From COLTBL.cpp - -extern FLMBYTE fwp_dia60Tbl[]; /* Diacritic conversions */ -extern FLMBYTE fwp_alefSubColTbl[]; -extern FLMBYTE fwp_ar2BitTbl[]; - -#define COMPARE_COLLATION 1 -#define COMPARE_COL_AND_SUBCOL 2 -#define COMPARE_VALUE 3 - -#define NULL_SUB_COL_CHECK NULL -#define NULL_CASE_CHECK NULL -#define NULL_WILD_CARD_CHECK NULL - -FSTATIC FLMINT flmTextCompareSingleChar( - FLMBYTE ** ppLeftText, - FLMUINT * puiLeftLen, - FLMUINT * puiLeftWpChar2, - FLMBYTE ** ppRightText, - FLMUINT * puiRightLen, - FLMUINT * puiRightWpChar2, - FLMINT * piSubColCompare, - FLMINT * piCaseCompare, - FLMBOOL * pbHitWildCard, - FLMINT iCompareType, - FLMUINT16 * pui16ColVal, - FLMUINT uiFlags, - FLMUINT uiLangId); - - -FSTATIC FLMUINT16 flmTextGetSubCol( - FLMUINT16 ui16WPValue, - FLMUINT16 ui16ColValue, - FLMUINT uiLangId); - -/**************************************************************************** -Desc: -****************************************************************************/ -FINLINE FLMUINT flmCharTypeAnsi7( - FLMUINT16 ui16Char) -{ - if( (ui16Char >= ASCII_LOWER_A && ui16Char <= ASCII_LOWER_Z) || - (ui16Char >= ASCII_UPPER_A && ui16Char <= ASCII_UPPER_Z) || - (ui16Char >= ASCII_ZERO && ui16Char <= ASCII_NINE)) - { - return SDWD_CHR; - } - if( ui16Char == 0x27) - return WDJN_CHR; - - if( ui16Char <= 0x2B) - return DELI_CHR; - - if( ui16Char == ASCII_COMMA || - ui16Char == ASCII_DASH || - ui16Char == ASCII_DOT || - ui16Char == ASCII_SLASH || - ui16Char == ASCII_COLON || - ui16Char == ASCII_AT || - ui16Char == ASCII_BACKSLASH || - ui16Char == ASCII_UNDERSCORE) - return WDJN_CHR; - return DELI_CHR; -} - - -/*API~*********************************************************************** -Desc : Compare two unicode strings. This comparison uses the collation - rules that are defined for the specified language. -Return: Signed value of compare. - <0 if less than, 0 if equal, >0 if greater than - The case of returning 1 may be in using wild cards which - only need to return a does not match value. -*END************************************************************************/ -FLMEXP FLMINT FLMAPI FlmStrCmp( - FLMUINT uiCompFlags, - FLMUINT byLang, - const FLMUNICODE * uzStr1, - const FLMUNICODE * uzStr2) -{ - FLMINT iCmp; - POOL Pool; - NODE * pNd1; - NODE * pNd2; - RCODE rc; - - GedPoolInit( &Pool, 256); - - if( (pNd1 = GedNodeMake( &Pool, 1, &rc)) == NULL || - (pNd2 = GedNodeMake( &Pool, 1, &rc)) == NULL) - { - flmAssert( 0); - iCmp = 1; - goto Exit; - } - - if( RC_BAD( rc = GedPutUNICODE( &Pool, pNd1, uzStr1))) - { - flmAssert( RC_OK( rc)); - iCmp = 1; - goto Exit; - } - - if( RC_BAD( rc = GedPutUNICODE( &Pool, pNd2, uzStr2))) - { - flmAssert( RC_OK( rc)); - iCmp = -1; - goto Exit; - } - - // Handle null string cases. - - if( GedValLen( pNd1) == 0) - { - iCmp = 1; - goto Exit; - } - else if( GedValLen( pNd2) == 0) - { - iCmp = -1; - goto Exit; - } - - // VISIT: need to add support for the IGNORE_DASH and IGNORE_SPACE options. - - iCmp = flmTextCompare( (FLMBYTE *)GedValPtr( pNd1), GedValLen( pNd1), - (FLMBYTE *)GedValPtr( pNd2), GedValLen( pNd2), uiCompFlags, byLang); - -Exit: - GedPoolFree( &Pool); - return iCmp; -} - -/**************************************************************************** -Desc: Compare two entire strings. There is some debate how this routine - should compare the sub-collation values when wild cards are used. - THIS DOES NOT ALLOW WILD CARDS. -Return: Signed value of compare. - <0 if less than, 0 if equal, >0 if greater than - The case of returning 1 may be in using wild cards which - only need to return a does not match value. -****************************************************************************/ -FLMINT flmTextCompare( - FLMBYTE * pLeftBuf, - FLMUINT uiLeftLen, - FLMBYTE * pRightBuf, - FLMUINT uiRightLen, - FLMUINT uiFlags, - FLMUINT uiLang) -{ - FLMINT iCompare = 0; - FLMINT iSubColCompare = 0; // MUST BE INITIALIZED - FLMINT * pSubColCompare; - FLMINT iCaseCompare = 0; // MUST BE INITIALIZED - FLMINT * pCaseCompare; - FLMUINT uiLeadingSpace; - FLMUINT uiTrailingSpace; - FLMUINT16 ui16ColVal = 0; // Needed for asian collation - FLMUINT16 ui16WPChar; - FLMUINT16 ui16UniChar; - FLMUINT uiLeftWpChar2 = 0; - FLMUINT uiRightWpChar2 = 0; - - uiTrailingSpace = uiLeadingSpace = - (uiFlags & FLM_MIN_SPACES) ? FLM_NO_SPACE : 0; - pCaseCompare = (uiFlags & FLM_NOCASE) ? NULL : &iCaseCompare; - pSubColCompare = &iSubColCompare; - - // Handle NULL buffers first. - - if (!pLeftBuf) - { - if (pRightBuf) - { - iCompare = -1; - } - goto Exit; - } - - while ((uiLeftLen || uiLeftWpChar2) && - (uiRightLen || uiRightWpChar2)) - { - if ((iCompare = flmTextCompareSingleChar( - &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, - &pRightBuf, &uiRightLen, &uiRightWpChar2, - pSubColCompare, pCaseCompare, NULL_WILD_CARD_CHECK, - COMPARE_COLLATION, &ui16ColVal, - uiFlags | uiLeadingSpace, uiLang)) != 0) - { - goto Exit; - } - uiLeadingSpace = 0; - } - - // EQUAL - as far as the collation values are concerned and one - // or both of the strings is at the end. - - if (uiLeftLen || uiLeftWpChar2) - { - uiLeftLen -= flmTextGetValue( pLeftBuf, uiLeftLen, &uiLeftWpChar2, - uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); - - if (uiLeftLen || ui16WPChar || ui16UniChar) - { - iCompare = 1; - } - } - else if (uiRightLen || uiRightWpChar2) - { - uiRightLen -= flmTextGetValue( pRightBuf, uiRightLen, &uiRightWpChar2, - uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); - if (uiRightLen || ui16WPChar || ui16UniChar) - { - iCompare = -1; - } - } - if (iCompare == 0) - { - - // All collation bytes equal - return subcollation/case difference. - - iCompare = (iSubColCompare != 0) ? iSubColCompare : iCaseCompare; - } - -Exit: - - return iCompare; -} - -/**************************************************************************** -Desc: Match two entire strings. -Return: FLM_TRUE or FLM_FALSE -Notes: This code calls the collation routine because in the future there - will be equal conditions with different unicode characters. - -DOCUMENTATION DEALING WITH WILD CARDS AND SPACE RULES. - - The space rules are not obvious when dealing with wild cards. - This will outline the rules that are being applied so that we can - do a regression test when this code changes. - - Rule #1: Return same result if leading or trailing wild card is added. - The underscore is also the space character in these examples - and the MIN_SPACES rule is being applied. - - Format: DataString Operator SearchString - - Example: if A == A A_ == A A == A_ A_ == A_ - then A == A* A_ == A* A == A_* A_ == A_* - and A == *A A_ == *A A == *A_ A_ == *A_ - and A == *A* A_ == *A* A == *A_* A_ == *A_* - where 'A' represent a string of any characters. - - Strictly put, the query Field == A_* can be broken down to - Field == A || Field == A_* - where the space after 'A' should not be treated as a trailing space. - - In addition we can apply the space before the string with the same results, - but we are not going to handle the case of *_A correctly. - This is because the query *_A should be expanded to - Field == A || Field == *_A - where the space before 'A' should not be treated as a leading space. - When we need to find "_A" in a search string then we will expand the - query to handle this. - - - Rule #2: The spaces before a trailing truncation are NOT to be treated - as trailing spaces if there are remaining bytes in the data string. - - Example: (A_B == A_*) but (AB != A_*) - - - Rule #3: Space value(s) without anything other value are equal to no values. - Example: (" " == "") - - - Rule #4: Trim leading/trailing spaces before and after wild cards. - SMI does this when formatting. - - _* and *_ same as * so A == _* and A = *_ but A != *_* - - - Additional wildcard cases to test for: - - Wildcard cases to handle. - (ABBBBC == A*BC) Hits the goto Compare_Again case three times. - (ABBBBD != A*B) Stuff still remains in dataString - (ABBBBC != A*BCD) Stuff still remains in searchString - -****************************************************************************/ -FLMUINT flmTextMatch( - FLMBYTE * pLeftBuf, - FLMUINT uiLeftLen, - FLMBYTE * pRightBuf, - FLMUINT uiRightLen, - FLMUINT uiFlags, - FLMBOOL bLeadingWildCard, - FLMBOOL bTrailingWildCard, - FLMUINT uiLang) -{ - FLMINT iCompare = 0; - FLMUINT uiLeadingSpace; - FLMUINT uiTrailingSpace; - FLMBOOL bHitWildCard; - FLMBOOL bHasWildCardPos; - FLMBOOL * pbHitWildCard; - FLMUINT uiValueLen; - FLMUINT16 ui16WPChar; - FLMUINT16 ui16UniChar; - FLMUINT16 ui16Tmp1; - FLMUINT16 ui16Tmp2; - FLMINT iCompareType; - FLMUINT uiLeftWpChar2 = 0; - FLMUINT uiRightWpChar2 = 0; - // LWCP = Last Wild Card Position - used for wild card state - FLMBYTE * pLWCPLeftBuf = NULL; - FLMBYTE * pLWCPRightBuf = NULL; - FLMUINT uiLWCPLeftLen = 0; - FLMUINT uiLWCPRightLen = 0; - FLMUINT uiLWCPLeftWpChar2 = 0; - FLMUINT uiLWCPRightWpChar2 = 0; - - if( uiFlags & FLM_COMPARE_COLLATED_VALUES) - { - iCompareType = COMPARE_COLLATION; - } - else - { - iCompareType = (uiFlags & FLM_NOCASE) - ? COMPARE_COL_AND_SUBCOL : COMPARE_VALUE; - } - - // Handle NULL buffers first - don't test for zero length values yet. - - if (!pLeftBuf) - { - if (pRightBuf) - { - iCompare = -1; - } - goto Exit; - } - - bHitWildCard = bHasWildCardPos = FALSE; - uiLeadingSpace = uiTrailingSpace = - (uiFlags & FLM_MIN_SPACES) ? FLM_NO_SPACE : 0; - pbHitWildCard = (uiFlags & FLM_WILD) ? &bHitWildCard : NULL; - - if (bLeadingWildCard) - { - goto Leading_Wild_Card; - } - - while (!iCompare && - (uiLeftLen || uiLeftWpChar2) && - (uiRightLen || uiRightWpChar2)) - { - iCompare = flmTextCompareSingleChar( - &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, - &pRightBuf, &uiRightLen, &uiRightWpChar2, - NULL_SUB_COL_CHECK, NULL_CASE_CHECK, pbHitWildCard, - iCompareType, NULL, - uiFlags | uiLeadingSpace, uiLang); - - uiLeadingSpace = 0; - if (bHitWildCard) - { -Leading_Wild_Card: - bHitWildCard = FALSE; - bHasWildCardPos = FALSE; // Turn off last wildcard. - - // If right side is done, we are done. - - if (!uiRightLen && !uiRightWpChar2) - { - uiLeftLen = 0; - uiLeftWpChar2 = 0; - break; - } - - // Save state on the RIGHT to handle the sick case of search key - // "b*aH" being able to match "baaaaaaaaaH" (Lambda Case) - // LWCP = LastWildCardPosition - - pLWCPRightBuf = pRightBuf; - uiLWCPRightLen = uiRightLen; - uiLWCPRightWpChar2 = uiRightWpChar2; - - // Find first matching character on the left side. - -Compare_Again: - - iCompare = -1; - while (iCompare && (uiLeftLen || uiLeftWpChar2)) - { - iCompare = flmTextCompareSingleChar( - &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, - &pRightBuf, &uiRightLen, &uiRightWpChar2, - NULL_SUB_COL_CHECK, NULL_CASE_CHECK, NULL_WILD_CARD_CHECK, - iCompareType, NULL, - uiFlags | uiLeadingSpace, uiLang); - - uiLeadingSpace = 0; - - // Done with the right side? Return iCompare value. - - if (!uiRightLen && !uiRightWpChar2) - { - break; - } - - // Values different and still have stuff on left? - - if (iCompare && (uiLeftLen || uiLeftWpChar2)) - { - // Advance the left if there is anything left - uiValueLen = flmTextGetValue( pLeftBuf, uiLeftLen, - &uiLeftWpChar2, - uiFlags, &ui16Tmp1, &ui16Tmp2); - pLeftBuf += uiValueLen; - uiLeftLen -= uiValueLen; - } - } - - // Save state on the LEFT - - if (uiLeftLen || uiLeftWpChar2) - { - pLWCPLeftBuf = pLeftBuf; - uiLWCPLeftLen = uiLeftLen; - uiLWCPLeftWpChar2 = uiLeftWpChar2; - bHasWildCardPos = TRUE; - } - - // EQUAL - as far as the collation values are concerned. - } - } - - if (iCompare == 0) - { - // In here because LEFT and/or RIGHT are out of bytes. - // Check for trailing spaces if MIN_SPACES. - - if (uiLeftLen || uiLeftWpChar2) - { - if (!bTrailingWildCard) - { - uiLeftLen -= flmTextGetValue( pLeftBuf, uiLeftLen, - &uiLeftWpChar2, - uiFlags | uiTrailingSpace, &ui16WPChar, - &ui16UniChar); - - if (uiLeftLen || ui16WPChar || ui16UniChar) - { - iCompare = 1; - } - } - } - else if (uiRightLen || uiRightWpChar2) - { - uiRightLen -= flmTextGetValue( pRightBuf, uiRightLen, &uiRightWpChar2, - uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); - - // Equals if right just had a trailing wild card. (else case) - - if (uiRightLen || !pbHitWildCard || ui16WPChar != '*') - { - if (uiRightLen || ui16WPChar || ui16UniChar) - { - iCompare = -1; - } - } - } - } - - // Handle the embedded wild card case. - - if (iCompare != 0 && bHasWildCardPos) - { - - // Restore wild card state. - - pLeftBuf = pLWCPLeftBuf; - uiLeftLen = uiLWCPLeftLen; - uiLeftWpChar2 = uiLWCPLeftWpChar2; - pRightBuf = pLWCPRightBuf; - uiRightLen = uiLWCPRightLen; - uiRightWpChar2 = uiLWCPRightWpChar2; - bHasWildCardPos = FALSE; - - goto Compare_Again; - } - -Exit: - - return (!iCompare ? FLM_TRUE : FLM_FALSE); -} - -/**************************************************************************** -Desc: Compare only the leading left and right characters according - to the many flags that are passed in. This routine operates - to save and set state for the calling routine. -TODO: - This routine does NOT support Asian, Hebrew, or Arabic language - collations. In addition, fwpCheckDoubleCollation() is not called for other non-US - lanagues. There is still a lot of work to do! This is our - default US compare and it is not very good for JP. - -Return: Signed value of compare. - <0 if less than, 0 if equal, >0 if greater than. -Asian Notes: - The asian compare takes two characters and may use one or both. - This makes the algorithm complex so we may have to build full - tests to see what we broke. -NDS Notes: - The right side (search string) is already formatted according - to the space/dash rules of the syntax. -****************************************************************************/ -FSTATIC FLMINT flmTextCompareSingleChar( - FLMBYTE ** ppLeftText, // [in] Points to current value. - // [out] Points to next character if equals. - FLMUINT * puiLeftLen, // [in] Bytes remaining in text string. - // [out] Bytes remaining in text string. - FLMUINT * puiLeftWpChar2,// Second left character - for double characters - FLMBYTE ** ppRightText, // [in] Points to current value. - // [out] Points to next character if equals. - FLMUINT * puiRightLen, // [in] Bytes remaining in text string. - // [out] Bytes remaining in text string. - FLMUINT * puiRightWpChar2,// Second right character - for double characters. - FLMINT * piSubColCompare,//[in] If NULL disregard the subcollation - // values if collation values are equal. - // [out] If equals is returned, value is - // set ONLY if the signed value of comparing - // the sub-collation values is not equal. - // See lengthy unicode compare below. - FLMINT * piCaseCompare, // [in] If NULL disregard the case bits - // if collation values are equal. Japanese - // values are an exception to this rule. - // [out] If equals is returned, value is - // set ONLY if the signed value of comparing - // the case values is not equal. - FLMBOOL * pbHitWildCard, // [in] If NULL then do not look for wild - // cards in the right text string. - // [out] If non-null, a wild card (*,?) will - // be looked for on the RIGHT SIDE ONLY. - // If '?' is found 0 will be returned and - // pointers are advanced. If '*' is found, - // this value will be set to TRUE and the - // right side is advanced. If no wild - // card is found the value will not be set. - FLMINT iCompareType, // COMPARE_COLLATION, COMPARE_COL_AND_SUBCOL, COMPARE_VALUE - FLMUINT16 * pui16ColVal, // Needed for asian collation compare. - FLMUINT uiFlags, // FLM_* flags - FLMUINT uiLangId) // FLAIM/WordPerfect Lanaguge id. -{ - FLMBYTE * pLeftText = *ppLeftText; - FLMBYTE * pRightText = *ppRightText; - FLMINT iCompare = 0; - FLMUINT uiRightFlags = uiFlags; - FLMUINT16 ui16LeftWPChar; - FLMUINT16 ui16LeftUniChar; - FLMUINT16 ui16RightWPChar; - FLMUINT16 ui16RightUniChar; - FLMUINT uiLeftValueLen; - FLMUINT uiRightValueLen; - FLMUINT16 ui16LeftCol; - FLMUINT16 ui16RightCol; - FLMUINT uiLeftWpChar2 = *puiLeftWpChar2; - FLMUINT uiRightWpChar2 = *puiRightWpChar2; - FLMBOOL bLeftTwoIntoOne; - FLMBOOL bRightTwoIntoOne; - - // Get the next character from the TEXT string. NOTE: OEM characters - // will be returned as a UNICODE character. A unicode character here - // is a value that cannot be converted to the WP set (no good collation value).. - - uiLeftValueLen = flmTextGetValue( pLeftText, *puiLeftLen, &uiLeftWpChar2, - uiFlags, &ui16LeftWPChar, &ui16LeftUniChar); - uiRightValueLen = flmTextGetValue( pRightText, *puiRightLen, &uiRightWpChar2, - uiRightFlags, &ui16RightWPChar, &ui16RightUniChar); - - // At this point, the double character, if any, should have been consumed. - - flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); - - // Check for the following escape characters: "\\" "*" and "\\" "\\" - - if( ui16RightWPChar == ASCII_BACKSLASH) - { - if( pRightText[ uiRightValueLen ] == ASCII_BACKSLASH) - { - uiRightValueLen++; - } - else if( pRightText[ uiRightValueLen ] == ASCII_WILDCARD) - { - ui16RightWPChar = ASCII_WILDCARD; - uiRightValueLen++; - } - } - // Checking for wild cards in the right string? (Always a WP character) - else if( pbHitWildCard) - { - - // The '*' wildcard means to match zero or many characters. - // The sick case of "A*B" compared to "A**B" should be considered. - - if( ui16RightWPChar == ASCII_WILDCARD) - { - // Eat all duplicate wild cards. - while( pRightText[ uiRightValueLen] == ASCII_WILDCARD) - { - uiRightValueLen++; - } - - // Advance the right value. Keep left value alone. - // Return equals (default). - - *pbHitWildCard = TRUE; - - // Don't advance the left value. - - uiLeftValueLen = 0; - uiLeftWpChar2 = *puiLeftWpChar2; - goto Exit; - } - } - - // First section is to compare just WP values. - - if( ui16LeftWPChar && ui16RightWPChar) - { - FLMUINT16 ui16LeftSubCol; - FLMUINT16 ui16RightSubCol; - - if (iCompareType == COMPARE_VALUE) - { - - // Check the obvious case of equal WP values. - - if( ui16LeftWPChar != ui16RightWPChar) - { - iCompare = -1; - } - goto Exit; - } - - // JP compare code. - - if (uiLangId >= FIRST_DBCS_LANG && uiLangId <= LAST_DBCS_LANG) - { - FLMUINT uiNextLeftLen; - FLMUINT uiNextRightLen; - FLMUINT16 ui16NextLeftWPChar; - FLMUINT16 ui16NextRightWPChar; - FLMUINT16 ui16ColVal = pui16ColVal ? *pui16ColVal : 0; - FLMBYTE ucLeftCaseValue; - FLMBYTE ucRightCaseValue; - - // Should have already consumed double character, if any - - flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); - uiNextLeftLen = flmTextGetValue( pLeftText+uiLeftValueLen, - *puiLeftLen, &uiLeftWpChar2, uiFlags, - &ui16NextLeftWPChar, &ui16LeftUniChar); - uiNextRightLen = flmTextGetValue( pRightText+uiRightValueLen, - *puiRightLen, &uiRightWpChar2, uiFlags, - &ui16NextRightWPChar, &ui16RightUniChar); - - // nextL/R WPChar may be zero. - - if (fwpAsiaGetCollation( ui16LeftWPChar, ui16NextLeftWPChar, ui16ColVal, - &ui16LeftCol, &ui16LeftSubCol, &ucLeftCaseValue, FALSE) == 2) - { - uiLeftValueLen += uiNextLeftLen; - } - if (fwpAsiaGetCollation( ui16RightWPChar, ui16NextRightWPChar, ui16ColVal, - &ui16RightCol, &ui16RightSubCol, &ucRightCaseValue, FALSE) == 2) - { - uiRightValueLen += uiNextRightLen; - } - - // Compare all of the stuff now. - - if (ui16LeftCol == ui16RightCol) - { - if( (iCompareType == COMPARE_COL_AND_SUBCOL) || - (piSubColCompare && (*piSubColCompare == 0))) - { - if( ui16LeftSubCol != ui16RightSubCol) - { - if( iCompareType == COMPARE_COL_AND_SUBCOL) - { - iCompare = -1; - goto Exit; - } - - // At this point piSubColCompare cannot be NULL. - - *piSubColCompare = (ui16LeftSubCol < ui16RightSubCol) ? -1 : 1; - - // Write over the case compare value - - if( piCaseCompare ) - { - *piCaseCompare = *piSubColCompare; - } - } - } - if (iCompareType != COMPARE_COL_AND_SUBCOL) - { - - // Check case? - - if (piCaseCompare && (*piCaseCompare == 0)) - { - if( ucLeftCaseValue != ucRightCaseValue) - { - *piCaseCompare = ucLeftCaseValue < ucRightCaseValue?-1:1; - } - } - } - } - else - { - iCompare = (ui16LeftCol < ui16RightCol) ? -1 : 1; - } - goto Exit; - } - - flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); - - if (uiLangId != US_LANG) - { - const FLMBYTE * pucTmp; - - pucTmp = pLeftText + uiLeftValueLen; - uiLeftWpChar2 = fwpCheckDoubleCollation( &ui16LeftWPChar, &bLeftTwoIntoOne, - &pucTmp, uiLangId); - uiLeftValueLen = (FLMUINT)(pucTmp - pLeftText); - - pucTmp = pRightText + uiRightValueLen; - uiRightWpChar2 = fwpCheckDoubleCollation( &ui16RightWPChar, &bRightTwoIntoOne, - &pucTmp, uiLangId); - uiRightValueLen = (FLMUINT)(pucTmp - pRightText); - - // See if we got the same double character - - if (uiLeftWpChar2 == uiRightWpChar2 && - ui16LeftWPChar == ui16RightWPChar) - { - uiLeftWpChar2 = 0; - uiRightWpChar2 = 0; - goto Exit; - } - } - else if (ui16LeftWPChar == ui16RightWPChar) - { - - // Same WP character - - goto Exit; - } - - ui16LeftCol = fwpGetCollation( ui16LeftWPChar, uiLangId); - - // Handle two characters collating as one. - - if (uiLeftWpChar2 && bLeftTwoIntoOne) - { - ui16LeftCol++; - } - - ui16RightCol = fwpGetCollation( ui16RightWPChar, uiLangId); - - // Handle two characters collating as one. - - if (uiRightWpChar2 && bRightTwoIntoOne) - { - ui16RightCol++; - } - - if( ui16LeftCol == ui16RightCol) - { - // Should we bother to check subcollation? - don't bother with 7-bit - - if( ( (iCompareType == COMPARE_COL_AND_SUBCOL) - || (piSubColCompare && (*piSubColCompare == 0))) - && ((ui16LeftWPChar | ui16RightWPChar) & 0xFF00)) // Non-ascii - { - ui16LeftSubCol = flmTextGetSubCol( ui16LeftWPChar, - ui16LeftCol, uiLangId); - ui16RightSubCol= flmTextGetSubCol( ui16RightWPChar, - ui16RightCol, uiLangId); - - if (!piCaseCompare) - { - - // If the sub-collation value is the original - // character, it means that the collation could not - // distinguish the characters and sub-collation is being - // used to do it. However, this creates a problem when the - // characters are the same character except for case. In that - // scenario, we incorrectly return a not-equal when we are - // doing a case-insensitive comparison. So, at this point, - // we need to use the sub-collation for the upper-case of the - // character instead of the sub-collation for the character - // itself. - - if (ui16LeftSubCol == ui16LeftWPChar) - { - ui16LeftSubCol = flmTextGetSubCol( - fwpCh6Upper( ui16LeftWPChar), - ui16LeftCol, uiLangId); - } - if (ui16RightSubCol == ui16RightWPChar) - { - ui16RightSubCol= flmTextGetSubCol( - fwpCh6Upper( ui16RightWPChar), - ui16RightCol, uiLangId); - } - } - - // YES - go for it... - - if( ui16LeftSubCol != ui16RightSubCol) - { - if( iCompareType == COMPARE_COL_AND_SUBCOL) - { - iCompare = (ui16LeftSubCol < ui16RightSubCol) ? -1 : 1; - goto Exit; - } - // At this point piSubColCompare cannot be NULL. - *piSubColCompare = (ui16LeftSubCol < ui16RightSubCol) ? -1 : 1; - /* Write over the case compare value */ - if( piCaseCompare ) - { - *piCaseCompare = *piSubColCompare; - } - } - // ? goto Exit??? - } - - if( iCompareType == COMPARE_COL_AND_SUBCOL) - { - goto Exit; - } - // Check case? - - if( piCaseCompare && (*piCaseCompare == 0)) - { - - // fwpIsUpper() only returns FALSE (lower) or TRUE (not-lower) - - FLMBOOL bLeftUpper = fwpIsUpper( ui16LeftWPChar); - FLMBOOL bRightUpper = fwpIsUpper( ui16RightWPChar); - - if (bLeftUpper != bRightUpper) - { - *piCaseCompare = !bLeftUpper ? -1 : 1; - } - // ? else - don't know why they would be the same. - } - } - else - { - iCompare = (ui16LeftCol < ui16RightCol) ? -1 : 1; - } - goto Exit; - - } // end of working with BOTH WP characters - - /*else*/ - if( ui16LeftUniChar && ui16RightUniChar) - { - // Compare two (non-convertable) UNICODE values. - - // Check the obvious case of equal UNICODE values. - if( ui16LeftUniChar == ui16RightUniChar) - { - goto Exit; - } - - // Compare subcollation or compare value? - if( iCompareType != COMPARE_COLLATION) - { - iCompare = -1; - goto Exit; - } - - /* - For non-asian - we store these values in the sub-collcation area. - We should return the differece in sub-collation values - but this - may not work for all compares. - For asian compares, most values we have a collation value. - This is a BIG differece in comparing asian values. - - If we want sub-collation compare then set it, otherwise set main - iCompare value. - */ - - if( piSubColCompare ) - { - if( *piSubColCompare == 0) - { - *piSubColCompare = ui16LeftUniChar < ui16RightUniChar ? -1 : 1; - } - } - else - { - // Treat as the collation value - this is different than the index. - - iCompare = ui16LeftUniChar < ui16RightUniChar ? -1 : 1; - } - goto Exit; - } - /*else*/ - - // Compare subcollation or compare value? - if( iCompareType != COMPARE_COLLATION) - { - iCompare = -1; - goto Exit; - } - - // Check for no left character. - if( !ui16LeftWPChar && !ui16LeftUniChar) - { - // No left character. check if no right character. - - if( ui16RightWPChar || ui16RightUniChar) - { - iCompare = -1; - } - /* else returns equals. */ - } - - // Check for no right character. - else if( !ui16RightWPChar && !ui16RightUniChar) - { - iCompare = 1; - } - - /* - What remains is one WP char and one Unicode char. - Remember the sub-collation comment above. Some WP char may not - have a collation value (COLS0) so in US sort these values may be - equal and have different sub-collation values. YECH!!!! - - The unicode value will always have collation value of COLS0 (0xFF) - and subcollation value of 11110 [unicodeValue] - The WP value could be anything & if collation value is COLS0 will - have a subcollation value os 1110 [WPValue] - - So, we have to check to see of the WP collation value is COLS0. - If not iCompare is used. If both represent high collation then - the WP value will always have a lower sub-collation value. - - The (not so obvious) code would be to code up... - iCompare = ui16LeftWPChar ? -1 : 1; - if we didn't care about sub-collation (and we may not care). - - This is easier to over code than have ?: operators for the two cases. - */ - - else if( ui16LeftWPChar) - { - // Remember - unicode subcol is always COLS0. - - if( fwpGetCollation( ui16LeftWPChar, uiLangId) == COLS0) - { - if( piSubColCompare && (*piSubColCompare == 0)) - { - *piSubColCompare = -1; - } - } - else - { - iCompare = -1; - } - } - else - { - // left=unicode, right=WP - // Remember - unicode subcol is always COLS0 for non-asian. - - if( fwpGetCollation( ui16RightWPChar, uiLangId) == COLS0) - { - if( piSubColCompare && (*piSubColCompare == 0)) - { - *piSubColCompare = 1; - } - } - else - { - iCompare = 1; - } - } -Exit: - - if( !iCompare ) - { - // Position to the next values if equal - - *puiLeftLen -= uiLeftValueLen; - *ppLeftText = pLeftText + uiLeftValueLen; - *puiLeftWpChar2 = uiLeftWpChar2; - *puiRightLen -= uiRightValueLen; - *ppRightText = pRightText + uiRightValueLen; - *puiRightWpChar2 = uiRightWpChar2; - } - return iCompare; -} - -/**************************************************************************** -Desc: Return the next WP or unicode character value and parsing type. -****************************************************************************/ -FLMUINT flmTextGetCharType( - const FLMBYTE * pText, - FLMUINT uiLen, - FLMUINT16 * pui16WPValue, - FLMUNICODE * puzUniValue, - FLMUINT * pType) -{ - FLMUINT uiReturnLen; - FLMUINT16 wpValue; - FLMUNICODE uniValue; - FLMUINT uiCharSet; - - uiReturnLen = flmTextGetValue( pText, uiLen, NULL, - FLM_MIN_SPACES, pui16WPValue, puzUniValue); - wpValue = *pui16WPValue; - uniValue = *puzUniValue; - - if( wpValue) - { - if( wpValue < 0x080) - { - *pType = flmCharTypeAnsi7( wpValue); - goto Exit; - } - uiCharSet = (FLMUINT) (wpValue >> 8); - - if( uiCharSet == 1 || - uiCharSet == 2 || - (uiCharSet >= 8 && uiCharSet <= 11)) - { - *pType = SDWD_CHR; - goto Exit; - } - *pType = DELI_CHR; - } - else - { - // For now all unicode is a delimeter - *pType = DELI_CHR; - } -Exit: - return uiReturnLen; -} - -/**************************************************************************** -Desc: Return the next WP or unicode character value. -Return: Number of bytes formatted to return the character value. -Note: This code must be fast so some compromises have been made - in respect to maintenance. - DON"T CHEAT. This routine returns the number of spaces - skipped over if FLM_MIN_SPACE or FLM_NO_SPACE is turned on. - White space checking does NOT applity to WP spaces. Only - to the 0x20 space. -****************************************************************************/ -FLMUINT flmTextGetValue( - const FLMBYTE * pText, // [in] Points to current value. - FLMUINT uiLen, // [in] Bytes remaining in text. - FLMUINT * puiWpChar2, // Was there a double character? - FLMUINT uiFlags, // [in] - FLMUINT16 * pui16WPValue, // [out] WP Character value or 0 if unicode. - FLMUNICODE * puzUniValue) // [out] Unicode or OEM value if - // *pui16WPChar is zero. -{ - FLMUINT uiReturnLength = 0; - FLMUINT uiObjectLength; - FLMUINT16 ui16CurValue; // Current working (WPish) value. - FLMUNICODE uzUniValue; - - uiReturnLength = 0; - ui16CurValue = 0; - uzUniValue = 0; - - if (puiWpChar2 && *puiWpChar2) - { - ui16CurValue = (FLMUINT16)(*puiWpChar2); - *puiWpChar2 = 0; - uiObjectLength = 0; - goto Check_White_Space; - } - - while (uiLen && !ui16CurValue && !uzUniValue) - { - ui16CurValue = (FLMUINT16) *pText; - - switch( GedTextObjType( ui16CurValue )) - { - case ASCII_CHAR_CODE: /* 0nnnnnnn */ - uiObjectLength = 1; - -Check_White_Space: - - // Do all of the bIgnore* stuff here. - // WHITE SPACE CODE doesn't apply. - - if( ui16CurValue == (FLMUINT16) ASCII_UNDERSCORE && (uiFlags & FLM_NO_UNDERSCORE)) - { - ui16CurValue = (FLMUINT16) ASCII_SPACE; - } - if( ui16CurValue == (FLMUINT16) ASCII_SPACE) - { - if( uiFlags & FLM_NO_SPACE) - { - ui16CurValue = 0; - } - else if( uiFlags & FLM_MIN_SPACES) - { - // Eat up the remaining spaces and underscores (if NO_UNDERSCORES). - while( (pText[ uiObjectLength] == ASCII_SPACE - || ( pText[ uiObjectLength] == ASCII_UNDERSCORE - && (uiFlags & FLM_NO_UNDERSCORE))) - && uiObjectLength < uiLen) - { - uiObjectLength++; - } - } - } - else if( ui16CurValue == ASCII_DASH && (uiFlags & FLM_NO_DASH)) - { - ui16CurValue = 0; - } - break; - - case CHAR_SET_CODE: /* 10nnnnnn - Character Set | Char */ - uiObjectLength = 2; - ui16CurValue = (FLMUINT16) - (((FLMUINT16)(ui16CurValue & (~CHAR_SET_MASK)) << 8) - + (FLMUINT16)*(pText + 1)); /* Character */ - break; - - case WHITE_SPACE_CODE: /* 110nnnnn */ - { - FLMBYTE ucTmpByte; - - uiObjectLength = 1; - ucTmpByte = *pText & (~WHITE_SPACE_MASK); - - ui16CurValue = ((ucTmpByte == HARD_HYPHEN) || - (ucTmpByte == HARD_HYPHEN_EOL) || - (ucTmpByte == HARD_HYPHEN_EOP)) - ? (FLMUINT16) 0x2D /* Minus sign */ - : (FLMUINT16) 0x20; /* Space */ - break; - } - - case EXT_CHAR_CODE: /* Full extended character */ - uiObjectLength = 3; - ui16CurValue = (FLMUINT16)(((FLMUINT16)*(pText + 1) << 8) /* Char set */ - + (FLMUINT16) *(pText + 2)); /* Character */ - break; - - case UNICODE_CODE: /* Unconvertable UNICODE code */ - - uiObjectLength = 3; - ui16CurValue = 0; - uzUniValue = (FLMUINT16)(((FLMUINT16)*(pText + 1) << 8) /* Char set */ - + (FLMUINT16)*(pText + 2)); /* Character */ - break; - - case OEM_CODE: - uiObjectLength = 2; /* OEM characters are always >= 128.*/ - /* Make this a unicode character */ - ui16CurValue = 0; - uzUniValue = (FLMUINT16) *(pText + 1); - break; - - - /* Skip all of the unknown stuff */ - case UNK_GT_255_CODE: - uiObjectLength = (FLMUINT16)(1 + sizeof( FLMUINT16) + FB2UW( pText + 1)); - break; - case UNK_LE_255_CODE: - uiObjectLength = 2 + (FLMUINT16)*(pText + 1); - break; - case UNK_EQ_1_CODE: - uiObjectLength = 2; - break; - default: /* should NEVER happen: bug if does */ - /* Coded to skip remaining data. */ - ui16CurValue = 0; - uiObjectLength = uiLen; - break; /* just give up. */ - } /* End of switch */ - - uiReturnLength += uiObjectLength; - pText += uiObjectLength; - uiLen -= uiObjectLength; - } - -//Exit: - *pui16WPValue = ui16CurValue; - *puzUniValue = uzUniValue; - return uiReturnLength; -} - - -/**************************************************************************** -Desc: Return the sub-collation value of a WPText character. - Unconvered Unicode values always have a sub-collation - value of 11110 + Unicode Value. -****************************************************************************/ - -FSTATIC FLMUINT16 flmTextGetSubCol( - FLMUINT16 ui16WPValue, // [in] WP Character value. - FLMUINT16 ui16ColValue, // [in] Collation Value (for arabic) - FLMUINT uiLangId) // [in] WP Language ID. -{ - FLMUINT16 ui16SubColVal; - FLMBYTE byCharVal; - FLMBYTE byCharSet; - FLMUINT16 ui16Base; - - // Easy case first. - - ui16SubColVal = 0; - if( (ui16WPValue & 0xFF00 ) == 0) - { - goto Exit; - } - - // From here down default ui16SubColVal is WP value. - - ui16SubColVal = ui16WPValue; - - byCharVal = (FLMBYTE) ui16WPValue; - byCharSet = (FLMBYTE) (ui16WPValue >> 8); - - /**-------------------------------------------------- - *** Convert char to uppercase because case information - *** is stored above. This will help - *** insure that the "ETA" doesn't sort before "eta" - *** could use is lower code here for added performance. - ***-------------------------------------------------*/ - - /* This just happens to work with all WP character values. */ - if (!fwpIsUpper( ui16WPValue)) - { - ui16WPValue &= ~1; - } - - switch( byCharSet) - { - case CHSMUL1: - /**-------------------------------------------------- - *** If you cannot break down a char into base and - *** diacritic then you cannot combine the charaacter - *** later when converting back the key. So, write - *** the entire WP char in the sub-collation area. - *** We can ONLY SUPPORT MULTINATIONAL 1 for brkcar() - ***-------------------------------------------------*/ - - if( fwpCh6Brkcar( ui16WPValue, &ui16Base, &ui16SubColVal)) - { - - // WordPerfect character cannot be broken down. - // If we had a collation value other than 0xFF (COLS0), don't - // return a sub-collation value. This will allow things like - // upper and lower AE digraphs to compare properly. - - if (ui16ColValue != COLS0) - { - ui16SubColVal = 0; - } - goto Exit; - } - - /**------------------------------------------------- - *** Write the FLAIM diacritic sub-collation value. - *** Prefix is 2 bits "10". Remember to leave - *** "111" alone for the future. - *** Bug 11/16/92 = was only writing a "1" and not "10" - ***------------------------------------------------*/ - ui16SubColVal = ( - (ui16SubColVal & 0xFF) == umlaut /* Def in charset.h */ - && ( (uiLangId == SU_LANG) || - (uiLangId == SV_LANG) || - (uiLangId == CZ_LANG) || - (uiLangId == SL_LANG) - ) - ) - ? (FLMUINT16)(fwp_dia60Tbl[ ring] + 1) /* umlaut must be after ring above*/ - : (FLMUINT16)(fwp_dia60Tbl[ ui16SubColVal & 0xFF]); - - break; - - case CHSGREK: - /**------------ - *** Greek - ***-----------*/ - if( (byCharVal >= 52) || /* Keep case bit for 52-69 else ignore*/ - (ui16WPValue == 0x804) || /*[ 8,4] BETA Medial | Terminal*/ - (ui16WPValue == 0x826)) /*[ 8,38] SIGMA termainal */ - { - ui16SubColVal = ui16WPValue; - } - /* else no subcollation to worry about */ - break; - - case CHSCYR: - if( byCharVal >= 144) - { - ui16SubColVal = ui16WPValue; - } - /* else no subcollation to worry about */ - - /* VISIT: Georgian covers 208-249 - no collation defined yet */ - break; - - case CHSHEB: /* Hebrew */ - /**----------------------------------------------------------- - *** Three sections in Hebrew: - *** 0..26 - main characters - *** 27..83 - accents that apear over previous character - *** 84..118- dagesh (ancient) hebrew with accents - *** - *** Because the ancient is only used for sayings & scriptures - *** we will support a collation value and in the sub-collation - *** store the actual character because sub-collation is in - *** character order. - ***----------------------------------------------------------*/ - - if( byCharVal >= 84) /* Save ancient - value 84 and above */ - { - ui16SubColVal = ui16WPValue; - } - break; - - case CHSARB1: /* Arabic 1 */ - /**------------------------------------------------------- - *** Three sections in Arabic: - *** 00..37 - accents that display OVER a previous character - *** 38..46 - symbols - *** 47..57 - numbers - *** 58..163 - characters - *** 164 - hamzah accent - *** 165..180- common characters with accents - *** 181..193- ligatures - common character combinations - *** 194..195- extensions - throw away when sorting - ***------------------------------------------------------*/ - - if( byCharVal <= 46 ) - { - ui16SubColVal = ui16WPValue; - } - else - { - if( ui16ColValue == COLS10a+1) /* Alef? */ - { - ui16SubColVal = (byCharVal >= 165) - ? (FLMUINT16)(fwp_alefSubColTbl[ byCharVal - 165 ]) - : (FLMUINT16)7; /* Alef subcol value */ - } - else - { - if( byCharVal >= 181) /* Ligatures - char combination*/ - { - ui16SubColVal = ui16WPValue; - } - else if( byCharVal == 64) /* taa exception */ - { - ui16SubColVal = 8; - } - } - } - break; - - case CHSARB2: /* Arabic 2 */ - /* There are some characters that share the same slot */ - /* Check the bit table if above character 64 */ - - if ((byCharVal >= 64) && - (fwp_ar2BitTbl[(byCharVal-64)>> 3] & (0x80 >> (byCharVal&0x07)))) - { - ui16SubColVal = ui16WPValue; - } - break; - - } /* end switch */ - -Exit: - return ui16SubColVal; -} diff --git a/flaim/src/fquery.h b/flaim/src/fquery.h index 4dd7410..92383e3 100644 --- a/flaim/src/fquery.h +++ b/flaim/src/fquery.h @@ -126,23 +126,10 @@ Desc: Macros used for determining the nature and precedence of OP codes. (((left) < (right)) ? -1 : 1 )) -typedef struct QueryAtom * FQATOM_p; -typedef struct QueryNode * FQNODE_p; -typedef struct QPredicateInfo * QPREDICATE_p; -typedef struct QFieldPredicateTag * QFIELD_PREDICATE_p; -typedef struct QIndexTag * QINDEX_p; -typedef struct QueryTreeInfo * QTINFO_p; -typedef struct Set_Delimeter * SET_DEL_p; -typedef struct FQKey * FQKEY_p; -typedef struct SubQuery * SUBQUERY_p; -typedef struct FQCursor * CURSOR_p; -typedef struct PositionKey * POS_KEY_p; - /**************************************************************************** -Structures used for the query tree and other stuff +Desc: ****************************************************************************/ - -typedef struct FlmQueryField +typedef struct F_QUERY_FLD { FLMUINT * puiFldPath; // In child-to-parent order. FLMUINT * puiPToCPath; // In parent-to-child order. @@ -150,17 +137,21 @@ typedef struct FlmQueryField FLMBOOL bValidateOnly; void * pvUserData; FLMUINT uiUserDataLen; -} F_QUERY_FLD, * F_QUERY_FLD_p; +} F_QUERY_FLD; -typedef struct QueryAtom +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct FQATOM { - FQATOM_p pNext; // Atoms are chained in some areas. + FQATOM * pNext; // Atoms are chained in some areas. FlmRecord * pFieldRec; QTYPES eType; // From enum qTypes in FLAIM.H. // Describes this atom. Value from 0 // to FLM_Q_MAX_TYPES. FLMUINT uiFlags; FLMUINT uiBufLen; // Length if the type is text or binary + union { FLMUINT uiBool; @@ -175,20 +166,25 @@ typedef struct QueryAtom } val; // Holds or points to the atom value. } FQATOM; - -typedef struct QueryNode +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct FQNODE { - QTYPES eOpType; // Type of QueryNode - see enum qTypes + QTYPES eOpType; // Type of QueryNode - see enum qTypes FLMUINT uiNestLvl; // Nesting level of query node. - FLMUINT uiStatus; // Status of node - defs in FLAIM.h - FQNODE_p pParent; // Parent of this query node - FQNODE_p pPrevSib; // Previous sibling of this query node - FQNODE_p pNextSib; // Next sibling of this query node - FQNODE_p pChild; // Child of this query node - FQATOM_p pQAtom; // Atomic value(s) of this query node + FLMUINT uiStatus; // Status of node - defs in FLAIM.h + FQNODE * pParent; // Parent of this query node + FQNODE * pPrevSib; // Previous sibling of this query node + FQNODE * pNextSib; // Next sibling of this query node + FQNODE * pChild; // Child of this query node + FQATOM * pQAtom; // Atomic value(s) of this query node } FQNODE; -typedef struct QPredicateInfo +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct QPREDICATE { FQNODE * pPredNode; // Root node of this predicate - unless // it is an exists operator or not exists, @@ -209,19 +205,25 @@ typedef struct QPredicateInfo FLMBOOL bReturnsTrueOnNullRec; // Does this predicate return NULL when // evaluated on an empty record? - QPREDICATE_p pNext; // Next predicate in the list. + QPREDICATE * pNext; // Next predicate in the list. } QPREDICATE; -typedef struct QFieldPredicateTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct QFIELD_PREDICATE { - QPREDICATE_p pPredicate; // Pointer to predicate - IFD_p pIfd; // IFD for this predicate's field. + QPREDICATE * pPredicate; // Pointer to predicate + IFD * pIfd; // IFD for this predicate's field. FLMUINT uiRank; // Ranking of this predicate with respect // to this IFD. - QFIELD_PREDICATE_p pNext; // Next predicate involving same field + QFIELD_PREDICATE * pNext; // Next predicate involving same field } QFIELD_PREDICATE; -typedef struct QIndexTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct QINDEX { FLMUINT uiIndexNum; FLMUINT uiNumFields; @@ -231,20 +233,23 @@ typedef struct QIndexTag // It doesn't matter which. FLMBOOL bMultiplePredsOnIfd; // Some IFD has multiple // predicates. - IXD_p pIxd; + IXD * pIxd; QFIELD_PREDICATE ** ppFieldPredicateList; // One for each IFD FLMUINT uiNumPredicatesCovered; FLMUINT uiRank; - QINDEX_p pNext; - QINDEX_p pPrev; + QINDEX * pNext; + QINDEX * pPrev; } QINDEX; -typedef struct QueryTreeInfo +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct QTINFO { - FQNODE_p pTopNode; - FQNODE_p pCurOpNode; - FQNODE_p pCurAtomNode; - FQNODE_p pSaveQuery; + FQNODE * pTopNode; + FQNODE * pCurOpNode; + FQNODE * pCurAtomNode; + FQNODE * pSaveQuery; FLMUINT uiNestLvl; // Number of unclosed left parens FLMUINT uiExpecting; // Next thing that should be pushed #define FLM_Q_PAREN 1 @@ -261,8 +266,10 @@ typedef struct QueryTreeInfo FLMUINT uiNumPredicates; } QTINFO; - -typedef struct Set_Delimeter +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct SET_DEL { FLMBYTE * pKeyBuf; FLMUINT uiKeyBufLen; @@ -271,29 +278,35 @@ typedef struct Set_Delimeter FLMUINT uiAttr; } SET_DEL; -typedef struct FQKey +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct FQKEY { SET_DEL FromKey; SET_DEL UntilKey; - FQKEY_p pNext; - FQKEY_p pPrev; + FQKEY * pNext; + FQKEY * pPrev; } FQKEY; -typedef struct PositionKey +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct POS_KEY { FLMBYTE * pucKey; FLMUINT uiKeyLen; FLMUINT uiDrn; // May be domain if not leaf level key. } POS_KEY; - -// Major structures: CURSOR, SUBQUERY - -typedef struct SubQuery +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct SUBQUERY { - SUBQUERY_p pNext; - SUBQUERY_p pPrev; - FQNODE_p pTree; + SUBQUERY * pNext; + SUBQUERY * pPrev; + FQNODE * pTree; OPT_INFO OptInfo; FSIndexCursor * pFSIndexCursor; // Used of OptInfo.eOptType is // QOPT_USING_INDEX @@ -321,25 +334,28 @@ typedef struct SubQuery FLMUINT uiCurrKeyMatch; } SUBQUERY; -typedef struct FQCursor +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct CURSOR { - FDB_p pDb; + FDB * pDb; FLMUINT uiContainer; FLMUINT uiRecType; FLMUINT uiIndexNum; // Query tree and subqueries. - FQNODE_p pTree; - SUBQUERY_p pSubQueryList; - SUBQUERY_p pCurrSubQuery; - SUBQUERY_p pSaveSubQuery; + FQNODE * pTree; + SUBQUERY * pSubQueryList; + SUBQUERY * pCurrSubQuery; + SUBQUERY * pSaveSubQuery; FLMBOOL bInvTrans; FLMUINT uiTransSeq; // Positioning keys. - POS_KEY_p pPosKeyArray; + POS_KEY * pPosKeyArray; FLMUINT uiNumPosKeys; FLMBOOL bLeafLevel; FLMUINT uiLastPrcntPos; @@ -366,38 +382,38 @@ typedef struct FQCursor RCODE ReadRc; // Will only be SUCCESS, FRC_EOF_HIT, // or FRC_BOF_HIT FLMUINT uiTimeLimit; - CS_CONTEXT_p pCSContext; + CS_CONTEXT * pCSContext; FLMUINT uiCursorId; } CURSOR; typedef RCODE FQ_OPERATION( - FQATOM_p lhs, // Left hand side - FQATOM_p rhs, // Right hand side - FQATOM_p pResult); // Newly allocated result side + FQATOM * lhs, // Left hand side + FQATOM * rhs, // Right hand side + FQATOM * pResult); // Newly allocated result side RCODE flmCurDbInit( - CURSOR_p pCursor); + CURSOR * pCursor); void flmSQFree( - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FLMBOOL bFreeEverything); void flmCurFinishTrans( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurSavePosition( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurRestorePosition( - CURSOR_p pCursor); + CURSOR * pCursor); void flmCurFree( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFinishTrans); RCODE flmCurSearch( eFlmFuncs eFlmFuncId, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFirstRead, FLMBOOL bReadForward, FLMUINT * puiCount, @@ -406,26 +422,26 @@ RCODE flmCurSearch( FLMUINT * puiDrn); RCODE flmInitCurCS( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurGetAtomVal( FlmRecord * pRecord, void * pField, POOL * pPool, QTYPES eFldType, - FQATOM_p pResult); + FQATOM * pResult); RCODE flmCurEvalCriteria( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery, + CURSOR * pCursor, + SUBQUERY * pSubQuery, FlmRecord * pRecord, FLMBOOL bHaveKey, FLMUINT * puiResult); void flmCompareOperands( FLMUINT uiLang, - FQATOM_p pLhs, - FQATOM_p pRhs, + FQATOM * pLhs, + FQATOM * pRhs, QTYPES eOp, FLMBOOL bResolveUnknown, FLMBOOL bForEvery, @@ -435,35 +451,35 @@ void flmCompareOperands( RCODE flmCurEvalCompareOp( FDB * pDb, - SUBQUERY_p pSubQuery, + SUBQUERY * pSubQuery, FlmRecord * pRecord, - FQNODE_p pQNode, + FQNODE * pQNode, QTYPES eOp, FLMBOOL bHaveKey, - FQATOM_p pResult); + FQATOM * pResult); RCODE flmCurDoNeg( - FQATOM_p pResult); + FQATOM * pResult); FLMUINT flmCurDoMatchOp( - FQATOM_p lhs, - FQATOM_p rhs, + FQATOM * lhs, + FQATOM * rhs, FLMUINT uiLang, FLMBOOL bLeadingWildCard, FLMBOOL bTrailingWildCard); FLMINT flmCurDoRelationalOp( - FQATOM_p lhs, - FQATOM_p rhs, + FQATOM * lhs, + FQATOM * rhs, FLMUINT uiLang); FLMUINT flmCurDoContainsOp( - FQATOM_p lhs, - FQATOM_p rhs, + FQATOM * lhs, + FQATOM * rhs, FLMUINT uiLang); RCODE flmCurDoNeg( - FQATOM_p pResult); + FQATOM * pResult); FLMINT flmTextCompare( FLMBYTE * pLeftBuf, @@ -485,60 +501,60 @@ FLMUINT flmTextMatch( RCODE flmCurMakeKeyFromRec( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, POOL * pPool, FlmRecord * pRec, FLMBYTE ** ppucKeyBuffer, FLMUINT * puiKeyLen); RCODE flmCurSetPosFromDRN( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiDRN); RCODE flmCurCopyQNode( - FQNODE_p pSrcNode, - QTINFO_p pDestQTInfo, - FQNODE_p * ppDestNode, + FQNODE * pSrcNode, + QTINFO * pDestQTInfo, + FQNODE * * ppDestNode, POOL * pPool); RCODE flmCurPrep( - CURSOR_p pCursor); + CURSOR * pCursor); void flmCurFreePosKeys( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurSetupPosKeyArray( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurGetPercentPos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT * puiPrcntPos); RCODE flmCurSetPercentPos( - CURSOR_p pCursor, + CURSOR * pCursor, FLMUINT uiPrcntPos); RCODE flmSQSetupFullContainerScan( - SUBQUERY_p pSubQuery); + SUBQUERY * pSubQuery); RCODE flmCurOptimize( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bStratified); RCODE flmCurPartitionTree( - CURSOR_p pCursor); + CURSOR * pCursor); RCODE flmCurAddRefPredicate( - QTINFO_p pQTInfo, + QTINFO * pQTInfo, FlmUserPredicate * pPredicate); void flmCurLinkFirstChild( - FQNODE_p pParent, - FQNODE_p pChild); + FQNODE * pParent, + FQNODE * pChild); void flmCurLinkLastChild( - FQNODE_p pParent, - FQNODE_p pChild); + FQNODE * pParent, + FQNODE * pChild); RCODE flmPutValInAtom( void * pAtom, @@ -553,21 +569,21 @@ RCODE flmCurMakeQNode( void * pVal, FLMUINT uiStrLen, FLMUINT uiFlags, - FQNODE_p * ppQNode); + FQNODE * * ppQNode); RCODE flmCurGraftNode( POOL * pPool, - FQNODE_p pQNode, + FQNODE * pQNode, QTYPES eGraftOp, - FQNODE_p * ppQTree); + FQNODE * * ppQTree); void flmLogQuery( F_LogMessage * pLogMsg, FLMUINT uiIndent, - CURSOR_p pCursor); + CURSOR * pCursor); FINLINE void flmCurFinishTransactions( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bSetToNull) { flmCurFinishTrans( pCursor); @@ -578,7 +594,7 @@ FINLINE void flmCurFinishTransactions( } void flmCurFreeSQList( - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bFreeEverything); FLMUINT flmGetPathLen( diff --git a/flaim/src/frec.cpp b/flaim/src/frec.cpp index 612b04e..30b56d6 100644 --- a/flaim/src/frec.cpp +++ b/flaim/src/frec.cpp @@ -727,7 +727,7 @@ RCODE FlmRecord::setNative( goto Exit; } - if( RC_BAD( rc = FlmNative2Storage( pszString, &uiBufLen, pucData))) + if( RC_BAD( rc = FlmNative2Storage( pszString, 0, &uiBufLen, pucData))) { goto Exit; } @@ -1528,7 +1528,7 @@ RCODE FlmRecord::compressMemory( void) // Add 1 to the length to allow for the flags byte which is only // present on long fields and encrypted fields. - uiTmp = uiNewDataSize + sizeof( FLMUINT16) + 1; + uiTmp = uiNewDataSize + sizeof( FLMUINT32) + 1; if( getFieldDataType( pFld) == FLM_BINARY_TYPE) { @@ -1608,7 +1608,7 @@ RCODE FlmRecord::compressMemory( void) } else if( uiLength >= 0xFF) { - uiTmp = uiNewDataOffset + sizeof( FLMUINT16) + 1; + uiTmp = uiNewDataOffset + sizeof( FLMUINT32) + 1; if( getFieldDataType( pFld) == FLM_BINARY_TYPE) { @@ -1619,8 +1619,8 @@ RCODE FlmRecord::compressMemory( void) } flmAssert( uiTmp + uiLength <= uiNewDataSize); - pucNewData[ uiNewDataOffset] = 0; // Set the flags byte. - UW2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); + pucNewData[ uiNewDataOffset + FLD_ENC_FLAGS] = 0; // Set the flags byte. + UD2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); f_memcpy( &pucNewData[ uiTmp], getDataPtr( pFld), uiLength); pFld->ui32DataOffset = (FLMUINT32)uiNewDataOffset; uiNewDataOffset = uiTmp + uiLength; @@ -1656,8 +1656,8 @@ RCODE FlmRecord::compressMemory( void) flmAssert( uiEncTmp + uiEncLength + (uiPicketFenceSize / 2) <= uiNewDataSize); pucNewData[ uiNewDataOffset + FLD_ENC_FLAGS] = ( FLMBYTE)uiFlags; UW2FBA( (FLMUINT32)uiEncId, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); - UW2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_DATA_LEN]); - UW2FBA( (FLMUINT32)uiEncLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCRYPTED_DATA_LEN]); + UD2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_DATA_LEN]); + UD2FBA( (FLMUINT32)uiEncLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCRYPTED_DATA_LEN]); #ifdef FLM_PICKET_FENCE // Set the picket fence f_sprintf( (char *)&pucNewData[ uiTmp], FLD_RAW_FENCE); @@ -1829,7 +1829,7 @@ RCODE FlmRecord::compactMemory( void) { // Add one extra byte for the flags byte. - uiTmp = uiNewDataSize + sizeof( FLMUINT16) + 1; + uiTmp = uiNewDataSize + sizeof( FLMUINT32) + 1; if( getFieldDataType( pFld) == FLM_BINARY_TYPE) { @@ -1951,7 +1951,7 @@ RCODE FlmRecord::compactMemory( void) } else if( uiLength >= 0xFF) { - uiTmp = uiNewDataOffset + sizeof( FLMUINT16) + 1; + uiTmp = uiNewDataOffset + sizeof( FLMUINT32) + 1; if( getFieldDataType( pFld) == FLM_BINARY_TYPE) { @@ -1962,8 +1962,8 @@ RCODE FlmRecord::compactMemory( void) } flmAssert( uiTmp + uiLength <= uiNewDataSize); - pucNewData[ uiNewDataOffset] = 0; // Flags - UW2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); + pucNewData[ uiNewDataOffset + FLD_ENC_FLAGS] = 0; // Flags + UD2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); f_memcpy( &pucNewData[ uiTmp], getDataPtr( pFld), uiLength); pNewFld->ui32DataOffset = (FLMUINT32)uiNewDataOffset; uiNewDataOffset = uiTmp + uiLength; @@ -1997,10 +1997,10 @@ RCODE FlmRecord::compactMemory( void) uiEncTmp = uiTmp + uiLength + (uiPicketFenceSize / 2); flmAssert( uiEncTmp + uiEncLength + (uiPicketFenceSize / 2) <= uiNewDataSize); - pucNewData[ uiNewDataOffset + FLD_ENC_FLAGS] = ( FLMBYTE)uiFlags; + pucNewData[ uiNewDataOffset + FLD_ENC_FLAGS] = (FLMBYTE)uiFlags; UW2FBA( (FLMUINT16)uiEncId, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCID]); - UW2FBA( (FLMUINT16)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_DATA_LEN]); - UW2FBA( (FLMUINT16)uiEncLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCRYPTED_DATA_LEN]); + UD2FBA( (FLMUINT32)uiLength, &pucNewData[ uiNewDataOffset + FLD_ENC_DATA_LEN]); + UD2FBA( (FLMUINT32)uiEncLength, &pucNewData[ uiNewDataOffset + FLD_ENC_ENCRYPTED_DATA_LEN]); #ifdef FLM_PICKET_FENCE f_sprintf( (char *)&pucNewData[ uiTmp], FLD_RAW_FENCE); @@ -2322,25 +2322,14 @@ RCODE FlmRecord::getNewDataPtr( goto Exit; } - // Make sure the requested size doesn't exceed the maximum - // field value size - - if( uiNewLength > FLM_MAX_FIELD_VAL_SIZE || - uiEncNewLength > FLM_MAX_FIELD_VAL_SIZE) - { - rc = RC_SET( FERR_VALUE_TOO_LARGE); - goto Exit; - } - bOldEncrypted = isEncryptedField( pField); // If the new field is encrypted, we need to prefix the value - // with the encryption overhead. - // Otherwise, if the new length is >= 0xFF, we need to prefix the value - // with a 2-byte length + // with the encryption overhead. Otherwise, if the new length + // is >= 0xFF, we need to prefix the value with a 4-byte length uiHeader = (bNewEncrypted ? FLM_ENC_FLD_OVERHEAD - : (uiNewLength >= 0xFF ? sizeof( FLMUINT16) + 1 + : (uiNewLength >= 0xFF ? sizeof( FLMUINT32) + 1 : 0)); // Determine the true original data length @@ -2352,7 +2341,8 @@ RCODE FlmRecord::getNewDataPtr( flmAssert( pField->ui8DataLen == 0xFF); // Account for the header - uiOldHeader = (bOldEncrypted ? FLM_ENC_FLD_OVERHEAD : sizeof( FLMUINT16) + 1); + + uiOldHeader = (bOldEncrypted ? FLM_ENC_FLD_OVERHEAD : sizeof( FLMUINT32) + 1); uiOldLength += uiOldHeader; // Special work if this is a binary field @@ -2527,7 +2517,7 @@ RCODE FlmRecord::getNewDataPtr( pucTmp = getDataBufPtr() + uiAllocStart; *pucTmp = 0; // Flags pucTmp++; - UW2FBA( (FLMUINT16)uiNewLength, pucTmp); + UD2FBA( (FLMUINT32)uiNewLength, pucTmp); pField->ui8DataLen = 0xFF; pField->ui32DataOffset = (FLMUINT32)uiAllocStart; } @@ -2581,7 +2571,7 @@ RCODE FlmRecord::getNewDataPtr( pucTmp = getDataBufPtr() + pField->ui32DataOffset; *pucTmp = 0; // Flags pucTmp++; - UW2FBA( (FLMUINT16)uiNewLength, pucTmp); + UD2FBA( (FLMUINT32)uiNewLength, pucTmp); pField->ui8DataLen = 0xFF; } else @@ -2679,7 +2669,7 @@ RCODE FlmRecord::getNewDataPtr( pucTmp = getDataBufPtr() + uiAllocStart; *pucTmp = 0; // Flags pucTmp++; - UW2FBA( (FLMUINT16)uiNewLength, pucTmp); + UD2FBA( (FLMUINT32)uiNewLength, pucTmp); pField->ui8DataLen = 0xFF; pField->ui32DataOffset = (FLMUINT32)uiAllocStart; } @@ -4019,7 +4009,7 @@ FLMBYTE * FlmRecord::getDataPtr( } else { - FLMUINT uiOffset = pField->ui32DataOffset + sizeof( FLMUINT16) + 1; + FLMUINT uiOffset = pField->ui32DataOffset + sizeof( FLMUINT32) + 1; if( getFieldDataType( pField) == FLM_BINARY_TYPE) { @@ -4226,11 +4216,11 @@ FLMUINT FlmRecord::getFieldDataLength( pucLength += 2; } - uiDataLen = FB2UW( pucLength); + uiDataLen = FB2UD( pucLength); Exit: - return uiDataLen; + return( uiDataLen); } /***************************************************************************** @@ -4289,8 +4279,7 @@ Exit: Desc: Function to get the length of the encrypted data. *****************************************************************************/ FLMUINT FlmRecord::getEncryptedDataLength( - FlmField * pField - ) + FlmField * pField) { FLMBYTE * pucBuffer = NULL; FLMUINT uiEncDataLength = 0; @@ -4303,7 +4292,7 @@ FLMUINT FlmRecord::getEncryptedDataLength( } pucBuffer = getDataBufPtr() + pField->ui32DataOffset; - uiEncDataLength = FB2UW( &pucBuffer[ FLD_ENC_ENCRYPTED_DATA_LEN]); + uiEncDataLength = FB2UD( &pucBuffer[ FLD_ENC_ENCRYPTED_DATA_LEN]); Exit: @@ -4343,8 +4332,7 @@ Exit: Desc: *****************************************************************************/ FLMUINT FlmRecord::getEncFlags( - FlmField * pField - ) + FlmField * pField) { FLMBYTE * pucBuffer; @@ -4357,7 +4345,6 @@ FLMUINT FlmRecord::getEncFlags( pucBuffer = getDataBufPtr() + pField->ui32DataOffset; return( (FLMUINT)pucBuffer[ FLD_ENC_FLAGS]); - } /***************************************************************************** @@ -4365,8 +4352,7 @@ Desc: *****************************************************************************/ void FlmRecord::setEncFlags( FlmField * pField, - FLMUINT uiFlags - ) + FLMUINT uiFlags) { FLMBYTE * pucBuffer; @@ -4806,8 +4792,8 @@ RCODE FlmRecord::checkField( { RCODE rc = FERR_OK; FLMBYTE * pucFldBuffer; - FLMUINT16 ui16DataLen; - FLMUINT16 ui16EncDataLen; + FLMUINT32 ui32DataLen; + FLMUINT32 ui32EncDataLen; FLMUINT uiAlignment = 0; FLMBYTE * pucDataFence = NULL; FLMBYTE * pucEncFence = NULL; @@ -4859,16 +4845,16 @@ RCODE FlmRecord::checkField( goto Exit; } - ui16DataLen = FB2UW( &pucFldBuffer[ FLD_ENC_DATA_LEN]); - if (!ui16DataLen) + ui32DataLen = FB2UD( &pucFldBuffer[ FLD_ENC_DATA_LEN]); + if (!ui32DataLen) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); goto Exit; } - ui16EncDataLen = FB2UW( &pucFldBuffer[ FLD_ENC_ENCRYPTED_DATA_LEN]); - if (!ui16EncDataLen) + ui32EncDataLen = FB2UD( &pucFldBuffer[ FLD_ENC_ENCRYPTED_DATA_LEN]); + if (!ui32EncDataLen) { flmAssert( 0); rc = RC_SET( FERR_FAILURE); @@ -4893,7 +4879,7 @@ RCODE FlmRecord::checkField( // Verify the picket fences. pucDataFence = pucFldBuffer + FLM_ENC_FLD_OVERHEAD + uiAlignment; - pucEncFence = pucDataFence + ui16DataLen + 4; + pucEncFence = pucDataFence + ui32DataLen + 4; if ( f_memcmp( pucDataFence, FLD_RAW_FENCE, FLD_PICKET_FENCE_SIZE / 2)) { @@ -4920,7 +4906,7 @@ RCODE FlmRecord::checkField( // Let's try to get this as unicode. // Allocate a temporary buffer. - uiBufLen = (ui16DataLen * 2) + 2; + uiBufLen = (ui32DataLen * 2) + 2; if (RC_BAD( rc = f_alloc( uiBufLen, &pUnicode))) { goto Exit; @@ -5525,3 +5511,696 @@ Exit: return( rc); } +/**************************************************************************** +Desc: +****************************************************************************/ +class RecCursor : public F_Base +{ +public: + + RecCursor( + FlmRecord * pRecord, + GRD_CallBackFunction pCallBackFunction, + void * pvCallBackData) + { + m_pRecord = pRecord; + m_pvField = pRecord ? pRecord->root() : NULL; + m_uiRootLevel = pRecord ? pRecord->getLevel( m_pvField) : 0; + m_uiAbsoluteCursorPosition = 1; + m_pCallBack = pCallBackFunction; + m_pvCallBackData = pvCallBackData; + m_bStillAtTheRoot = TRUE; + } + + RecCursor( + RecCursor * pCursor) + { + m_pRecord = pCursor->m_pRecord; + m_pvField = pCursor->m_pvField; + m_uiRootLevel = pCursor->m_uiRootLevel; + m_uiAbsoluteCursorPosition = pCursor->m_uiAbsoluteCursorPosition; + m_pCallBack = pCursor->m_pCallBack; + m_pvCallBackData = pCursor->m_pvCallBackData; + m_bStillAtTheRoot = pCursor->m_bStillAtTheRoot; + } + + virtual ~RecCursor( void) + { + if (m_pRecord) + { + m_pRecord = NULL; + } + } + + FINLINE FLMBOOL EndOfRecord( void) + { + return( m_pvField == NULL + ? TRUE + : (m_pRecord->getLevel( m_pvField) <= m_uiRootLevel && + !m_bStillAtTheRoot) + ? TRUE + : FALSE); + } + + FINLINE void Advance( void) + { + m_bStillAtTheRoot = FALSE; + if (m_pvField) + { + m_pvField = m_pRecord->next( m_pvField); + m_uiAbsoluteCursorPosition++; + } + } + + FLMBOOL FieldValueIsEqualTo( + RecCursor * pSomeField); + + FINLINE FLMBOOL FieldIdIsEqualTo( + RecCursor * pSomeField) + { + return( Level() == pSomeField->Level() && + m_pRecord->getFieldID( m_pvField) == + pSomeField->m_pRecord->getFieldID( pSomeField->m_pvField) && + m_pRecord->getDataType( m_pvField) == + pSomeField->m_pRecord->getDataType( pSomeField->m_pvField) + ? TRUE + : FALSE); + } + + enum RecFieldMatchTypes + { + GRD_NoMatch, + GRD_ExactMatch, + GRD_IDMatch + }; + + void * Scan( + RecCursor * pTargetCursor, + RecFieldMatchTypes * peMatchType); + + FINLINE FLMUINT AbsolutePosition( void) + { + return (m_uiAbsoluteCursorPosition); + } + + FINLINE void * Field( void) + { + return ( m_pvField); + } + + FINLINE FlmRecord * Record( void) + { + return (m_pRecord); + } + + FINLINE FLMUINT Level( void) + { + return (m_pvField ? Normalize( m_pRecord->getLevel( m_pvField)) : 0); + } + + FINLINE FLMUINT RawLevel( void) + { + return( m_pvField ? m_pRecord->getLevel( m_pvField) : 0); + } + + FINLINE void CallBack( + GRD_DifferenceData & difference) + { + (*m_pCallBack) (difference, m_pvCallBackData); + } + + static void MarkBranchDeleted( + RecCursor * pBeforeCursor, + RecCursor * pAfterCursor); + + static void MarkModified( + RecCursor * pBeforeCursor, + RecCursor * pAfterCursor); + + static void MarkInserted( + RecCursor * pCursor); + + static void MarkRangeInserted( + RecCursor * pAfterCursor, + void * pEndOfRange); + +private: + + FLMUINT m_uiAbsoluteCursorPosition; + FlmRecord * m_pRecord; + void * m_pvField; + FLMUINT m_uiRootLevel; + GRD_CallBackFunction m_pCallBack; + void * m_pvCallBackData; + FLMBOOL m_bStillAtTheRoot; + + RecCursor( void) + { + } + + FINLINE FLMUINT Normalize( + FLMUINT uiLevel) + { + return( uiLevel - m_uiRootLevel); + } + + FINLINE FLMBOOL isLeafField(void) + { + void * pvNext = m_pRecord->next( m_pvField); + + // It is valid to compare raw node levels of nodes within the same + // record + + return( (pvNext && + m_pRecord->getLevel( pvNext) > m_pRecord->getLevel( m_pvField)) + ? FALSE + : TRUE); + } +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBOOL RecCursor::FieldValueIsEqualTo( + RecCursor* pSomeField) +{ + FLMBOOL bEqual = FALSE; + FLMUINT uiFieldLen = m_pRecord->getDataLength( m_pvField); + FLMUINT uiSomeLen = pSomeField->m_pRecord->getDataLength( pSomeField->m_pvField); + FLMUINT uiEncFieldLen = 0; + FLMUINT uiEncSomeLen = 0; + const FLMBYTE* pValue1; + const FLMBYTE* pValue2; + + // If the data lengths are not equal, we can exit. + + if (uiFieldLen != uiSomeLen) + { + goto Exit; + } + + // If one field is encrypted and the other is not, then we can exit. + + if ((m_pRecord->isEncryptedField( m_pvField) && + !pSomeField->m_pRecord->isEncryptedField( pSomeField->m_pvField)) || + (!m_pRecord->isEncryptedField( m_pvField) && + pSomeField->m_pRecord->isEncryptedField( pSomeField->m_pvField))) + { + goto Exit; + } + + // If the fields are encrypted, are they using the same encryption + // scheme? + + if (m_pRecord->isEncryptedField( m_pvField)) + { + if (m_pRecord->getEncryptionID( m_pvField) != + pSomeField->m_pRecord->getEncryptionID( pSomeField->m_pvField)) + { + goto Exit; + } + } + + // If the field is not encrypted, and we have a value length + + if (uiFieldLen && !m_pRecord->isEncryptedField( m_pvField)) + { + pValue1 = m_pRecord->getDataPtr( m_pvField); + pValue2 = pSomeField->m_pRecord->getDataPtr( pSomeField->m_pvField); + + // If the values are not equal, we can exit. + + if (f_memcmp( pValue1, pValue2, uiFieldLen) != 0) + { + goto Exit; + } + } + + // Otherwise, if the field is encrypted, we need to check the + // encrypted value. + + else if (m_pRecord->isEncryptedField( m_pvField)) + { + uiEncFieldLen = m_pRecord->getEncryptedDataLength( m_pvField); + uiEncSomeLen = pSomeField->m_pRecord->getEncryptedDataLength( pSomeField->m_pvField); + + // If the encrypted lengths are not equal, we can exit. + + if (uiEncFieldLen != uiEncSomeLen) + { + goto Exit; + } + + if (uiEncFieldLen) + { + pValue1 = m_pRecord->getEncryptionDataPtr( m_pvField); + pValue2 = pSomeField->m_pRecord->getEncryptionDataPtr( pSomeField->m_pvField); + + // If the encrypted values are not equal, we can exit. + + if (f_memcmp( pValue1, pValue2, uiFieldLen) != 0) + { + goto Exit; + } + } + } + + // If we get this far, the fields are identical. + + bEqual = TRUE; + +Exit: + + return (bEqual); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void * RecCursor::Scan( + RecCursor * pTargetCursor, + RecFieldMatchTypes * peMatchType) +{ + void * pvIDMatch = NULL; + FLMUINT uiTargetLevel = pTargetCursor->Level(); + FLMBOOL bAdvanced = FALSE; + + *peMatchType = GRD_NoMatch; + + for (RecCursor candidate = this; + candidate.Level() >= uiTargetLevel && !candidate.EndOfRecord(); + candidate.Advance(), bAdvanced = TRUE) + { + if (pTargetCursor->FieldIdIsEqualTo( &candidate)) + { + if (pTargetCursor->FieldValueIsEqualTo( &candidate)) + { + *peMatchType = GRD_ExactMatch; + return (candidate.Field()); + } + else if (*peMatchType == GRD_NoMatch) + { + if (!bAdvanced && isLeafField()) + { + // Only allow ID matches on leaf fields, when cursor hasn't + // advanced + + *peMatchType = GRD_IDMatch; + pvIDMatch = candidate.Field(); + } + } + } + } + + return (pvIDMatch); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void RecCursor::MarkBranchDeleted( + RecCursor * pBeforeCursor, + RecCursor * pAfterCursor) +{ + GRD_DifferenceData difference; + FLMUINT uiStartLevel = pBeforeCursor->RawLevel(); + + difference.type = GRD_DeletedSubtree; + difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); + difference.pBeforeRecord = pBeforeCursor->Record(); + difference.pvBeforeField = pBeforeCursor->Field(); + difference.pAfterRecord = NULL; + difference.pvAfterField = NULL; + + pBeforeCursor->CallBack( difference); + difference.type = GRD_Deleted; + do + { + pBeforeCursor->CallBack( difference); + pBeforeCursor->Advance(); + } while( !pBeforeCursor->EndOfRecord() && + pBeforeCursor->RawLevel() > uiStartLevel); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void RecCursor::MarkModified( + RecCursor * pBeforeCursor, + RecCursor * pAfterCursor) +{ + GRD_DifferenceData difference; + + difference.type = GRD_Modified; + difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); + difference.pBeforeRecord = pBeforeCursor->Record(); + difference.pvBeforeField = pBeforeCursor->Field(); + difference.pAfterRecord = pAfterCursor->Record(); + difference.pvAfterField = pAfterCursor->Field(); + + pBeforeCursor->CallBack( difference); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void RecCursor::MarkInserted( + RecCursor * pAfterCursor) +{ + GRD_DifferenceData difference; + + difference.type = GRD_Inserted; + difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); + difference.pBeforeRecord = NULL; + difference.pvBeforeField = NULL; + difference.pAfterRecord = pAfterCursor->Record(); + difference.pvAfterField = pAfterCursor->Field(); + + pAfterCursor->CallBack( difference); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void RecCursor::MarkRangeInserted( + RecCursor * pAfterCursor, + void * pEndOfRange) +{ + void * pvField; + + for (pvField = pAfterCursor->Field(); + pvField != pEndOfRange; + pvField = pAfterCursor->Field()) + { + + // Note that MarkInserted will advance the field pointer + + RecCursor::MarkInserted( pAfterCursor); + pAfterCursor->Advance(); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void flmRecordDifference( + FlmRecord * pBefore, + FlmRecord * pAfter, + GRD_CallBackFunction pCallBackFunction, + void * pvCallBackData) +{ + RecCursor beforeCursor( pBefore, pCallBackFunction, pvCallBackData); + RecCursor afterCursor( pAfter, pCallBackFunction, pvCallBackData); + + // Iterate through all of the fields in the 'before record' + + while (!beforeCursor.EndOfRecord()) + { + void * pvFound; + RecCursor::RecFieldMatchTypes eMatchType; + + if (afterCursor.EndOfRecord()) + { + RecCursor::MarkBranchDeleted( &beforeCursor, &afterCursor); + continue; + } + + pvFound = afterCursor.Scan( &beforeCursor, &eMatchType); + if (pvFound) + { + // 'before field' found in 'after record' Mark all intervening + // 'after fields' as inserted + + RecCursor::MarkRangeInserted( &afterCursor, pvFound); + + if (eMatchType == RecCursor::GRD_IDMatch) + { + // 'before field' was modified in 'after record' + + RecCursor::MarkModified( &beforeCursor, &afterCursor); + } + + afterCursor.Advance(); + beforeCursor.Advance(); + } + else + { + // 'before field' has been deleted from 'after record' + + RecCursor::MarkBranchDeleted( &beforeCursor, &afterCursor); + } + } + + // The end of the 'before record' has been reached, all remaining + // 'after fields' must have been inserted + + RecCursor::MarkRangeInserted( &afterCursor, NULL); +} + +/**************************************************************************** +Desc: This routine adds a field to a record. +****************************************************************************/ +RCODE flmAddField( + FlmRecord * pRecord, + FLMUINT uiTagNum, + const void * pvData, + FLMUINT uiDataLen, + FLMUINT uiDataType) +{ + RCODE rc = FERR_OK; + void * pvField; + + // Insert new field. + + if( RC_BAD( rc = pRecord->insertLast( 1, uiTagNum, uiDataType, &pvField))) + { + goto Exit; + } + + switch( uiDataType) + { + case FLM_TEXT_TYPE: + { + rc = pRecord->setNative( pvField, (const char *)pvData); + + break; + } + + case FLM_NUMBER_TYPE: + { + FLMUINT uiNum; + + switch (uiDataLen) + { + case 0: + uiNum = (FLMUINT)(*((FLMUINT *)(pvData))); + break; + case 1: + uiNum = (FLMUINT)(*((FLMBYTE *)(pvData))); + break; + case 2: + uiNum = (FLMUINT)(*((FLMUINT16 *)(pvData))); + break; + case 4: + uiNum = (FLMUINT)(*((FLMUINT32 *)(pvData))); + break; + default: + flmAssert( 0); + rc = RC_SET( FERR_INVALID_PARM); + goto Exit; + } + rc = pRecord->setUINT( pvField, uiNum); + break; + } + case FLM_BINARY_TYPE: + { + rc = pRecord->setBinary( pvField, pvData, uiDataLen); + break; + } + default : + { + flmAssert( 0); + break; + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: This routine modifies the first matching field in a record. + If the field is not found, a new field will be created. +****************************************************************************/ +RCODE flmModField( + FlmRecord * pRecord, + FLMUINT uiTagNum, + const void * pvData, + FLMUINT uiDataLen, + FLMUINT uiDataType) +{ + RCODE rc = FERR_OK; + void * pvField; + + if( (pvField = pRecord->find( pRecord->root(), uiTagNum)) == NULL) + { + // Create the field. + + if( RC_BAD( rc = pRecord->insertLast( 1, uiTagNum, uiDataType, &pvField))) + { + goto Exit; + } + } + + switch( uiDataType) + { + case FLM_TEXT_TYPE: + { + rc = pRecord->setNative( pvField, (const char *)pvData); + break; + } + + case FLM_NUMBER_TYPE: + { + FLMUINT uiNum; + switch (uiDataLen) + { + case 0: + uiNum = (FLMUINT)(*((FLMUINT *)(pvData))); + case 1: + uiNum = (FLMUINT)(*((FLMBYTE *)(pvData))); + break; + case 2: + uiNum = (FLMUINT)(*((FLMUINT16 *)(pvData))); + break; + case 4: + uiNum = (FLMUINT)(*((FLMUINT32 *)(pvData))); + break; + default: + flmAssert( 0); + rc = RC_SET( FERR_INVALID_PARM); + goto Exit; + } + + rc = pRecord->setUINT( pvField, uiNum); + break; + } + + case FLM_BINARY_TYPE: + { + rc = pRecord->setBinary( pvField, pvData, uiDataLen); + break; + } + + default : + { + flmAssert( 0); + break; + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: This routine searches for a specific numeric field and deletes + that field from the record. +****************************************************************************/ +RCODE flmDelField( + FlmRecord * pRecord, + FLMUINT uiTagNum, + FLMUINT uiValue) +{ + RCODE rc = FERR_OK; + FLMUINT uiNum; + void * pvField; + + if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) + { + for(;;) + { + if( pRecord->getFieldID( pvField) == uiTagNum) + { + if( RC_BAD( rc = pRecord->getUINT( pvField, &uiNum))) + { + goto Exit; + } + + if( uiNum == uiValue) + { + pRecord->remove( pvField); + break; + } + } + + pvField = pRecord->nextSibling( pvField); + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: This routine finds a field in a record and increments its value. + The value of 1 will be assigned if the field is not present. +****************************************************************************/ +RCODE flmIncrField( + FlmRecord * pRecord, + FLMUINT uiTagNum) +{ + RCODE rc = FERR_OK; + void * pvField; + + if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) + { + FLMUINT uiNum; + + if( RC_OK( rc = pRecord->getUINT( pvField, &uiNum))) + { + uiNum++; + rc = pRecord->setUINT( pvField, uiNum); + } + } + else + { + // Create the field and set the value to one. + + if( RC_OK( rc = pRecord->insertLast( 1, uiTagNum, + FLM_NUMBER_TYPE, &pvField))) + { + rc = pRecord->setUINT( pvField, 1); + } + } + + return( rc); +} + +/**************************************************************************** +Desc: This routine finds a field in a record and decrements its value. +****************************************************************************/ +RCODE flmDecrField( + FlmRecord * pRecord, + FLMUINT uiTagNum) +{ + RCODE rc = FERR_OK; + void * pvField; + + if( (pvField = pRecord->find( pRecord->root(), uiTagNum, 1)) != NULL) + { + FLMUINT uiNum; + + if( RC_OK( rc = pRecord->getUINT( pvField, &uiNum))) + { + uiNum--; + rc = pRecord->setUINT( pvField, uiNum); + } + } + + return( rc); +} + diff --git a/flaim/src/frestore.cpp b/flaim/src/frestore.cpp deleted file mode 100644 index 8faf6d2..0000000 --- a/flaim/src/frestore.cpp +++ /dev/null @@ -1,543 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Database restore. -// Tabs: 3 -// -// Copyright (c) 2001-2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: frestore.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -****************************************************************************/ -F_RflUnknownStream::F_RflUnknownStream() -{ - m_pRfl = NULL; - m_bStartedWriting = FALSE; - m_bInputStream = FALSE; - m_bSetupCalled = FALSE; -} - -/**************************************************************************** -Desc: -****************************************************************************/ -F_RflUnknownStream::~F_RflUnknownStream() -{ - if (m_bSetupCalled) - { - (void)close(); - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_RflUnknownStream::setup( - F_Rfl * pRfl, - FLMBOOL bInputStream) -{ - RCODE rc = FERR_OK; - - flmAssert( !m_bSetupCalled); - - if (!pRfl) - { - flmAssert( 0); - rc = RC_SET( FERR_INVALID_PARM); - goto Exit; - } - m_pRfl = pRfl; - m_bInputStream = bInputStream; - m_bSetupCalled = TRUE; - m_bStartedWriting = FALSE; - -Exit: - return( rc); -} - -/**************************************************************************** -Public: close -****************************************************************************/ -RCODE F_RflUnknownStream::close( void) -{ - RCODE rc = FERR_OK; - - flmAssert( m_bSetupCalled); - - // There is nothing to do for input streams, because the RFL - // code handles skipping over any unknown data that may not have - // been read yet. - // For output streams, we need to call the endLoggingUnknown - // routine so that the last packet gets written out. - - if (!m_bInputStream) - { - if (m_bStartedWriting) - { - m_bStartedWriting = FALSE; - if (RC_BAD( rc = m_pRfl->endLoggingUnknown())) - { - goto Exit; - } - } - } -Exit: - return( rc); -} - -/**************************************************************************** -Public: read - will return FERR_EOF_HIT when there is no more data to read. -****************************************************************************/ -RCODE F_RflUnknownStream::read( - FLMUINT uiLength, - void * pvBuffer, - FLMUINT * puiBytesRead) -{ - RCODE rc = FERR_OK; - - flmAssert( m_bSetupCalled); - - if (!m_bInputStream) - { - - // Cannot read from an output stream. - - flmAssert( 0); - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - if (RC_BAD( rc = m_pRfl->readUnknown( uiLength, (FLMBYTE *)pvBuffer, - puiBytesRead))) - { - goto Exit; - } - -Exit: - return( rc); -} - -/**************************************************************************** -Public: write -****************************************************************************/ -RCODE F_RflUnknownStream::write( - FLMUINT uiLength, - void * pvBuffer) -{ - RCODE rc = FERR_OK; - - flmAssert( m_bSetupCalled); - flmAssert( m_pRfl); - - if (m_bInputStream) - { - - // Cannot write to an input stream. - - flmAssert( 0); - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - // Need to start logging on the first write. - - if (!m_bStartedWriting) - { - if (RC_BAD( rc = m_pRfl->startLoggingUnknown())) - { - goto Exit; - } - m_bStartedWriting = TRUE; - } - - // Log the data. - - if (RC_BAD( rc = m_pRfl->logUnknown( (FLMBYTE *)pvBuffer, uiLength))) - { - goto Exit; - } -Exit: - return( rc); -} - -/*API~*********************************************************************** -Desc: Returns an unknown stream object - suitable for writing unknown - streams into the roll-forward log. -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetUnknownStreamObj( - HFDB hDb, - F_UnknownStream ** ppUnknownStream) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - F_RflUnknownStream * pUnkStream = NULL; - - flmAssert( pDb); - flmAssert( ppUnknownStream); - - // See if the database is being forced to close - - if( RC_BAD( rc = flmCheckDatabaseState( pDb))) - { - goto Exit; - } - - // This is only valid on 4.3 and greater. - - if (pDb->pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; // Will return FERR_OK and a NULL pointer. - } - - // Must be in an update transaction. - - if (pDb->uiTransType == FLM_NO_TRANS) - { - rc = RC_SET( FERR_NO_TRANS_ACTIVE); - goto Exit; - } - if (pDb->uiTransType != FLM_UPDATE_TRANS) - { - rc = RC_SET( FERR_ILLEGAL_TRANS_OP); - goto Exit; - } - - // Allocate the stream object we want. - - if ((pUnkStream = f_new F_RflUnknownStream) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Setup the unknown stream object. - - if (RC_BAD( rc = pUnkStream->setup( pDb->pFile->pRfl, FALSE))) - { - goto Exit; - } - -Exit: - if (RC_BAD( rc) && pUnkStream) - { - pUnkStream->Release(); - pUnkStream = NULL; - } - *ppUnknownStream = (F_UnknownStream *)pUnkStream; - return( rc); -} - -/* -*** R_RestoreFS methods -*/ - -/**************************************************************************** -Public: Constructor -****************************************************************************/ -F_FSRestore::F_FSRestore() -{ - m_pFileHdl = NULL; - m_pFileHdl64 = NULL; - m_ui64Offset = 0; - m_bSetupCalled = FALSE; - m_szDbPath[ 0] = 0; - m_uiDbVersion = 0; - m_szBackupSetPath[ 0] = 0; - m_szRflDir[ 0] = 0; - m_bOpen = FALSE; -} - -/**************************************************************************** -Public: Destructor -****************************************************************************/ -F_FSRestore::~F_FSRestore() -{ - if( m_bOpen) - { - (void)close(); - } -} - -/**************************************************************************** -Public: setup -****************************************************************************/ -RCODE F_FSRestore::setup( - const char * pucDbPath, - const char * pucBackupSetPath, - const char * pucRflDir) -{ - flmAssert( !m_bSetupCalled); - flmAssert( pucDbPath); - flmAssert( pucBackupSetPath); - - f_strcpy( m_szDbPath, pucDbPath); - f_strcpy( m_szBackupSetPath, pucBackupSetPath); - - if( pucRflDir) - { - f_strcpy( m_szRflDir, pucRflDir); - } - - - m_bSetupCalled = TRUE; - return( FERR_OK); -} - -/**************************************************************************** -Public: openBackupSet -****************************************************************************/ -RCODE F_FSRestore::openBackupSet( void) -{ - RCODE rc = FERR_OK; - - flmAssert( m_bSetupCalled); - flmAssert( !m_pFileHdl64); - - if( (m_pFileHdl64 = f_new F_64BitFileHandle) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = m_pFileHdl64->Open( m_szBackupSetPath))) - { - m_pFileHdl64->Release(); - m_pFileHdl64 = NULL; - goto Exit; - } - - m_ui64Offset = 0; - m_bOpen = TRUE; - -Exit: - - return( rc); -} - -/**************************************************************************** -Public: openRflFile -****************************************************************************/ -RCODE F_FSRestore::openRflFile( - FLMUINT uiFileNum) -{ - RCODE rc = FERR_OK; - char szRflPath[ F_PATH_MAX_SIZE]; - char szDbPrefix[ F_FILENAME_SIZE]; - char szBaseName[ F_FILENAME_SIZE]; - FLMBYTE * pBuf = NULL; - FILE_HDR fileHdr; - LOG_HDR logHdr; - F_FileHdl * pFileHdl = NULL; - - flmAssert( m_bSetupCalled); - flmAssert( uiFileNum); - flmAssert( !m_pFileHdl); - - /* - Read the database header to determine the version number - */ - - if( !m_uiDbVersion) - { - if (RC_BAD( rc = f_alloc( 2048, &pBuf))) - { - goto Exit; - } - - if( RC_BAD( rc = gv_FlmSysData.pFileSystem->Open( - m_szDbPath, F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, - &pFileHdl))) - { - goto Exit; - } - - if( RC_BAD( rc = flmReadAndVerifyHdrInfo( NULL, pFileHdl, - pBuf, &fileHdr, &logHdr, NULL))) - { - goto Exit; - } - - pFileHdl->Close(); - pFileHdl->Release(); - pFileHdl = NULL; - - m_uiDbVersion = fileHdr.uiVersionNum; - } - - /* - Generate the log file name. - */ - - if( RC_BAD( rc = rflGetDirAndPrefix( - m_uiDbVersion, m_szDbPath, m_szRflDir, szRflPath, szDbPrefix))) - { - goto Exit; - } - - rflGetBaseFileName( m_uiDbVersion, szDbPrefix, uiFileNum, szBaseName); - f_pathAppend( szRflPath, szBaseName); - - /* - Open the file. - */ - - if( RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( - szRflPath, F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, - 512, &m_pFileHdl))) - { - goto Exit; - } - - m_bOpen = TRUE; - m_ui64Offset = 0; - -Exit: - - if( pBuf) - { - f_free( &pBuf); - } - - if( pFileHdl) - { - pFileHdl->Release(); - } - - return( rc); -} - -/**************************************************************************** -Public: openIncFile -****************************************************************************/ -RCODE F_FSRestore::openIncFile( - FLMUINT uiFileNum) -{ - RCODE rc = FERR_OK; - char szIncPath[ F_PATH_MAX_SIZE]; - char szIncFile[ F_FILENAME_SIZE]; - - flmAssert( m_bSetupCalled); - flmAssert( !m_pFileHdl64); - - /* - Since this is a non-interactive restore, we will "guess" - that incremental backups are located in the same parent - directory as the main backup set. We will further assume - that the incremental backup sets have been named XXXXXXXX.INC, - where X is a hex digit. - */ - - if( RC_BAD( rc = f_pathReduce( m_szBackupSetPath, - szIncPath, NULL))) - { - goto Exit; - } - - f_sprintf( szIncFile, "%08X.INC", (unsigned)uiFileNum); - f_pathAppend( szIncPath, szIncFile); - - if( (m_pFileHdl64 = f_new F_64BitFileHandle) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = m_pFileHdl64->Open( szIncPath))) - { - m_pFileHdl64->Release(); - m_pFileHdl64 = NULL; - goto Exit; - } - - m_ui64Offset = 0; - m_bOpen = TRUE; - -Exit: - - return( rc); -} - -/**************************************************************************** -Public: read -****************************************************************************/ -RCODE F_FSRestore::read( - FLMUINT uiLength, - void * pvBuffer, - FLMUINT * puiBytesRead) -{ - FLMUINT uiBytesRead = 0; - RCODE rc = FERR_OK; - - flmAssert( m_bSetupCalled); - flmAssert( m_pFileHdl || m_pFileHdl64); - - if( m_pFileHdl64) - { - if( RC_BAD( rc = m_pFileHdl64->Read( m_ui64Offset, - uiLength, pvBuffer, &uiBytesRead))) - { - goto Exit; - } - } - else - { - if( RC_BAD( rc = m_pFileHdl->Read( (FLMUINT)m_ui64Offset, - uiLength, pvBuffer, &uiBytesRead))) - { - goto Exit; - } - } - -Exit: - - m_ui64Offset += uiBytesRead; - - if( puiBytesRead) - { - *puiBytesRead = uiBytesRead; - } - - return( rc); -} - -/**************************************************************************** -Public: close -****************************************************************************/ -RCODE F_FSRestore::close( void) -{ - flmAssert( m_bSetupCalled); - - if( m_pFileHdl64) - { - m_pFileHdl64->Release(); - m_pFileHdl64 = NULL; - } - - if( m_pFileHdl) - { - m_pFileHdl->Release(); - m_pFileHdl = NULL; - } - - m_bOpen = FALSE; - m_ui64Offset = 0; - - return( FERR_OK); -} diff --git a/flaim/src/frestore.h b/flaim/src/frestore.h deleted file mode 100644 index 6d8f2ee..0000000 --- a/flaim/src/frestore.h +++ /dev/null @@ -1,149 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Database restore - class definitions -// Tabs: 3 -// -// Copyright (c) 2001-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: frestore.h 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#ifndef FRESTORE_H -#define FRESTORE_H - -#include "fpackon.h" -// IMPORTANT NOTE: No other include files should follow this one except -// for fpackoff.h - -/**************************************************************************** -Desc: This object is our implementation of the - F_UnknownStream object which is used to handle unknown - objects in the RFL. -****************************************************************************/ -class F_RflUnknownStream : public F_UnknownStream -{ -public: - - F_RflUnknownStream(); - virtual ~F_RflUnknownStream(); - - RCODE setup( - F_Rfl * pRfl, - FLMBOOL bInputStream); - - RCODE reset( void); - - RCODE read( - FLMUINT uiLength, // Number of bytes to read - void * pvBuffer, // Buffer to place read bytes into - FLMUINT * puiBytesRead); // [out] Number of bytes read - - RCODE write( - FLMUINT uiLength, // Number of bytes to write - void * pvBuffer); - - RCODE close( void); // Reads to the end of the - // stream and discards any - // remaining data (if input stream). - -private: - - FLMBOOL m_bSetupCalled; - F_Rfl * m_pRfl; // RFL object. - FLMBOOL m_bInputStream; // TRUE=input stream, FALSE=output stream - FLMBOOL m_bStartedWriting; // Only used for output streams -}; - -/**************************************************************************** -Desc: The F_FSRestore class is used to read backup and RFL files from - a disk file system. -****************************************************************************/ -class F_FSRestore : public F_Restore -{ -public: - - F_FSRestore(); - - virtual ~F_FSRestore(); - - RCODE setup( - const char * pucDbPath, - const char * pucBackupSetPath, - const char * pucRflDir); - - RCODE openBackupSet( void); - - RCODE openIncFile( - FLMUINT uiFileNum); - - RCODE openRflFile( - FLMUINT uiFileNum); - - RCODE read( - FLMUINT uiLength, - void * pvBuffer, - FLMUINT * puiBytesRead); - - RCODE close( void); - - FINLINE RCODE abortFile( void) - { - return( close()); - } - - FINLINE RCODE processUnknown( - F_UnknownStream * pUnkStrm) - { - // Skip any unknown data in the RFL - - return( pUnkStrm->close()); - } - - FINLINE RCODE status( - eRestoreStatusType eStatusType, - FLMUINT uiTransId, - void * pvValue1, - void * pvValue2, - void * pvValue3, - eRestoreActionType * peRestoreAction) - { - F_UNREFERENCED_PARM( eStatusType); - F_UNREFERENCED_PARM( uiTransId); - F_UNREFERENCED_PARM( pvValue1); - F_UNREFERENCED_PARM( pvValue2); - F_UNREFERENCED_PARM( pvValue3); - - *peRestoreAction = RESTORE_ACTION_CONTINUE; - return( FERR_OK); - } - -private: - - F_FileHdlImp * m_pFileHdl; - F_64BitFileHandle * m_pFileHdl64; - FLMUINT64 m_ui64Offset; - FLMUINT m_uiDbVersion; - char m_szDbPath[ F_PATH_MAX_SIZE]; - char m_szBackupSetPath[ F_PATH_MAX_SIZE]; - char m_szRflDir[ F_PATH_MAX_SIZE]; - FLMBOOL m_bSetupCalled; - FLMBOOL m_bOpen; -}; - -#include "fpackoff.h" - -#endif diff --git a/flaim/src/frset.h b/flaim/src/frset.h index d84f2ab..5c42aa1 100644 --- a/flaim/src/frset.h +++ b/flaim/src/frset.h @@ -105,7 +105,7 @@ RCODE FRSDefaultCompare( ***** *****************************************************************************/ -typedef struct +typedef struct RSET_CB_INFO { void * UserValue; FLMUINT64 ui64EstTotalUnits; // Estimated total number of units to do. @@ -115,7 +115,6 @@ typedef struct typedef FLMINT (* RSET_CB_FUNC_p)( RSET_CB_INFO *); - /***************************************************************************** ***** ** Forward References @@ -185,7 +184,7 @@ class FResultSetBlk; read the block header i.e. portability is not a problem. ****************************************************************************/ -typedef struct _FBlockHeader +typedef struct FBlockHeader { FLMUINT64 ui64FilePos; // RSBLK_UNSET_FILE_POS or file position FLMUINT uiEntryCount, // Number of entries in block diff --git a/flaim/src/fsblk_u.cpp b/flaim/src/fsblk_u.cpp index 4d08375..26e0b6f 100644 --- a/flaim/src/fsblk_u.cpp +++ b/flaim/src/fsblk_u.cpp @@ -1,364 +1,343 @@ -//------------------------------------------------------------------------- -// Desc: Free blocks, avail list handling -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsblk_u.cpp 12282 2006-01-19 14:52:56 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*************************************************************************** -Desc: Need to use the current avail block - free up and point to next -*****************************************************************************/ -RCODE FSBlockUseNextAvail( - FDB_p pDb, - LFILE * pLFile, - SCACHE ** ppSCacheRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiPbcAddr; - SCACHE * pSCache; - FLMBYTE * pucBlkBuf; - FLMBOOL bGotBlock = FALSE; - FLMBYTE * pucLogHdr; - - pucLogHdr = &pDb->pFile->ucUncommittedLogHdr [0]; - - if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, - pDb->LogHdr.uiFirstAvailBlkAddr, - NULL, &pSCache))) - { - goto Exit; - } - bGotBlock = TRUE; - - /* - GWBUG 34514 - A corruption we have seen a couple of times is where a free - block points to itself in the free list. This will hang the machine - so this check has been added to verify that the block is a free block. - */ - - if( BH_GET_TYPE( pSCache->pucBlk) != BHT_FREE ) - { - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - - /* Log the block because we are changing it! */ - - if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache))) - { - goto Exit; - } - - *ppSCacheRV = pSCache; - pucBlkBuf = pSCache->pucBlk; - - pDb->LogHdr.uiFirstAvailBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf [BH_NEXT_BLK]); - UD2FBA( pDb->LogHdr.uiFirstAvailBlkAddr, &pucLogHdr [LOG_PF_AVAIL_BLKS]); - UD2FBA( 0, &pucBlkBuf [BH_NEXT_BLK]); - - // One less block in the avail list. - - flmDecrUint( &pucLogHdr [LOG_PF_NUM_AVAIL_BLKS], 1); - - // Decrement so chains are consistent - - pucLogHdr [LOG_PF_FIRST_BC_CNT]--; - - if (ALGetNBC( pucBlkBuf) == BT_END) /* or first BC count == 1 */ - { - - /* This is a chain block - so take care of the back chains */ - - uiPbcAddr = ALGetPBC( pucBlkBuf); - ALResetAvailBlk( pucBlkBuf); - - if (uiPbcAddr == BT_END) /* Only block in avail list */ - { - UD2FBA( BT_END, &pucLogHdr [LOG_PF_FIRST_BACKCHAIN]); - pucLogHdr [LOG_PF_FIRST_BC_CNT] = 0; // Should be this already! - } - else - { - SCACHE * pPbcSCache; - - /* - Hit a backchain block - Setup backchain links and adjust - LOG_PF_FIRST_BC_CNT to BACKCHAIN_CNT - This is not perfect because there may - be less blocks in that chain than expected. - */ - - /* Ensure next block is chained. */ - - pucLogHdr [LOG_PF_FIRST_BC_CNT] = BACKCHAIN_CNT; - UD2FBA( (FLMUINT32)uiPbcAddr, &pucLogHdr [LOG_PF_FIRST_BACKCHAIN]); - - /* - Read the previous backchain and modify its - nextBackchain pointer. - */ - - /* Read the old first backchain block and change the NBC. */ - - if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, - NULL, &pPbcSCache))) - { - goto Exit; - } - - /* Log the block because we are changing it! */ - - if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache))) - { - ALPutNBC( pPbcSCache->pucBlk, BT_END); - } - ScaReleaseCache( pPbcSCache, FALSE); - if (RC_BAD( rc)) - { - goto Exit; - } - } - } - - // If this is an index block, check to see if it is encrypted. - if (pLFile && pLFile->pIxd && pLFile->pIxd->uiEncId) - { - pucBlkBuf[ BH_ENCRYPTED] = 1; - } - -Exit: - - if ((RC_BAD( rc)) && (bGotBlock)) - { - ScaReleaseCache( pSCache, FALSE); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine puts a block back in a physical file's avail list. -Notes: This routine assumes that the block pointed to by pSCache has - been locked into memory. Regardless of whether or not the block - is actually freed on disk, its cache will be released. The - cached block should NOT be accessed after a call to FSBlockFree. -*****************************************************************************/ -RCODE FSBlockFree( - FDB_p pDb, - SCACHE * pSCache // Pointer to pointer of cache block - // that is to be freed. NOTE: Regardless of whether - // or not the block is actually freed, it will be - // released. - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiFirstAvailAddress; - FLMBYTE * pucBlkBuf; - FLMUINT uiBlkAddress; - SCACHE * pPbcSCache; - FLMUINT uiPbcAddr; - FLMBYTE * pucLogHdr; - - pucLogHdr = &pDb->pFile->ucUncommittedLogHdr [0]; - - /* Log the block before modifying it. */ - - if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache))) - { - goto Exit; - } - pucBlkBuf = pSCache->pucBlk; - - /* - Set all elements except block address and checkpoint info - to zeros. If you add any new block elements please make - sure they are taken care of here. - */ - - /* Leave block address alone. */ - - uiBlkAddress = GET_BH_ADDR( pucBlkBuf); - - ALResetAvailBlk( pucBlkBuf); - - uiFirstAvailAddress = pDb->LogHdr.uiFirstAvailBlkAddr; - UD2FBA( (FLMUINT32)uiFirstAvailAddress, &pucBlkBuf [BH_NEXT_BLK]); - pucBlkBuf [BH_TYPE] = BHT_FREE; - pucBlkBuf [BH_LEVEL] = 0; - UW2FBA( BH_OVHD, &pucBlkBuf [BH_ELM_END]); - - // Wipe the contents of encrypted blocks... - - if (pucBlkBuf[ BH_ENCRYPTED]) - { - f_memset( &pucBlkBuf[ BH_OVHD], 0, pDb->pFile->FileHdr.uiBlockSize - - BH_OVHD); - pucBlkBuf [BH_ENCRYPTED] = 0; - } - - /* Leave CHECKPOINT, PREV_CP and PREV_BLK_ADDR alone. */ - - /* Update the physical file log information. */ - - pDb->LogHdr.uiFirstAvailBlkAddr = uiBlkAddress; - UD2FBA( (FLMUINT32)uiBlkAddress, &pucLogHdr [LOG_PF_AVAIL_BLKS]); - - /* Is it time to add a new backchain? */ - - if (pucLogHdr [LOG_PF_FIRST_BC_CNT] >= BACKCHAIN_CNT || - FB2UD( &pucLogHdr [LOG_PF_NUM_AVAIL_BLKS]) == 0) - { - /* Start over - increments to 1 below. */ - - pucLogHdr [LOG_PF_FIRST_BC_CNT] = 0; - ALPutNBC( pucBlkBuf, BT_END); - - /* Increment & check if no avail blks. */ - - if (FB2UD( &pucLogHdr [LOG_PF_NUM_AVAIL_BLKS]) == 0) - { - ALPutPBC( pucBlkBuf, BT_END); - } - else - { - uiPbcAddr = (FLMUINT)FB2UD( &pucLogHdr [LOG_PF_FIRST_BACKCHAIN]); - ALPutPBC( pucBlkBuf, uiPbcAddr); - - /* Read the old first backchain block and change the NBC. */ - - if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, - NULL, &pPbcSCache))) - { - goto Exit; - } - - /* Log the block because we are changing it! */ - - if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache))) - { - ALPutNBC( pPbcSCache->pucBlk, uiBlkAddress); - } - ScaReleaseCache( pPbcSCache, FALSE); - if (RC_BAD( rc)) - { - goto Exit; - } - } - UD2FBA( (FLMUINT32)uiBlkAddress, - &pucLogHdr [LOG_PF_FIRST_BACKCHAIN]); - } - - /* Be sure to increment these. */ - - flmIncrUint( &pucLogHdr [LOG_PF_NUM_AVAIL_BLKS], 1); - pucLogHdr [LOG_PF_FIRST_BC_CNT]++; - -Exit: - - ScaReleaseCache( pSCache, FALSE); - return( rc); -} - -/*************************************************************************** -Desc: Fix up the previous/next links removal of the block -Notes: This routine assumes that the block pointed to by pSCache has - been locked into memory. Regardless of whether or not the block - is actually freed on disk, its cache will be released. The - cached block should NOT be accessed after a call to FSBlockFree. -*****************************************************************************/ -RCODE FSBlockFixLinks( - FDB_p pDb, - LFILE * pLFile, // Logical file. - SCACHE * pSCache // Pointer to pointer of block that - // is to be unlinked. NOTE: Regardless of whether - // or not the block is actually freed, it will be - // released. - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiPrevBlkAddr; - FLMUINT uiNextBlkAddr; - FLMBYTE * pucBlkBuf; - - pucBlkBuf = pSCache->pucBlk; - uiPrevBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf [BH_PREV_BLK]); - uiNextBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf [BH_NEXT_BLK]); - - /* First free block. NOTE: Do NOT access pSCache after this call */ - - if (RC_BAD( rc = FSBlockFree( pDb, pSCache))) - { - goto Exit; - } - - /* Read the previous block if current is not the left end. */ - - if (uiPrevBlkAddr != BT_END) - { - if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiPrevBlkAddr, - NULL, &pSCache))) - { - goto Exit; - } - - /* Log the block before modifying it. */ - - if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache))) - { - UD2FBA( uiNextBlkAddr, &pSCache->pucBlk [BH_NEXT_BLK]); - } - ScaReleaseCache( pSCache, FALSE); - if (RC_BAD( rc)) - { - goto Exit; - } - } - - /* Read the next block if current is not the left end. */ - - if (uiNextBlkAddr != BT_END) - { - if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiNextBlkAddr, - NULL, &pSCache))) - { - goto Exit; - } - - /* Log the block before modifying it. */ - - if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache))) - { - UD2FBA( uiPrevBlkAddr, &pSCache->pucBlk [BH_PREV_BLK]); - } - ScaReleaseCache( pSCache, FALSE); - if (RC_BAD( rc)) - { - goto Exit; - } - } - -Exit: - - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Free blocks, avail list handling +// Tabs: 3 +// +// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsblk_u.cpp 12282 2006-01-19 14:52:56 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +/**************************************************************************** +Desc: Need to use the current avail block - free up and point to next +****************************************************************************/ +RCODE FSBlockUseNextAvail( + FDB * pDb, + LFILE * pLFile, + SCACHE ** ppSCacheRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiPbcAddr; + SCACHE * pSCache; + FLMBYTE * pucBlkBuf; + FLMBOOL bGotBlock = FALSE; + FLMBYTE * pucLogHdr; + + pucLogHdr = &pDb->pFile->ucUncommittedLogHdr[0]; + + if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, + pDb->LogHdr.uiFirstAvailBlkAddr, NULL, &pSCache))) + { + goto Exit; + } + + bGotBlock = TRUE; + + // A corruption we have seen a couple of times is where a free block + // points to itself in the free list. This will hang the machine so + // this check has been added to verify that the block is a free block. + + if (BH_GET_TYPE( pSCache->pucBlk) != BHT_FREE) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + // Log the block because we are changing it! + + if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache))) + { + goto Exit; + } + + *ppSCacheRV = pSCache; + pucBlkBuf = pSCache->pucBlk; + + pDb->LogHdr.uiFirstAvailBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_NEXT_BLK]); + UD2FBA( pDb->LogHdr.uiFirstAvailBlkAddr, &pucLogHdr[LOG_PF_AVAIL_BLKS]); + UD2FBA( 0, &pucBlkBuf[BH_NEXT_BLK]); + + // One less block in the avail list. + + flmDecrUint( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS], 1); + + // Decrement so chains are consistent + + pucLogHdr[LOG_PF_FIRST_BC_CNT]--; + + if (ALGetNBC( pucBlkBuf) == BT_END) + { + + // This is a chain block - so take care of the back chains + + uiPbcAddr = ALGetPBC( pucBlkBuf); + ALResetAvailBlk( pucBlkBuf); + + if (uiPbcAddr == BT_END) + { + UD2FBA( BT_END, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]); + pucLogHdr[LOG_PF_FIRST_BC_CNT] = 0; + } + else + { + SCACHE * pPbcSCache; + + // Hit a backchain block Setup backchain links and adjust + // LOG_PF_FIRST_BC_CNT to BACKCHAIN_CNT This is not perfect + // because there may be less blocks in that chain than expected. + // + // Ensure next block is chained. + + pucLogHdr[LOG_PF_FIRST_BC_CNT] = BACKCHAIN_CNT; + UD2FBA( (FLMUINT32) uiPbcAddr, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]); + + // Read the previous backchain and modify its nextBackchain + // pointer. + // + // Read the old first backchain block and change the NBC. + + if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, NULL, + &pPbcSCache))) + { + goto Exit; + } + + // Log the block because we are changing it! + + if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache))) + { + ALPutNBC( pPbcSCache->pucBlk, BT_END); + } + + ScaReleaseCache( pPbcSCache, FALSE); + if (RC_BAD( rc)) + { + goto Exit; + } + } + } + + // If this is an index block, check to see if it is encrypted. + + if (pLFile && pLFile->pIxd && pLFile->pIxd->uiEncId) + { + pucBlkBuf[BH_ENCRYPTED] = 1; + } + +Exit: + + if ((RC_BAD( rc)) && (bGotBlock)) + { + ScaReleaseCache( pSCache, FALSE); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine puts a block back in a physical file's avail list. +****************************************************************************/ +RCODE FSBlockFree( + FDB * pDb, + SCACHE * pSCache) +{ + RCODE rc = FERR_OK; + FLMUINT uiFirstAvailAddress; + FLMBYTE * pucBlkBuf; + FLMUINT uiBlkAddress; + SCACHE * pPbcSCache; + FLMUINT uiPbcAddr; + FLMBYTE * pucLogHdr; + + pucLogHdr = &pDb->pFile->ucUncommittedLogHdr[0]; + + // Log the block before modifying it. + + if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pSCache))) + { + goto Exit; + } + + pucBlkBuf = pSCache->pucBlk; + + // Set all elements except block address and checkpoint info to zeros. + // If you add any new block elements please make sure they are taken + // care of here. + // + // Leave block address alone. + + uiBlkAddress = GET_BH_ADDR( pucBlkBuf); + + ALResetAvailBlk( pucBlkBuf); + + uiFirstAvailAddress = pDb->LogHdr.uiFirstAvailBlkAddr; + UD2FBA( (FLMUINT32) uiFirstAvailAddress, &pucBlkBuf[BH_NEXT_BLK]); + pucBlkBuf[BH_TYPE] = BHT_FREE; + pucBlkBuf[BH_LEVEL] = 0; + UW2FBA( BH_OVHD, &pucBlkBuf[BH_ELM_END]); + + // Wipe the contents of encrypted blocks... + + if (pucBlkBuf[BH_ENCRYPTED]) + { + f_memset( &pucBlkBuf[BH_OVHD], 0, + pDb->pFile->FileHdr.uiBlockSize - BH_OVHD); + pucBlkBuf[BH_ENCRYPTED] = 0; + } + + // Leave CHECKPOINT, PREV_CP and PREV_BLK_ADDR alone. + // Update the physical file log information. + + pDb->LogHdr.uiFirstAvailBlkAddr = uiBlkAddress; + UD2FBA( (FLMUINT32) uiBlkAddress, &pucLogHdr[LOG_PF_AVAIL_BLKS]); + + // Is it time to add a new backchain? + + if (pucLogHdr[LOG_PF_FIRST_BC_CNT] >= BACKCHAIN_CNT || + FB2UD( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS]) == 0) + { + + // Start over - increments to 1 below. + + pucLogHdr[LOG_PF_FIRST_BC_CNT] = 0; + ALPutNBC( pucBlkBuf, BT_END); + + // Increment and check if no avail blocks + + if (FB2UD( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS]) == 0) + { + ALPutPBC( pucBlkBuf, BT_END); + } + else + { + uiPbcAddr = (FLMUINT) FB2UD( &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]); + ALPutPBC( pucBlkBuf, uiPbcAddr); + + // Read the old first backchain block and change the NBC. + + if (RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, uiPbcAddr, NULL, + &pPbcSCache))) + { + goto Exit; + } + + // Log the block because we are changing it! + + if (RC_OK( rc = ScaLogPhysBlk( pDb, &pPbcSCache))) + { + ALPutNBC( pPbcSCache->pucBlk, uiBlkAddress); + } + + ScaReleaseCache( pPbcSCache, FALSE); + if (RC_BAD( rc)) + { + goto Exit; + } + } + + UD2FBA( (FLMUINT32) uiBlkAddress, &pucLogHdr[LOG_PF_FIRST_BACKCHAIN]); + } + + // Be sure to increment these. + + flmIncrUint( &pucLogHdr[LOG_PF_NUM_AVAIL_BLKS], 1); + pucLogHdr[LOG_PF_FIRST_BC_CNT]++; + +Exit: + + ScaReleaseCache( pSCache, FALSE); + return (rc); +} + +/**************************************************************************** +Desc: Fix up the previous/next links +****************************************************************************/ +RCODE FSBlockFixLinks( + FDB * pDb, + LFILE * pLFile, + SCACHE * pSCache) +{ + RCODE rc = FERR_OK; + FLMUINT uiPrevBlkAddr; + FLMUINT uiNextBlkAddr; + FLMBYTE * pucBlkBuf; + + pucBlkBuf = pSCache->pucBlk; + uiPrevBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_PREV_BLK]); + uiNextBlkAddr = (FLMUINT) FB2UD( &pucBlkBuf[BH_NEXT_BLK]); + + // First free block. NOTE: Do NOT access pSCache after this call + + if (RC_BAD( rc = FSBlockFree( pDb, pSCache))) + { + goto Exit; + } + + // Read the previous block if current is not the left end. + + if (uiPrevBlkAddr != BT_END) + { + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiPrevBlkAddr, NULL, + &pSCache))) + { + goto Exit; + } + + // Log the block before modifying it. + + if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache))) + { + UD2FBA( uiNextBlkAddr, &pSCache->pucBlk[BH_NEXT_BLK]); + } + + ScaReleaseCache( pSCache, FALSE); + if (RC_BAD( rc)) + { + goto Exit; + } + } + + // Read the next block if current is not the left end. + + if (uiNextBlkAddr != BT_END) + { + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiNextBlkAddr, + NULL, &pSCache))) + { + goto Exit; + } + + // Log the block before modifying it. + + if (RC_OK( rc = ScaLogPhysBlk( pDb, &pSCache))) + { + UD2FBA( uiPrevBlkAddr, &pSCache->pucBlk[BH_PREV_BLK]); + } + + ScaReleaseCache( pSCache, FALSE); + if (RC_BAD( rc)) + { + goto Exit; + } + } + +Exit: + + return (rc); +} diff --git a/flaim/src/fscomblk.cpp b/flaim/src/fscomblk.cpp index d8e2668..cd3a5cd 100644 --- a/flaim/src/fscomblk.cpp +++ b/flaim/src/fscomblk.cpp @@ -1,641 +1,700 @@ -//------------------------------------------------------------------------- -// Desc: B-tree block combining -// Tabs: 3 -// -// Copyright (c) 1992-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fscomblk.cpp 12283 2006-01-19 14:53:15 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC FLMINT FSBlkCompressPKC( - BTSK_p pStack, - FLMBYTE * pTempPKCBuf); - - -/* -Desc: Build a PKC buffer for a single element -Return: Length used within the PKC buffer -*/ -FINLINE FLMUINT FSElmBuildPKC( - FLMBYTE * pPkcBuf, - FLMBYTE * pElement, - FLMBYTE * pElmPkcBuf, - FLMUINT uiElmOvhd) -{ - FLMUINT uiPkc; - FLMUINT uiKeyLen; - - if( uiElmOvhd == BNE_DATA_OVHD) - return 0; - - uiKeyLen = (FLMUINT)(BBE_GET_KL( pElement )); - - if( (uiPkc = (FLMUINT)(BBE_GET_PKC( pElement))) != 0) - { - f_memmove( pPkcBuf, pElmPkcBuf, uiPkc ); - } - if( uiPkc + uiKeyLen > BBE_PKC_MAX) - uiKeyLen = (FLMUINT)(BBE_PKC_MAX - uiPkc); - - f_memmove( &pPkcBuf[ uiPkc ], &pElement[ uiElmOvhd ], uiKeyLen ); - - return( uiPkc + uiKeyLen); -} - - -/**************************************************************************** -Desc: Try to combine two blocks into a single block. The algorithm will - alternate tring the block to the right or uiLeft of the 'target' block. - The bsCurElm MUST be positioned to the current element. The bsCurElm - may be at the very end of the block not pointing to an element. If - so then if blocks are combine bsCurElm should then be valid. -Notes: Remember that this can be called on any level of the btree. -****************************************************************************/ -RCODE FSCombineBlks( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV /* Stack may change on you */ - ) -{ - RCODE rc = FERR_OK; - BTSK_p pStack = *pStackRV; - SCACHE * pLeftCache; - SCACHE * pRightCache; - FLMBYTE * pLeftBlk; - FLMBYTE * pRightBlk; - FLMBYTE * pBlk = pStack->pBlk; - FLMBOOL bReleaseLeft = FALSE; - FLMBOOL bReleaseRight = FALSE; - FLMUINT uiLeftBlkAddr; - FLMUINT uiRightBlkAddr; - FLMUINT uiLeftBlkEnd; - FLMUINT uiRightBlkEnd; - FLMUINT uiBlkAddr = pStack->uiBlkAddr; - FLMUINT uiBlkEnd = pStack->uiBlkEnd; - FLMUINT uiCurElm = pStack->uiCurElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMUINT uiBlkSize; - FLMUINT uiPosToElm = 0; - FLMUINT uiPosToBlk = 0; - FLMUINT uiSplitPoint; - FLMUINT uiTargetSplitPoint; - FLMINT iTemp; - FLMINT iDelta; - BTSK tempStack; - FLMBYTE pPkcBuf[ BBE_PKC_MAX ]; - DB_STATS * pDbStats; - - f_yieldCPU(); /* NLM - release cpu */ - - /* Return if either block is leftmost or rightmost block */ - uiLeftBlkAddr = (FLMUINT) FB2UD( &pBlk[ BH_PREV_BLK ]); - uiRightBlkAddr = (FLMUINT) FB2UD( &pBlk[ BH_NEXT_BLK ]); - if( ( uiLeftBlkAddr == BT_END) || ( uiRightBlkAddr == BT_END)) - { - goto Exit; // Should return SUCCESS - } - - uiBlkSize = pDb->pFile->FileHdr.uiBlockSize - uiElmOvhd; - - /* Read in left and right blocks - make sure all cache ptrs are valid */ - - if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiLeftBlkAddr, NULL, - &pLeftCache))) - { - goto Exit; - } - bReleaseLeft = TRUE; - - if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiRightBlkAddr, NULL, - &pRightCache))) - { - goto Exit; - } - bReleaseRight = TRUE; - - /* Determine if there is room without compressing first elm in current blk*/ - pLeftBlk = pLeftCache->pucBlk; - uiLeftBlkEnd = (FLMUINT) FB2UW( &pLeftBlk[ BH_BLK_END ]); - pRightBlk = pRightCache->pucBlk; - uiRightBlkEnd = (FLMUINT) FB2UW( &pRightBlk[ BH_BLK_END ]); - - /* Don't want to fill too tight - so don't subtract BH_OVHD from sum */ - if( uiLeftBlkEnd + uiBlkEnd + uiRightBlkEnd > uiBlkSize + uiBlkSize) - { -FSCB_Unpin: - if( bReleaseRight) - { - ScaReleaseCache( pRightCache, FALSE); - bReleaseRight = FALSE; - } - if( bReleaseLeft) - { - ScaReleaseCache( pLeftCache, FALSE); - bReleaseLeft = FALSE; - } - - if( RC_OK( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) - { - pStack->uiCurElm = uiCurElm; - /* bsKeyBuf[] could have been wiped out in a scanTo call! */ - FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM); - } - goto Exit; - } - - /**--------------------------------------------------------------------- - *** This is a very good yet extreamly tricky algorithm! - *** If the delta (difference in size) of the left and right blocks - *** is more than the size of the middle block the entire middle will - *** will be moved to the left or right block that is not very full. - *** Otherwise, uiTargetSplitPoint will be computed to be around the - *** point that will place elements in both blocks to fill the left - *** and right blocks to about the same point. - *** NOTE: Read the comments if all is fuzzy. - ***--------------------------------------------------------------------*/ - - iTemp = uiBlkEnd - BH_OVHD + BBE_PKC_MAX; /* temp is max. bytes to move */ - uiTargetSplitPoint = 0; - - if( uiLeftBlkEnd < uiRightBlkEnd ) /* Put most in the left block */ - { - iDelta = uiRightBlkEnd - uiLeftBlkEnd; - if( iTemp <= iDelta) - pStack->uiCurElm = uiBlkEnd; /* Put all in the left block */ - else - uiTargetSplitPoint = BH_OVHD + iDelta + ((iTemp - iDelta) >> 1); - } - else /* Put most in the right block */ - { - iDelta = uiLeftBlkEnd - uiRightBlkEnd; - if( iTemp <= iDelta ) - pStack->uiCurElm = BH_OVHD; /* Put all in right block */ - else - uiTargetSplitPoint = BH_OVHD + ((iTemp - iDelta) >> 1); - } - - if( uiTargetSplitPoint) /* If try to divide into both blocks */ - { - pStack->uiCurElm = uiTargetSplitPoint; - - /* Scan AFTER targetSplitPoint */ - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0))) - goto Exit; - - /**----------------------------------------------------------------- - *** Last check to see if elements will fit in both blocks. - *** This is still a chance that all elements will go to one block - ***----------------------------------------------------------------*/ - if( ( uiLeftBlkEnd + (pStack->uiCurElm - BH_OVHD) > uiBlkSize ) || - ( uiRightBlkEnd + (uiBlkEnd - pStack->uiCurElm) + BBE_PKC_MAX > uiBlkSize )) - goto FSCB_Unpin; - } - - /* We are now guarenteed to fit!!! - log blocks and start moving */ - - if( (pDbStats = pDb->pDbStats) != NULL) - { - LFILE_STATS * pLFileStats; - - if( (pLFileStats = fdbGetLFileStatPtr( pDb, pLFile)) != NULL) - { - pLFileStats->bHaveStats = - pDbStats->bHaveStats = TRUE; - pLFileStats->ui64BlockCombines++; - } - } - - if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pLeftCache ))) - goto Exit; - pLeftBlk = pLeftCache->pucBlk; - - uiSplitPoint = pStack->uiCurElm; - if( uiSplitPoint != BH_OVHD ) /* Elements to move into LEFT block? */ - { - FLMUINT uiCompressBytes; - FLMUINT uiBytesAdded = uiSplitPoint - BH_OVHD; - - tempStack.pSCache = pLeftCache; - tempStack.pBlk = pLeftCache->pucBlk; - FSBlkToStack( &tempStack ); - tempStack.uiKeyBufSize = MAX_KEY_SIZ; - - /* Algorithm could call the move routine if it wasn't for uiCompressBytes */ - f_memmove( &pLeftBlk[ uiLeftBlkEnd ], &pBlk[ BH_OVHD ], uiBytesAdded ); - tempStack.uiCurElm = uiLeftBlkEnd; - - uiLeftBlkEnd += uiBytesAdded; - tempStack.uiBlkEnd = uiLeftBlkEnd; - UW2FBA( uiLeftBlkEnd, &pLeftBlk[ BH_BLK_END ]); - - uiCompressBytes = FSBlkCompressPKC( &tempStack, pPkcBuf ); - if( uiCompressBytes == 0xFFFF) /* Special case that shouldn't happen. */ - { - rc = RC_SET( FERR_DATA_ERROR); - goto Exit; - } - if( uiCurElm < uiSplitPoint ) - { - uiPosToBlk = uiLeftBlkAddr; - uiPosToElm = (FLMUINT)((uiLeftBlkEnd - uiBytesAdded) + uiCurElm - BH_OVHD); - - // NOTE: uiCompressBytes should be zero for fixed element blocks - see - // FSBlkCompressPKC - - if( uiCurElm != BH_OVHD ) - uiPosToElm -= uiCompressBytes; - } - } - UD2FBA( uiRightBlkAddr, &pLeftBlk[ BH_NEXT_BLK ] ); - ScaReleaseCache( pLeftCache, FALSE); - bReleaseLeft = FALSE; - - /**------------------------------------------------------------------- - *** WOW - done with the left block. Move the rest of the data - *** into the right block. Be carefull to compress the first - *** element of the right block and decompress the element that - *** is at the split point in the middle (deleted) block. - ***------------------------------------------------------------------*/ - - if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pRightCache ))) - goto Exit; - pRightBlk = pRightCache->pucBlk; - - if( uiSplitPoint != uiBlkEnd ) /* Elements to move into RIGHT block? */ - { - FLMBYTE * pSplitPoint = &pBlk[ uiSplitPoint ]; - tempStack.pSCache = pRightCache; - tempStack.pBlk = pRightCache->pucBlk; - FSBlkToStack( &tempStack ); - tempStack.uiKeyBufSize = MAX_KEY_SIZ; - - /* Setup to position to current block and element at end of routine */ - if( uiCurElm >= uiSplitPoint ) - { - uiPosToBlk = uiRightBlkAddr; - uiPosToElm = (FLMUINT)((uiCurElm - uiSplitPoint) + BH_OVHD); - - // No PKC in fixed element blocks. - - if( uiCurElm != uiSplitPoint && tempStack.uiElmOvhd != BNE_DATA_OVHD) - { - uiPosToElm += BBE_GET_PKC( pSplitPoint ); - } - } - /**--------------------------------------------------------------- - *** If ScanTo() doesn't match uiCurElm exact then current element - *** does not have the proper stuff in the pkc buffer or bsKeyBuf - ***--------------------------------------------------------------*/ - /* pStack->uiCurElm is uiSplitPoint */ - FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_AT_CURELM ); - if( RC_BAD( rc = FSBlkMoveElms( &tempStack, pSplitPoint, - (FLMUINT)(uiBlkEnd - uiSplitPoint), pPkcBuf ))) - goto Exit; - } - - UD2FBA( uiLeftBlkAddr, &pRightBlk[ BH_PREV_BLK ] ); - ScaReleaseCache( pRightCache, FALSE); - bReleaseRight = FALSE; - - /* Now we can free the current block - blkFixLinks may work instead */ - - rc = FSBlockFree( pDb, pStack->pSCache); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - if( RC_BAD( rc)) - return( rc ); - - /**---------------------------------------------------------------------- - *** Now the hard part. Go to the parent & delete the current element. - *** Go to the previous element and modify to reflect the new last - *** element in the left block. - ***---------------------------------------------------------------------*/ - - if( RC_BAD( rc = FSDelParentElm( pDb, pLFile, &pStack ))) - return( rc ); - - if( uiSplitPoint != BH_OVHD ) /* Is there is new stuff in left blk?*/ - { - /* Position and fixup the parent elements */ - if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiLeftBlkAddr, pStack))) - { - rc = FSNewLastBlkElm( pDb, pLFile, &pStack, - FSNLBE_GREATER | FSNLBE_POSITION ); - } - } - - /**------------------------------------------------------ - *** Position the pStack to where you should be. - *** The parent element is pointing to the right block. - ***-----------------------------------------------------*/ - if( RC_OK( rc )) - { - /* Read in position block and position to current element */ - if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiPosToBlk, pStack))) - { - pStack->uiCurElm = uiPosToElm; - if( uiPosToBlk == uiLeftBlkAddr ) - { - rc = FSAdjustStack( pDb, pLFile, pStack, FALSE); - } - /**-------------------------------------------- - *** This line must be explained! - *** We should really be replacing the original - *** PKC buffer into what was there before this - *** routine was called. This works because - *** delete/insert pairs call scanTo before the - *** insert. - ***--------------------------------------------*/ - FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM ); - } - } - *pStackRV = pStack; -Exit: - if( bReleaseLeft) - { - ScaReleaseCache( pLeftCache, FALSE); - } - if( bReleaseRight) - { - ScaReleaseCache( pRightCache, FALSE); - } - return( rc ); -} - -/**************************************************************************** -Desc: Move 1 or more elements into the bsCurElm location within a block. - Everything MUST fit. Will compress the element coming in as well - as the element at bsCurElm. This will also work if you are moving - data down within the same block. -****************************************************************************/ -RCODE FSBlkMoveElms( - BTSK_p pStack, /* Stack containing block to accept data*/ - FLMBYTE * pInsertElm, /* Element(s) to insert into block */ - FLMUINT uiInsElmLen, /* Length of the Element(s) */ - FLMBYTE * pElmPkcBuf /* PKC buffer for element if elm has PKC*/ - ) -{ - FLMBYTE * pBlk = pStack->pBlk; - FLMUINT uiCurElm = pStack->uiCurElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMUINT uiBytesInPkc; - - FLMBYTE pInsertElmPckBuf[ BBE_PKC_MAX ]; - FLMUINT uiMovedKeyLen, uiMovedPkc; - FLMUINT uiTemp; - FLMUINT uiNewBlkEnd; - FLMUINT uiInsertElmKeyLen; - FLMINT iDistanceToShiftDown; - FLMUINT uiAreaToShiftDown; - FLMBYTE pPkcBuf[ BBE_PKC_MAX ]; - FLMUINT uiInsertElmPkc; - FLMUINT uiInsertElmPkcLen; - - if( uiElmOvhd == BNE_DATA_OVHD) - { - if( (uiAreaToShiftDown = (pStack->uiBlkEnd - uiCurElm)) > 0) - { - shiftN( &pBlk[ uiCurElm ], uiAreaToShiftDown, uiInsElmLen); - } - f_memmove( &pBlk[ uiCurElm], pInsertElm, uiInsElmLen); - pStack->uiBlkEnd += uiInsElmLen; - UW2FBA( pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]); - goto Exit; - } - - // ELSE Normal complex move with previos key count (PKC) - - /* Puts up to BBE_PKC_MAX bytes in pPkcBuf[] only */ - uiBytesInPkc = FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_BEFORE_CURELM ); - - /* Compute real pkc for element */ - uiInsertElmPkcLen = FSElmBuildPKC( pInsertElmPckBuf, pInsertElm, pElmPkcBuf, uiElmOvhd ); - - uiMovedPkc = FSElmComparePKC( pPkcBuf, uiBytesInPkc, pInsertElmPckBuf, uiInsertElmPkcLen ); - - /**---------------------------------------------------------------- - *** Compute how much area pInsertElm[] will take when moved, - *** compute uiBlkEnd and move most of the element except the key - ***---------------------------------------------------------------*/ - uiInsertElmKeyLen = (FLMUINT)(BBE_GET_KL( pInsertElm )); - uiInsertElmPkc = (FLMUINT)(BBE_GET_PKC( pInsertElm )); - uiMovedKeyLen = (FLMUINT)(uiInsertElmKeyLen + uiInsertElmPkc - uiMovedPkc); - iDistanceToShiftDown = (FLMINT)(uiInsElmLen + uiMovedKeyLen - uiInsertElmKeyLen); - if( (uiAreaToShiftDown = (FLMUINT)(pStack->uiBlkEnd - uiCurElm)) > 0) - { - shiftN( &pBlk[ uiCurElm ], uiAreaToShiftDown, iDistanceToShiftDown ); - } - - uiNewBlkEnd = (FLMUINT)(pStack->uiBlkEnd + iDistanceToShiftDown); - UW2FBA( uiNewBlkEnd, &pBlk[ BH_BLK_END ]); - pStack->uiBlkEnd = uiNewBlkEnd; - - /* Move the first pInsertElm[] overhead values and key to where to be inserted*/ - FSSetElmOvhd( &pBlk[uiCurElm], uiElmOvhd, uiMovedPkc, uiMovedKeyLen, pInsertElm); - - /**-------------------------------------------------------------- - *** The tricky part is to move the key! - *** The key could move in 2 parts pInsertElmPckBuf and pInsertElm[] - ***-------------------------------------------------------------*/ - - if( uiMovedKeyLen + uiMovedPkc > BBE_PKC_MAX ) /* Key not entirely in pPkcBuf[] */ - { - /* Move all that is in the pPkcBuf[] */ - f_memcpy( &pBlk[ uiCurElm + uiElmOvhd ], - &pInsertElmPckBuf[ uiMovedPkc ], - uiTemp = (FLMUINT)(BBE_PKC_MAX - uiMovedPkc) ); - - /* Move the rest that is in the element */ - f_memmove( &pBlk[ uiCurElm + uiElmOvhd + uiTemp ], - &pInsertElm[ uiElmOvhd + uiInsertElmKeyLen - (uiMovedKeyLen - uiTemp) ], - uiMovedKeyLen - uiTemp ); - } - else if( uiMovedKeyLen) - { - /* Entire key fits within the pPkcBuf[] */ - f_memcpy( &pBlk[ uiCurElm + uiElmOvhd ], - &pInsertElmPckBuf[ uiMovedPkc ], uiMovedKeyLen ); - } - /* Move the rest of the element(s) over to the block */ - uiTemp = uiElmOvhd + uiInsertElmKeyLen; - f_memmove( &pBlk[ uiCurElm + uiElmOvhd + uiMovedKeyLen ], /* Better move HIGH-LOW */ - &pInsertElm[ uiTemp ], uiInsElmLen - uiTemp ); - - /**--------------------------------------------------------------- - *** Now - if uiAreaToShiftDown has a value then position to the - *** old uiCurElm and try to compress more out of the element - ***--------------------------------------------------------------*/ - - if( uiAreaToShiftDown) - { - pStack->uiCurElm = uiCurElm + iDistanceToShiftDown; - /* Could change pStack->wBlkEnd */ - FSBlkCompressPKC( pStack, pPkcBuf ); - } - pStack->uiCurElm = uiCurElm; /* Points to start of inserted element(s) */ - -Exit: - return( FERR_OK ); -} - -/**************************************************************************** -Desc: Build the PKC portion scanning in a block to but not - including pStack->uiCurElm -Notes: General routine for split and combine code. - More setup needed if you are calling FSBtInsert() or FSBlkInsElm(). - This routine is fastest known way to build PKC from any element. -****************************************************************************/ -FLMUINT FSBlkBuildPKC( - BTSK_p pStack, - FLMBYTE * pPkcBuf, - FLMUINT uiFlags - ) -{ - FLMUINT uiMoveArea; - FLMUINT uiPkc; - FLMUINT uiTargetCurElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMUINT uiCurElm; - FLMUINT uiElmKeyLen; - FLMBYTE * pCurElm; - - if( uiElmOvhd == BNE_DATA_OVHD) - { - return 0; - } - /* Code below is fastest way to position to bsCurElm */ - uiTargetCurElm = pStack->uiCurElm; - uiMoveArea = uiPkc = 0; - uiCurElm = BH_OVHD; - while( uiCurElm < uiTargetCurElm) - { -FSBB_one_more_time: - - pCurElm = &pStack->pBlk[ uiCurElm ]; - uiElmKeyLen = (FLMUINT)(BBE_GET_KL( pCurElm)); - if( uiElmKeyLen ) - { - /* Move minimum data over to the pPkcBuf[] */ - uiPkc = (FLMUINT)(BBE_GET_PKC( pCurElm )); - uiMoveArea = ((uiPkc + uiElmKeyLen) > BBE_PKC_MAX) - ? (BBE_PKC_MAX - uiPkc) - : uiElmKeyLen; - - /* Most common uiMoveArea value for data records & numeric keys */ - if( uiMoveArea == 1) - pPkcBuf[ uiPkc ] = pCurElm[ uiElmOvhd ]; - else if( uiMoveArea ) - { - f_memmove( &pPkcBuf[ uiPkc ], &pCurElm[ uiElmOvhd ], uiMoveArea); - } - } - - if( pStack->uiBlkType == BHT_LEAF) - { - /* Goto the next element in the block */ - uiCurElm += BBE_GET_RL( pCurElm); - } - else if( BNE_IS_DOMAIN( pCurElm)) /* Non-leaf block */ - { - uiCurElm += BNE_DOMAIN_LEN; - } - uiCurElm += uiElmOvhd + uiElmKeyLen; - } - - /* Hit the target current element */ - if( uiFlags == FSBBPKC_AT_CURELM) - { - /* Copy the current element into the pPkcBuf[] */ - uiFlags = FSBBPKC_BEFORE_CURELM; - goto FSBB_one_more_time; - } - - return( uiPkc + uiMoveArea); -} - -/**************************************************************************** -Desc: Compress out (or in) the PKC bytes in the current element -Notes: pTempPkcBuf passed in only to save pStack space. -****************************************************************************/ -FSTATIC FLMINT FSBlkCompressPKC( - BTSK_p pStack, - FLMBYTE * pTempPkcBuf - ) -{ - FLMUINT uiTempPkcLen; - FLMUINT uiPkcBufLen; - FLMUINT uiCurPkc, uiTruePkc; - FLMINT iCompressBytes = 0; - FLMBYTE * pCurElm; - FLMBYTE pPkcBuf[ BBE_PKC_MAX ]; - - if( pStack->uiElmOvhd == BNE_DATA_OVHD) - goto Exit; - - /* Build the PKC buffer from the block */ - uiTempPkcLen = FSBlkBuildPKC( pStack, pTempPkcBuf, FSBBPKC_BEFORE_CURELM); - - /**------------------------------------------------------- - *** Position to the current element and build its own - *** pkc buffer. Compare and see if equals the current - *** element's pkc value. If not compress/decompress - ***------------------------------------------------------*/ - - pCurElm = &pStack->pBlk[ pStack->uiCurElm ]; - uiCurPkc = (FLMUINT)(BBE_GET_PKC( pCurElm)); - uiPkcBufLen = FSElmBuildPKC( pPkcBuf, pCurElm, pTempPkcBuf, pStack->uiElmOvhd); - - uiTruePkc = FSElmComparePKC( pTempPkcBuf, uiTempPkcLen, pPkcBuf, uiPkcBufLen); - - if( uiTruePkc != uiCurPkc) - { - FLMBYTE * pBlk = pStack->pBlk; - FLMUINT uiCurElm = pStack->uiCurElm; - FLMUINT uiBlkEnd = pStack->uiBlkEnd; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMUINT keyLen = (FLMUINT)(BBE_GET_KL(pCurElm)); - FLMUINT uiTemp; - - if( uiTruePkc > uiCurPkc) - { - /* Need to compress out some more bytes */ - iCompressBytes = uiTruePkc - uiCurPkc; - uiTemp = uiCurElm + uiElmOvhd + iCompressBytes; - shiftN( &pBlk[ uiTemp ], (FLMUINT)(uiBlkEnd - uiTemp), - (FLMINT)(-iCompressBytes)); - - /* Reassign the element overhead */ - FSSetElmOvhd( pCurElm, uiElmOvhd, - (FLMUINT)(uiCurPkc + iCompressBytes), - (FLMUINT)(keyLen - iCompressBytes), - pCurElm); - uiBlkEnd -= iCompressBytes; - } - else /* uiTruePkc < uiCurPkc */ - { - return( 0xFFFF); /* FERR_BTREE_ERROR Cannot ever happen right now */ - } - UW2FBA( uiBlkEnd, &pBlk[ BH_BLK_END ]); - pStack->uiBlkEnd = uiBlkEnd; - } -Exit: - return( iCompressBytes); -} - +//------------------------------------------------------------------------- +// Desc: B-tree block combining +// Tabs: 3 +// +// Copyright (c) 1992-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fscomblk.cpp 12283 2006-01-19 14:53:15 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC FLMINT FSBlkCompressPKC( + BTSK * pStack, + FLMBYTE * pTempPKCBuf); + +/**************************************************************************** +Desc: Build a PKC buffer for a single element Return: Length used within + the PKC buffer +****************************************************************************/ +FINLINE FLMUINT FSElmBuildPKC( + FLMBYTE * pPkcBuf, + FLMBYTE * pElement, + FLMBYTE * pElmPkcBuf, + FLMUINT uiElmOvhd) +{ + FLMUINT uiPkc; + FLMUINT uiKeyLen; + + if (uiElmOvhd == BNE_DATA_OVHD) + { + return (0); + } + + uiKeyLen = (FLMUINT) (BBE_GET_KL( pElement)); + + if ((uiPkc = (FLMUINT) (BBE_GET_PKC( pElement))) != 0) + { + f_memmove( pPkcBuf, pElmPkcBuf, uiPkc); + } + + if (uiPkc + uiKeyLen > BBE_PKC_MAX) + { + uiKeyLen = (FLMUINT) (BBE_PKC_MAX - uiPkc); + } + + f_memmove( &pPkcBuf[uiPkc], &pElement[uiElmOvhd], uiKeyLen); + + return (uiPkc + uiKeyLen); +} + +/**************************************************************************** +Desc: Try to combine two blocks into a single block. The algorithm will + alternate tring the block to the right or uiLeft of the 'target' + block. The bsCurElm MUST be positioned to the current element. + The bsCurElm may be at the very end of the block not pointing + to an element. If so then if blocks are combine bsCurElm should + then be valid. +****************************************************************************/ +RCODE FSCombineBlks( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV) +{ + RCODE rc = FERR_OK; + BTSK * pStack = *pStackRV; + SCACHE * pLeftCache; + SCACHE * pRightCache; + FLMBYTE * pLeftBlk; + FLMBYTE * pRightBlk; + FLMBYTE * pBlk = pStack->pBlk; + FLMBOOL bReleaseLeft = FALSE; + FLMBOOL bReleaseRight = FALSE; + FLMUINT uiLeftBlkAddr; + FLMUINT uiRightBlkAddr; + FLMUINT uiLeftBlkEnd; + FLMUINT uiRightBlkEnd; + FLMUINT uiBlkAddr = pStack->uiBlkAddr; + FLMUINT uiBlkEnd = pStack->uiBlkEnd; + FLMUINT uiCurElm = pStack->uiCurElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMUINT uiBlkSize; + FLMUINT uiPosToElm = 0; + FLMUINT uiPosToBlk = 0; + FLMUINT uiSplitPoint; + FLMUINT uiTargetSplitPoint; + FLMINT iTemp; + FLMINT iDelta; + BTSK tempStack; + FLMBYTE pPkcBuf[BBE_PKC_MAX]; + DB_STATS * pDbStats; + + // Return if either block is leftmost or rightmost block + + uiLeftBlkAddr = (FLMUINT) FB2UD( &pBlk[BH_PREV_BLK]); + uiRightBlkAddr = (FLMUINT) FB2UD( &pBlk[BH_NEXT_BLK]); + + if ((uiLeftBlkAddr == BT_END) || (uiRightBlkAddr == BT_END)) + { + goto Exit; + } + + uiBlkSize = pDb->pFile->FileHdr.uiBlockSize - uiElmOvhd; + + // Read in left and right blocks - make sure all cache ptrs are valid + + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiLeftBlkAddr, NULL, + &pLeftCache))) + { + goto Exit; + } + + bReleaseLeft = TRUE; + + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiRightBlkAddr, NULL, + &pRightCache))) + { + goto Exit; + } + + bReleaseRight = TRUE; + + // Determine if there is room without compressing first elm in current blk + + pLeftBlk = pLeftCache->pucBlk; + uiLeftBlkEnd = (FLMUINT) FB2UW( &pLeftBlk[BH_BLK_END]); + pRightBlk = pRightCache->pucBlk; + uiRightBlkEnd = (FLMUINT) FB2UW( &pRightBlk[BH_BLK_END]); + + // Don't want to fill too tight - so don't subtract BH_OVHD from sum + + if (uiLeftBlkEnd + uiBlkEnd + uiRightBlkEnd > uiBlkSize + uiBlkSize) + { +FSCB_Unpin: + + if (bReleaseRight) + { + ScaReleaseCache( pRightCache, FALSE); + bReleaseRight = FALSE; + } + + if (bReleaseLeft) + { + ScaReleaseCache( pLeftCache, FALSE); + bReleaseLeft = FALSE; + } + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + { + pStack->uiCurElm = uiCurElm; + FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM); + } + + goto Exit; + } + + // This is a very good yet extreamly tricky algorithm! If the delta + // (difference in size) of the left and right blocks is more than the + // size of the middle block the entire middle will will be moved to the + // left or right block that is not very full. Otherwise, + // uiTargetSplitPoint will be computed to be around the point that will + // place elements in both blocks to fill the left and right blocks to + // about the same point. NOTE: Read the comments if all is fuzzy. + + iTemp = uiBlkEnd - BH_OVHD + BBE_PKC_MAX; + uiTargetSplitPoint = 0; + + if (uiLeftBlkEnd < uiRightBlkEnd) + { + iDelta = uiRightBlkEnd - uiLeftBlkEnd; + if (iTemp <= iDelta) + { + pStack->uiCurElm = uiBlkEnd; + } + else + { + uiTargetSplitPoint = BH_OVHD + iDelta + ((iTemp - iDelta) >> 1); + } + } + else + { + iDelta = uiLeftBlkEnd - uiRightBlkEnd; + if (iTemp <= iDelta) + { + pStack->uiCurElm = BH_OVHD; + } + else + { + uiTargetSplitPoint = BH_OVHD + ((iTemp - iDelta) >> 1); + } + } + + if (uiTargetSplitPoint) + { + pStack->uiCurElm = uiTargetSplitPoint; + + // Scan AFTER targetSplitPoint + + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0))) + { + goto Exit; + } + + // Last check to see if elements will fit in both blocks. This is + // still a chance that all elements will go to one block + + if ((uiLeftBlkEnd + (pStack->uiCurElm - BH_OVHD) > uiBlkSize) || + (uiRightBlkEnd + (uiBlkEnd - pStack->uiCurElm) + + BBE_PKC_MAX > uiBlkSize)) + { + goto FSCB_Unpin; + } + } + + // We are now guarenteed to fit!!! - log blocks and start moving + + if ((pDbStats = pDb->pDbStats) != NULL) + { + LFILE_STATS * pLFileStats; + + if ((pLFileStats = fdbGetLFileStatPtr( pDb, pLFile)) != NULL) + { + pLFileStats->bHaveStats = pDbStats->bHaveStats = TRUE; + pLFileStats->ui64BlockCombines++; + } + } + + if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pLeftCache))) + { + goto Exit; + } + + pLeftBlk = pLeftCache->pucBlk; + uiSplitPoint = pStack->uiCurElm; + + if (uiSplitPoint != BH_OVHD) + { + FLMUINT uiCompressBytes; + FLMUINT uiBytesAdded = uiSplitPoint - BH_OVHD; + + tempStack.pSCache = pLeftCache; + tempStack.pBlk = pLeftCache->pucBlk; + FSBlkToStack( &tempStack); + tempStack.uiKeyBufSize = MAX_KEY_SIZ; + + // Algorithm could call the move routine if it wasn't for + // uiCompressBytes + + f_memmove( &pLeftBlk[uiLeftBlkEnd], &pBlk[BH_OVHD], uiBytesAdded); + tempStack.uiCurElm = uiLeftBlkEnd; + + uiLeftBlkEnd += uiBytesAdded; + tempStack.uiBlkEnd = uiLeftBlkEnd; + UW2FBA( uiLeftBlkEnd, &pLeftBlk[BH_BLK_END]); + + uiCompressBytes = FSBlkCompressPKC( &tempStack, pPkcBuf); + + if (uiCompressBytes == 0xFFFF) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + if (uiCurElm < uiSplitPoint) + { + uiPosToBlk = uiLeftBlkAddr; + uiPosToElm = (FLMUINT) ((uiLeftBlkEnd - uiBytesAdded) + uiCurElm - BH_OVHD); + + if (uiCurElm != BH_OVHD) + { + uiPosToElm -= uiCompressBytes; + } + } + } + + UD2FBA( uiRightBlkAddr, &pLeftBlk[BH_NEXT_BLK]); + ScaReleaseCache( pLeftCache, FALSE); + bReleaseLeft = FALSE; + + // Done with the left block. Move the rest of the data into the + // right block. Be carefull to compress the first element of the right + // block and decompress the element that is at the split point in the + // middle (deleted) block. + + if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pRightCache))) + { + goto Exit; + } + + pRightBlk = pRightCache->pucBlk; + + if (uiSplitPoint != uiBlkEnd) + { + FLMBYTE * pSplitPoint = &pBlk[uiSplitPoint]; + + tempStack.pSCache = pRightCache; + tempStack.pBlk = pRightCache->pucBlk; + FSBlkToStack( &tempStack); + tempStack.uiKeyBufSize = MAX_KEY_SIZ; + + // Setup to position to current block and element at end of routine + + if (uiCurElm >= uiSplitPoint) + { + uiPosToBlk = uiRightBlkAddr; + uiPosToElm = (FLMUINT) ((uiCurElm - uiSplitPoint) + BH_OVHD); + + // No PKC in fixed element blocks. + + if (uiCurElm != uiSplitPoint && tempStack.uiElmOvhd != BNE_DATA_OVHD) + { + uiPosToElm += BBE_GET_PKC( pSplitPoint); + } + } + + // If ScanTo() doesn't match uiCurElm exact then current element + // does not have the proper stuff in the pkc buffer or bsKeyBuf + + FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_AT_CURELM); + if (RC_BAD( rc = FSBlkMoveElms( &tempStack, pSplitPoint, + (FLMUINT) (uiBlkEnd - uiSplitPoint), pPkcBuf))) + { + goto Exit; + } + } + + UD2FBA( uiLeftBlkAddr, &pRightBlk[BH_PREV_BLK]); + ScaReleaseCache( pRightCache, FALSE); + bReleaseRight = FALSE; + + // Now we can free the current block + + rc = FSBlockFree( pDb, pStack->pSCache); + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + if (RC_BAD( rc)) + { + return (rc); + } + + // Now the hard part. Go to the parent and delete the current element. + // Go to the previous element and modify to reflect the new last element + // in the left block. + + if (RC_BAD( rc = FSDelParentElm( pDb, pLFile, &pStack))) + { + return (rc); + } + + if (uiSplitPoint != BH_OVHD) + { + + // Position and fixup the parent elements + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, uiLeftBlkAddr, pStack))) + { + rc = FSNewLastBlkElm( pDb, pLFile, &pStack, + FSNLBE_GREATER | FSNLBE_POSITION); + } + } + + // Position the pStack to where you should be. The parent element is + // pointing to the right block. + + if (RC_OK( rc)) + { + + // Read in position block and position to current element + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, uiPosToBlk, pStack))) + { + pStack->uiCurElm = uiPosToElm; + if (uiPosToBlk == uiLeftBlkAddr) + { + rc = FSAdjustStack( pDb, pLFile, pStack, FALSE); + } + + // This line must be explained! We should really be replacing the + // original PKC buffer into what was there before this routine + // was called. This works because delete/insert pairs call scanTo + // before the insert. + + FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM); + } + } + + *pStackRV = pStack; + +Exit: + + if (bReleaseLeft) + { + ScaReleaseCache( pLeftCache, FALSE); + } + + if (bReleaseRight) + { + ScaReleaseCache( pRightCache, FALSE); + } + + return (rc); +} + +/**************************************************************************** +Desc: Move 1 or more elements into the bsCurElm location within a block. +****************************************************************************/ +RCODE FSBlkMoveElms( + BTSK * pStack, // Stack containing block to accept data + FLMBYTE * pInsertElm, // Element(s) to insert into block + FLMUINT uiInsElmLen, // Length of the Element(s) + FLMBYTE * pElmPkcBuf) // PKC buffer for element if elm has PKC +{ + FLMBYTE * pBlk = pStack->pBlk; + FLMUINT uiCurElm = pStack->uiCurElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMUINT uiBytesInPkc; + FLMBYTE pInsertElmPckBuf[BBE_PKC_MAX]; + FLMUINT uiMovedKeyLen; + FLMUINT uiMovedPkc; + FLMUINT uiTemp; + FLMUINT uiNewBlkEnd; + FLMUINT uiInsertElmKeyLen; + FLMINT iDistanceToShiftDown; + FLMUINT uiAreaToShiftDown; + FLMBYTE pPkcBuf[BBE_PKC_MAX]; + FLMUINT uiInsertElmPkc; + FLMUINT uiInsertElmPkcLen; + + if (uiElmOvhd == BNE_DATA_OVHD) + { + if ((uiAreaToShiftDown = (pStack->uiBlkEnd - uiCurElm)) > 0) + { + shiftN( &pBlk[uiCurElm], uiAreaToShiftDown, uiInsElmLen); + } + + f_memmove( &pBlk[uiCurElm], pInsertElm, uiInsElmLen); + pStack->uiBlkEnd += uiInsElmLen; + UW2FBA( pStack->uiBlkEnd, &pBlk[BH_BLK_END]); + goto Exit; + } + + // ELSE Normal complex move with previos key count (PKC); + // Puts up to BBE_PKC_MAX bytes in pPkcBuf[] only + + uiBytesInPkc = FSBlkBuildPKC( pStack, pPkcBuf, FSBBPKC_BEFORE_CURELM); + + // Compute real pkc for element + + uiInsertElmPkcLen = FSElmBuildPKC( pInsertElmPckBuf, pInsertElm, pElmPkcBuf, + uiElmOvhd); + + uiMovedPkc = FSElmComparePKC( pPkcBuf, uiBytesInPkc, pInsertElmPckBuf, + uiInsertElmPkcLen); + + // Compute how much area pInsertElm[] will take when moved, compute + // uiBlkEnd and move most of the element except the key + + uiInsertElmKeyLen = (FLMUINT) (BBE_GET_KL( pInsertElm)); + uiInsertElmPkc = (FLMUINT) (BBE_GET_PKC( pInsertElm)); + uiMovedKeyLen = (FLMUINT) (uiInsertElmKeyLen + uiInsertElmPkc - uiMovedPkc); + iDistanceToShiftDown = (FLMINT) (uiInsElmLen + uiMovedKeyLen - uiInsertElmKeyLen); + + if ((uiAreaToShiftDown = (FLMUINT) (pStack->uiBlkEnd - uiCurElm)) > 0) + { + shiftN( &pBlk[uiCurElm], uiAreaToShiftDown, iDistanceToShiftDown); + } + + uiNewBlkEnd = (FLMUINT) (pStack->uiBlkEnd + iDistanceToShiftDown); + UW2FBA( uiNewBlkEnd, &pBlk[BH_BLK_END]); + pStack->uiBlkEnd = uiNewBlkEnd; + + // Move the first pInsertElm[] overhead values and key to where to be + // inserted + + FSSetElmOvhd( &pBlk[uiCurElm], uiElmOvhd, uiMovedPkc, uiMovedKeyLen, + pInsertElm); + + // The tricky part is to move the key! The key could move in 2 parts + // pInsertElmPckBuf and pInsertElm[] + + if (uiMovedKeyLen + uiMovedPkc > BBE_PKC_MAX) + { + + // Move all that is in the pPkcBuf[] + + f_memcpy( &pBlk[uiCurElm + uiElmOvhd], &pInsertElmPckBuf[uiMovedPkc], + uiTemp = (FLMUINT) (BBE_PKC_MAX - uiMovedPkc)); + + // Move the rest that is in the element + + f_memmove( &pBlk[uiCurElm + uiElmOvhd + uiTemp], + &pInsertElm[uiElmOvhd + uiInsertElmKeyLen - + (uiMovedKeyLen - uiTemp)], uiMovedKeyLen - uiTemp); + } + else if (uiMovedKeyLen) + { + + // Entire key fits within the pPkcBuf[] + + f_memcpy( &pBlk[uiCurElm + uiElmOvhd], &pInsertElmPckBuf[uiMovedPkc], + uiMovedKeyLen); + } + + // Move the rest of the element(s) over to the block + + uiTemp = uiElmOvhd + uiInsertElmKeyLen; + f_memmove( &pBlk[uiCurElm + uiElmOvhd + uiMovedKeyLen], + &pInsertElm[uiTemp], uiInsElmLen - uiTemp); + + // Now if uiAreaToShiftDown has a value then position to the old + // uiCurElm and try to compress more out of the element + + if (uiAreaToShiftDown) + { + pStack->uiCurElm = uiCurElm + iDistanceToShiftDown; + + // Could change pStack->wBlkEnd + + FSBlkCompressPKC( pStack, pPkcBuf); + } + + // Points to start of inserted element(s) + + pStack->uiCurElm = uiCurElm; + +Exit: + + return (FERR_OK); +} + +/**************************************************************************** +Desc: Build the PKC portion scanning in a block to but not including + pStack->uiCurElm +****************************************************************************/ +FLMUINT FSBlkBuildPKC( + BTSK * pStack, + FLMBYTE * pPkcBuf, + FLMUINT uiFlags) +{ + FLMUINT uiMoveArea; + FLMUINT uiPkc; + FLMUINT uiTargetCurElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMUINT uiCurElm; + FLMUINT uiElmKeyLen; + FLMBYTE * pCurElm; + + if (uiElmOvhd == BNE_DATA_OVHD) + { + return (0); + } + + // Code below is fastest way to position to bsCurElm + + uiTargetCurElm = pStack->uiCurElm; + uiMoveArea = uiPkc = 0; + uiCurElm = BH_OVHD; + while (uiCurElm < uiTargetCurElm) + { +FSBB_one_more_time: + + pCurElm = &pStack->pBlk[uiCurElm]; + uiElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm)); + if (uiElmKeyLen) + { + + // Move minimum data over to the pPkcBuf[] + + uiPkc = (FLMUINT) (BBE_GET_PKC( pCurElm)); + uiMoveArea = ((uiPkc + uiElmKeyLen) > BBE_PKC_MAX) + ? (BBE_PKC_MAX - uiPkc) + : uiElmKeyLen; + + // Most common uiMoveArea value for data records and numeric keys + + if (uiMoveArea == 1) + { + pPkcBuf[uiPkc] = pCurElm[uiElmOvhd]; + } + else if (uiMoveArea) + { + f_memmove( &pPkcBuf[uiPkc], &pCurElm[uiElmOvhd], uiMoveArea); + } + } + + if (pStack->uiBlkType == BHT_LEAF) + { + + // Goto the next element in the block + + uiCurElm += BBE_GET_RL( pCurElm); + } + else if (BNE_IS_DOMAIN( pCurElm)) + { + uiCurElm += BNE_DOMAIN_LEN; + } + + uiCurElm += uiElmOvhd + uiElmKeyLen; + } + + // Hit the target current element + + if (uiFlags == FSBBPKC_AT_CURELM) + { + + // Copy the current element into the pPkcBuf[] + + uiFlags = FSBBPKC_BEFORE_CURELM; + goto FSBB_one_more_time; + } + + return (uiPkc + uiMoveArea); +} + +/**************************************************************************** +Desc: Compress out (or in) the PKC bytes in the current element +****************************************************************************/ +FSTATIC FLMINT FSBlkCompressPKC( + BTSK * pStack, + FLMBYTE * pTempPkcBuf) +{ + FLMUINT uiTempPkcLen; + FLMUINT uiPkcBufLen; + FLMUINT uiCurPkc; + FLMUINT uiTruePkc; + FLMINT iCompressBytes = 0; + FLMBYTE * pCurElm; + FLMBYTE pPkcBuf[BBE_PKC_MAX]; + + if (pStack->uiElmOvhd == BNE_DATA_OVHD) + { + goto Exit; + } + + // Build the PKC buffer from the block + + uiTempPkcLen = FSBlkBuildPKC( pStack, pTempPkcBuf, FSBBPKC_BEFORE_CURELM); + + // Position to the current element and build its own pkc buffer. + // Compare and see if equals the current element's pkc value. If not + // compress/decompress. + + pCurElm = &pStack->pBlk[pStack->uiCurElm]; + uiCurPkc = (FLMUINT) (BBE_GET_PKC( pCurElm)); + uiPkcBufLen = FSElmBuildPKC( pPkcBuf, pCurElm, pTempPkcBuf, pStack->uiElmOvhd); + uiTruePkc = FSElmComparePKC( pTempPkcBuf, uiTempPkcLen, pPkcBuf, uiPkcBufLen); + + if (uiTruePkc != uiCurPkc) + { + FLMBYTE * pBlk = pStack->pBlk; + FLMUINT uiCurElm = pStack->uiCurElm; + FLMUINT uiBlkEnd = pStack->uiBlkEnd; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMUINT keyLen = (FLMUINT) (BBE_GET_KL( pCurElm)); + FLMUINT uiTemp; + + if (uiTruePkc > uiCurPkc) + { + + // Need to compress out some more bytes + + iCompressBytes = uiTruePkc - uiCurPkc; + uiTemp = uiCurElm + uiElmOvhd + iCompressBytes; + shiftN( &pBlk[uiTemp], (FLMUINT) (uiBlkEnd - uiTemp), + (FLMINT) (-iCompressBytes)); + + // Reassign the element overhead + + FSSetElmOvhd( pCurElm, uiElmOvhd, (FLMUINT) (uiCurPkc + iCompressBytes), + (FLMUINT) (keyLen - iCompressBytes), pCurElm); + uiBlkEnd -= iCompressBytes; + } + else + { + return (0xFFFF); + } + + UW2FBA( uiBlkEnd, &pBlk[BH_BLK_END]); + pStack->uiBlkEnd = uiBlkEnd; + } + +Exit: + + return (iCompressBytes); +} diff --git a/flaim/src/fsconvrt.cpp b/flaim/src/fsconvrt.cpp index cbbf388..04aa765 100644 --- a/flaim/src/fsconvrt.cpp +++ b/flaim/src/fsconvrt.cpp @@ -25,17 +25,17 @@ #include "flaimsys.h" FSTATIC RCODE FSConvertNonLeafTree( - FDB_p pDb, + FDB * pDb, LFILE * pLFile, - BTSK_p pOldStack, - BTSK_p pOldStackBase, + BTSK * pOldStack, + BTSK * pOldStackBase, FLMUINT uiNewVersion, STATUS_HOOK fnStatusCallback, void * UserData, DB_UPGRADE_INFO * pDbConvertInfo); FSTATIC void FSBuildNonLeafDataElement( - BTSK_p pStack, + BTSK * pStack, FLMBYTE * pElement, FLMUINT * puiElmLen, FLMUINT uiNewElmOvhd, @@ -45,7 +45,7 @@ FSTATIC void FSBuildNonLeafDataElement( Desc: File system conversions from one version to another. *****************************************************************************/ RCODE FSVersionConversion40( - FDB_p pDb, + FDB * pDb, FLMUINT uiNewVersion, STATUS_HOOK fnStatusCallback, void * UserData) @@ -55,7 +55,7 @@ RCODE FSVersionConversion40( LFILE * pLFileTbl; FLMUINT uiPos, uiTblSize; FLMUINT uiCurrentVersion; - BTSK_p pStack; + BTSK * pStack; BTSK stackBuf[ BH_MAX_LEVELS ]; FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ]; FLMBYTE pDrnKey[ DIN_KEY_SIZ]; @@ -125,10 +125,10 @@ Desc: Convert the non-leaf data blocks from one version to another version. and make this the new tree while freeing up the old non-leaf blocks. *****************************************************************************/ FSTATIC RCODE FSConvertNonLeafTree( - FDB_p pDb, + FDB * pDb, LFILE * pLFile, - BTSK_p pOldStack, - BTSK_p pOldStackBase, + BTSK * pOldStack, + BTSK * pOldStackBase, FLMUINT uiNewVersion, STATUS_HOOK fnStatusCallback, void * UserData, @@ -136,7 +136,7 @@ FSTATIC RCODE FSConvertNonLeafTree( { RCODE rc = FERR_OK; BTSK stackBuf[ BH_MAX_LEVELS ]; - BTSK_p pStack; + BTSK * pStack; FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ]; FLMBYTE pDrnKey[ DIN_KEY_SIZ]; FLMBYTE pElement[ DIN_KEY_SIZ + 16]; // Enough bytes for either format @@ -202,7 +202,7 @@ FSTATIC RCODE FSConvertNonLeafTree( UW2FBA( BH_OVHD, &pStack->pBlk[ BH_BLK_END]); - if( uiNewVersion >= FLM_VER_4_0) + if( uiNewVersion >= FLM_FILE_FORMAT_VER_4_0) { pStack->pBlk[ BH_TYPE ] = BHT_NON_LEAF_DATA + BHT_ROOT_BLK; } @@ -233,7 +233,7 @@ FSTATIC RCODE FSConvertNonLeafTree( FSBuildNonLeafDataElement( pOldStack, pElement, &uiElmLen, pStack->uiElmOvhd, &pKey); - if( uiNewVersion <= FLM_VER_3_02) + if( uiNewVersion <= FLM_FILE_FORMAT_VER_3_02) { flmAssert( pStack->uiCurElm == pStack->uiBlkEnd); if( pStack != stackBuf) @@ -314,7 +314,7 @@ Exit: Desc: Build a non-leaf data element from the current stack position. *****************************************************************************/ FSTATIC void FSBuildNonLeafDataElement( - BTSK_p pStack, + BTSK * pStack, FLMBYTE * pElement, FLMUINT * puiElmLen, FLMUINT uiNewElmOvhd, diff --git a/flaim/src/fscounts.cpp b/flaim/src/fscounts.cpp index affd3b7..cbd520c 100644 --- a/flaim/src/fscounts.cpp +++ b/flaim/src/fscounts.cpp @@ -26,15 +26,14 @@ extern FLMBYTE SENLenArray[]; - /*************************************************************************** Desc: Compute the number of blocks between two stack positions. These values may be estimated or actual. *****************************************************************************/ RCODE FSComputeRecordBlocks( // Returns WERR_OK or FERR_BTREE_ERROR - BTSK_p pFromStack, // [in] - be carefull not to change + BTSK * pFromStack, // [in] - be carefull not to change // anything in this structure. - BTSK_p pUntilStack, // [in] + BTSK * pUntilStack, // [in] FLMUINT * puiLeafBlocksBetween, // [out] blocks between the stacks FLMUINT * puiTotalRecords, // [out] FLMBOOL * pbTotalsEstimated)// [out] Set to TRUE when estimating. @@ -80,6 +79,7 @@ RCODE FSComputeRecordBlocks( // Returns WERR_OK or FERR_BTREE_ERROR } // Get (or estimate) the number of elements in the parent block. + *pbTotalsEstimated = TRUE; if( RC_BAD( rc = FSBlockCounts( pFromStack, BH_OVHD, pFromStack->uiBlkEnd, &uiEstRecordCount, NULL, NULL))) @@ -179,27 +179,28 @@ Notes: There are two versions for this routine in the way of estimating the LFILE. *****************************************************************************/ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR - BTSK_p pFromStack, // [in] - be carefull not to change - // anything in this structure. - BTSK_p pUntilStack, // [in] - FLMUINT * puiLeafBlocksBetween, // [out] blocks between the stacks - FLMUINT * puiTotalKeys, // [out] total number of keys inclusive - FLMUINT * puiTotalRefs, // [out] total references inclusive - FLMBOOL * pbTotalsEstimated)// [out] Set to TRUE when estimating. + BTSK * pFromStack, // [in] - be carefull not to change + // anything in this structure. + BTSK * pUntilStack, // [in] + FLMUINT * puiLeafBlocksBetween, // [out] blocks between the stacks + FLMUINT * puiTotalKeys, // [out] total number of keys inclusive + FLMUINT * puiTotalRefs, // [out] total references inclusive + FLMBOOL * pbTotalsEstimated) // [out] Set to TRUE when estimating. { RCODE rc = FERR_OK; - FLMUINT uiTotalKeys, - uiTempKeyCount, - uiEstKeyCount; - FLMUINT uiTotalRefs, - uiTempRefCount, - uiEstRefCount; - FLMUINT uiTotalBlocksBetween, - uiEstBlocksBetween; + FLMUINT uiTotalKeys; + FLMUINT uiTempKeyCount; + FLMUINT uiEstKeyCount; + FLMUINT uiTotalRefs; + FLMUINT uiTempRefCount; + FLMUINT uiEstRefCount; + FLMUINT uiTotalBlocksBetween; + FLMUINT uiEstBlocksBetween; FLMBYTE * pBlk; uiTotalBlocksBetween = uiTotalKeys = uiTotalRefs = 0; *pbTotalsEstimated = FALSE; + // Are the from and until positions in the same block? if( pFromStack->uiBlkAddr == pUntilStack->uiBlkAddr) @@ -231,13 +232,12 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR goto Exit; } - /* - Estimate number of keys/refs in the leaf block. - Estimate using just the left block. The right block may be a right-most - block so will scew the results. - */ - + // Estimate number of keys/refs in the leaf block. + // Estimate using just the left block. The right block may be a right-most + // block so will skew the results. + // // Code for non-leaf child counts is easy - no need to estimate. + if( (pFromStack-1)->uiBlkType != BHT_NON_LEAF_COUNTS) { *pbTotalsEstimated = TRUE; @@ -251,24 +251,29 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR for(;;) { - FLMUINT uiElementCount, // These are non-leaf elements. - uiTempElementCount, - uiEstElementCount, - uiRefCount; + FLMUINT uiElementCount; + FLMUINT uiTempElementCount; + FLMUINT uiEstElementCount; + FLMUINT uiRefCount; FLMBYTE * pCounts; // Go up a b-tree level and check out how far apart the elements are. + pFromStack--; pUntilStack--; // Share the same block? + if( pFromStack->uiBlkAddr == pUntilStack->uiBlkAddr) { if( RC_BAD( rc = FSBlockCounts( pFromStack, pFromStack->uiCurElm, pUntilStack->uiCurElm, NULL, &uiElementCount, &uiRefCount))) + { goto Exit; + } // Don't count the current element nor the ref counts. + uiElementCount--; if( pFromStack->uiBlkType == BHT_NON_LEAF_COUNTS) { @@ -290,7 +295,7 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR uiTotalKeys += uiEstKeyCount * uiElementCount; uiTotalRefs += uiEstRefCount * uiElementCount; } - // DONE ! + goto Exit; } @@ -298,8 +303,12 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR if( RC_BAD( rc = FSBlockCounts( pFromStack, pFromStack->uiCurElm, pFromStack->uiBlkEnd, NULL, &uiElementCount, &uiRefCount))) + { goto Exit; + } + // Don't count the first element. + uiElementCount--; if( pFromStack->uiBlkType == BHT_NON_LEAF_COUNTS) @@ -311,12 +320,14 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR if( RC_BAD( rc = FSBlockCounts( pUntilStack, BH_OVHD, pUntilStack->uiCurElm, NULL, &uiTempElementCount, &uiRefCount))) + { goto Exit; + } uiElementCount += uiTempElementCount; - uiTotalBlocksBetween += uiEstBlocksBetween * uiElementCount; uiTotalKeys += uiEstKeyCount * uiElementCount; + if( pUntilStack->uiBlkType == BHT_NON_LEAF_COUNTS) { uiTotalRefs += uiRefCount; @@ -343,7 +354,9 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR if( RC_BAD( rc = FSBlockCounts( pFromStack, BH_OVHD, pFromStack->uiBlkEnd, NULL, &uiEstElementCount, NULL))) + { goto Exit; + } // Adjust the estimated key/ref count to be the counts from a complete // (not partial) block starting at this level going to the leaf. @@ -354,18 +367,22 @@ RCODE FSComputeIndexCounts( // Returns WERR_OK or FERR_BTREE_ERROR } Exit: + if( puiLeafBlocksBetween) { *puiLeafBlocksBetween = uiTotalBlocksBetween; } + if( puiTotalKeys) { *puiTotalKeys = uiTotalKeys; } + if( puiTotalRefs) { *puiTotalRefs = uiTotalRefs; } + return( rc); } @@ -374,7 +391,7 @@ Desc: Returns the number of first keys (elements with the first flag), elements and references (for leaf blocks). *****************************************************************************/ RCODE FSBlockCounts( // Returns WERR_OK currently. - BTSK_p pStack, // [in] - be careful not to change + BTSK * pStack, // [in] - be careful not to change // anything in this structure. FLMUINT uiFirstElement, // [in] start at this element FLMUINT uiLastElement, // [in] Do not include reference counts @@ -392,7 +409,6 @@ RCODE FSBlockCounts( // Returns WERR_OK currently. FLMBOOL bHaveNonleafElementCounts; BTSK tempStack; - // Debug checks. flmAssert( uiFirstElement <= uiLastElement); flmAssert( uiLastElement <= pStack->uiBlkEnd); @@ -409,18 +425,8 @@ RCODE FSBlockCounts( // Returns WERR_OK currently. (tempStack.uiBlkType == BHT_NON_LEAF_COUNTS) ? TRUE : FALSE; // Position to uiFirstElement (it could be bogus). - // The while() code is safer but lots slower. -#if 0 - while( tempStack.uiCurElm < uiFirstElement) - { - if( FSBlkNextElm( &tempStack) == FERR_BT_END_OF_DATA) - { - break; - } - } -#else + tempStack.uiCurElm = uiFirstElement; -#endif // Loop gathering the statistics. @@ -435,6 +441,7 @@ RCODE FSBlockCounts( // Returns WERR_OK currently. uiFirstKeyCount++; } } + if( puiRefCount) { if( !bHaveNonleafElementCounts) @@ -449,21 +456,28 @@ RCODE FSBlockCounts( // Returns WERR_OK currently. } // Next element. + if( FSBlkNextElm( &tempStack) == FERR_BT_END_OF_DATA) + { break; + } } + if( puiFirstKeyCount) { *puiFirstKeyCount = uiFirstKeyCount; } + if( puiElementCount) { *puiElementCount = uiElementCount; } + if( puiRefCount) { *puiRefCount = uiRefCount; } + return( rc); } @@ -471,8 +485,8 @@ RCODE FSBlockCounts( // Returns WERR_OK currently. Desc: Returns the number of references at the current b-tree element. Leaf level blocks must be passed in and the block must be usable. *****************************************************************************/ -FLMUINT FSElementRefCount( // Returns the number of references - BTSK_p pStack) // [in] +FLMUINT FSElementRefCount( // Returns the number of references + BTSK * pStack) // [in] { FLMUINT uiRefCount; FLMBYTE * pCurRef; // Points to current reference @@ -480,14 +494,18 @@ FLMUINT FSElementRefCount( // Returns the number of references FLMUINT uiRefSize; // Size of the reference set DIN_STATE tempState; - // Check block type. + // Check block type + if( pStack->uiBlkType != BHT_LEAF) { uiRefCount = 0; goto Exit; } + uiRefCount = 1; + // Point to the start of the current reference skipping over domain info. + pCurRef = pCurElm = CURRENT_ELM( pStack ); (void) FSGetDomain( &pCurRef, pStack->uiElmOvhd ); uiRefSize = (FLMUINT)(BBE_GET_RL(pCurElm) - @@ -496,13 +514,14 @@ FLMUINT FSElementRefCount( // Returns the number of references RESET_DINSTATE( tempState ); // Read the first reference - there must be at least one reference. + (void) DINNextVal( pCurRef, &tempState ); while( tempState.uiOffset < uiRefSize ) { FLMUINT uiNextLength; - /* Get the current byte to see what kind of item it is */ + // Get the current byte to see what kind of item it is if( (uiNextLength = SENValLen( pCurRef + tempState.uiOffset)) == 0) { @@ -514,10 +533,11 @@ FLMUINT FSElementRefCount( // Returns the number of references uiRefCount++; } } + Exit: - return uiRefCount; -} + return (uiRefCount); +} /*************************************************************************** Desc: Read in the child block and set the counts in the input element. @@ -540,23 +560,30 @@ RCODE FSUpdateAdjacentBlkCounts( { goto Exit; } + pStack = pBaseStack; pStack--; + if( RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) { if( rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_BTREE_ERROR); } + goto Exit; } + pStack = pBaseStack; + if( RC_BAD( rc = FSUpdateBlkCounts( pDb, pStack, uiNextBlkCount))) { goto Exit; } + pStack = pBaseStack; pStack--; + if( RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack))) { if( rc == FERR_BT_END_OF_DATA) @@ -567,6 +594,7 @@ RCODE FSUpdateAdjacentBlkCounts( } Exit: + return( rc); } @@ -602,16 +630,20 @@ RCODE FSUpdateBlkCounts( bFirstTime = FALSE; // If the delta is zero there is nothing to do. + if( !iDelta) { break; } } + // Log the block. + if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) { goto Exit; } + // The block should be able to be used. uiCount = uiCount - iDelta; @@ -619,6 +651,7 @@ RCODE FSUpdateBlkCounts( } Exit: + return( rc); } @@ -630,8 +663,8 @@ Desc: For a positioning index update the count in all the parent elements. *****************************************************************************/ RCODE FSChangeCount( FDB * pDb, - BTSK_p pStack, - FLMBOOL bAddReference) // If FALSE decrement the referernce + BTSK * pStack, + FLMBOOL bAddReference) // If FALSE, decrement the reference { RCODE rc = FERR_OK; FLMBYTE * pCurElm; @@ -640,17 +673,21 @@ RCODE FSChangeCount( while( !BH_IS_ROOT_BLK( pStack->pBlk)) { // Go to the parent and increment/decrement the counts. + pStack--; // Log the block. + if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) { goto Exit; } + // The block should be able to be used. pCurElm = pStack->pBlk + pStack->uiCurElm; uiCount = FB2UD( &pCurElm[ BNE_CHILD_COUNT]); + if( bAddReference) { uiCount++; @@ -658,14 +695,18 @@ RCODE FSChangeCount( else { // Don't allow value to be less than zero. + if( uiCount) { uiCount--; } } + UD2FBA( uiCount, &pCurElm[ BNE_CHILD_COUNT]); } + Exit: + return( rc); } @@ -686,6 +727,7 @@ RCODE FSChangeBlkCounts( while( !BH_IS_ROOT_BLK( pStack->pBlk)) { // Go to the parent and increment/decrement the counts. + pStack--; pCurElm = pStack->pBlk + pStack->uiCurElm; @@ -695,16 +737,19 @@ RCODE FSChangeBlkCounts( ? 0 : (FLMUINT) (uiCount + iDelta); // Log the block. + if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) { goto Exit; } + // The block should be able to be used. UD2FBA( uiCount, &pCurElm[ BNE_CHILD_COUNT]); } Exit: + return( rc); } @@ -724,7 +769,9 @@ RCODE FSGetBtreeRefPosition( FLMUINT uiRefCount; F_UNREFERENCED_PARM( pDb); + // Compute the reference counts before all the current elements up the tree. + if( RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, pStack->uiCurElm, NULL, NULL, &uiTotalCount))) { @@ -732,6 +779,7 @@ RCODE FSGetBtreeRefPosition( } // This must be a one-based number (first reference is 1). + if( !pDinState->uiOffset) { uiTotalCount++; @@ -753,6 +801,7 @@ RCODE FSGetBtreeRefPosition( (pCurRef - BBE_REC_PTR(pCurElm))); // Read the first reference - there must be at least one reference. + (void) DINNextVal( pCurRef, &tempState ); while( tempState.uiOffset < pDinState->uiOffset @@ -760,7 +809,7 @@ RCODE FSGetBtreeRefPosition( { FLMUINT uiNextLength; - /* Get the current byte to see what kind of item it is */ + // Get the current byte to see what kind of item it is if( (uiNextLength = SENValLen( pCurRef + tempState.uiOffset)) == 0) { @@ -772,17 +821,21 @@ RCODE FSGetBtreeRefPosition( uiRefCount++; } } + if( tempState.uiOffset == pDinState->uiOffset && pDinState->uiOnes) { uiRefCount += pDinState->uiOnes; } + uiTotalCount += uiRefCount; } // Go up the stack and keep the count up. + while( !BH_IS_ROOT_BLK( pStack->pBlk)) { // Go to the parent and increment/decrement the counts. + pStack--; if( RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, pStack->uiCurElm, @@ -790,10 +843,12 @@ RCODE FSGetBtreeRefPosition( { goto Exit; } + uiTotalCount += uiRefCount; } Exit: + *puiRefPosition = uiTotalCount; return( rc); } @@ -813,8 +868,8 @@ RCODE FSPositionSearch( DIN_STATE * pDinState) { RCODE rc; - BTSK_p pStack = *ppStack; - FLMBYTE * pKeyBuf = pStack->pKeyBuf;// Used to set key buf on each btsk. + BTSK * pStack = *ppStack; + FLMBYTE * pKeyBuf = pStack->pKeyBuf; FLMUINT uiBlkAddr; LFILE TmpLFile; @@ -841,23 +896,29 @@ RCODE FSPositionSearch( { goto Exit; } + if( !pStack->uiLevel) + { break; + } uiBlkAddr = FSChildBlkAddr( pStack ); pStack++; pStack->pKeyBuf = pKeyBuf; if( RC_BAD(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack ))) + { goto Exit; + } } - *ppStack = pStack; // Set the stack return value. + + *ppStack = pStack; Exit: + return( rc); } - /*************************************************************************** Desc: Position to the element given a position value relative to the block. *****************************************************************************/ @@ -920,6 +981,7 @@ RCODE FSPositionScan( else { // Copy the key into the key buffer. + if( uiPrevKeyCnt > uiPrevPrevKeyCnt) { uiBytesToMove = uiPrevKeyCnt - uiPrevPrevKeyCnt; @@ -928,6 +990,7 @@ RCODE FSPositionScan( pPrevKey = pCurElm + uiElmOvhd; uiTotalElmLen += BBE_GET_RL( pCurElm); } + if( uiRefCount >= uiRelativePosition) { pStack->uiKeyLen = uiElmKeyLen + uiPrevKeyCnt; @@ -937,23 +1000,28 @@ RCODE FSPositionScan( if( uiBlkType == BHT_LEAF) { // Copy the remaining bytes of the key. pPrevKey is current key. + if( uiElmKeyLen) { f_memcpy( &pKeyBuf[ uiPrevKeyCnt], pPrevKey, uiElmKeyLen); } + if( RC_BAD( rc = FSPositionToRef( pStack, uiRelativePosition, puiRecordId, puiDomain, pDinState))) { goto Exit; } + uiRelativePosition = 0; } + break; } uiPrevPrevKeyCnt = uiPrevKeyCnt; uiRelativePosition -= uiRefCount; pStack->uiCurElm += uiTotalElmLen; + if( pStack->uiCurElm >= pStack->uiBlkEnd) { uiRelativePosition = 0; @@ -963,7 +1031,9 @@ RCODE FSPositionScan( } *puiRelativePosInElement = uiRelativePosition; + Exit: + return( rc); } @@ -988,7 +1058,7 @@ RCODE FSPositionToRef( { uiRecordId = FSRefFirst( pStack, pDinState, puiDomain); } - else // if( uiRefCount > uiRelativePosition) + else { // Find the position within the element. @@ -998,6 +1068,7 @@ RCODE FSPositionToRef( DIN_STATE tempState; // Point to the start of the current reference skipping over domain info. + pCurRef = pCurElm = CURRENT_ELM( pStack ); *puiDomain = FSGetDomain( &pCurRef, pStack->uiElmOvhd) + 1; uiRefSize = (FLMUINT)(BBE_GET_RL(pCurElm) - @@ -1011,16 +1082,16 @@ RCODE FSPositionToRef( uiRecordId -= DINNextVal( pCurRef, pDinState); uiRelativePosition--; } + flmAssert( pDinState->uiOffset < uiRefSize); // Get the last value without moving pDinState. + tempState.uiOffset = pDinState->uiOffset; - tempState.uiOnes = pDinState->uiOnes; + tempState.uiOnes = pDinState->uiOnes; uiRecordId -= DINNextVal( pCurRef, &tempState ); } + *puiRecordId = uiRecordId; - -//Exit: return( rc); } - diff --git a/flaim/src/fscursor.cpp b/flaim/src/fscursor.cpp index 02c7972..6afddc0 100644 --- a/flaim/src/fscursor.cpp +++ b/flaim/src/fscursor.cpp @@ -41,7 +41,7 @@ FSTATIC FLMINT FSCompareKeys( (pKeyPos2)->pKey, (pKeyPos2)->uiKeyLen, (pKeyPos2)->bExclusiveKey) /**************************************************************************** -Public: Constructor +Desc: ****************************************************************************/ FSIndexCursor::FSIndexCursor() { @@ -52,7 +52,7 @@ FSIndexCursor::FSIndexCursor() } /**************************************************************************** -Public: Destructor +Desc: ****************************************************************************/ FSIndexCursor::~FSIndexCursor() { @@ -61,8 +61,7 @@ FSIndexCursor::~FSIndexCursor() } /**************************************************************************** -Public: reset -Desc: Resets any allocations, keys, state, etc. +Desc: Resets any allocations, keys, state, etc. ****************************************************************************/ void FSIndexCursor::reset( void) { @@ -83,10 +82,9 @@ void FSIndexCursor::reset( void) /**************************************************************************** -Public: resetTransaction -Desc: Resets to a new transaction that may change the read consistency of - the query. This is usually an old view error internal or external of - this class. +Desc: Resets to a new transaction that may change the read consistency of + the query. This is usually an old view error internal or external of + this class. ****************************************************************************/ RCODE FSIndexCursor::resetTransaction( FDB * pDb) @@ -100,13 +98,12 @@ RCODE FSIndexCursor::resetTransaction( { goto Exit; } + m_uiCurrTransId = pDb->LogHdr.uiCurrTransID; m_uiBlkChangeCnt = pDb->uiBlkChangeCnt; m_bIsUpdateTrans = (pDb->uiTransType == FLM_UPDATE_TRANS) ? TRUE : FALSE; - /* - Need to release all stacks that are currently in use. - */ + // Need to release all stacks that are currently in use. for( pTmpSet = m_pFirstSet; pTmpSet; pTmpSet = pTmpSet->pNext) { @@ -125,11 +122,12 @@ RCODE FSIndexCursor::resetTransaction( releaseKeyBlocks( &m_curKeyPos); Exit: + return( rc); } /**************************************************************************** -Desc: Free all of the allocated sets. +Desc: Free all of the allocated sets. ****************************************************************************/ void FSIndexCursor::freeSets( void) { @@ -139,11 +137,13 @@ void FSIndexCursor::freeSets( void) for( pCurSet = m_pFirstSet; pCurSet; pCurSet = pNextSet) { pNextSet = pCurSet->pNext; + if( pCurSet != &m_DefaultSet) { f_free( &pCurSet); } } + m_pFirstSet = m_pCurSet = NULL; if( m_pSavedPos) @@ -152,15 +152,11 @@ void FSIndexCursor::freeSets( void) f_free( &m_pSavedPos); m_pSavedPos = NULL; } - return; } - /**************************************************************************** -Public: releaseBlocks -Desc: Releases the cache blocks back to cache. +Desc: Releases the cache blocks back to cache. ****************************************************************************/ - void FSIndexCursor::releaseBlocks( void) { KEYSET * pCurSet; @@ -172,20 +168,18 @@ void FSIndexCursor::releaseBlocks( void) releaseKeyBlocks( &pCurSet->fromKey); releaseKeyBlocks( &pCurSet->untilKey); } + releaseKeyBlocks( &m_curKeyPos); - - return; } /**************************************************************************** -Public: setupKeys -Desc: Setup the from and until keys in the cursor. Return counts - after positioning to the from and until key in the index. - This code does not work with multiple key sets of FROM/UNTIL keys. +Desc: Setup the from and until keys in the cursor. Return counts + after positioning to the from and until key in the index. + This code does not work with multiple key sets of FROM/UNTIL keys. ****************************************************************************/ RCODE FSIndexCursor::setupKeys( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, QPREDICATE ** ppQPredicateList, FLMBOOL * pbDoRecMatch, // [out] Leave alone or set to TRUE. FLMBOOL * pbDoKeyMatch, // [out] Set to TRUE or FALSE @@ -193,7 +187,6 @@ RCODE FSIndexCursor::setupKeys( FLMUINT * puiTotalKeys, // [out] total number of keys FLMUINT * puiTotalRefs, // [out] total references FLMBOOL * pbTotalsEstimated) // [out] set to TRUE when estimating. - { RCODE rc = FERR_OK; FLMUINT uiUntilKeyLen; @@ -202,10 +195,12 @@ RCODE FSIndexCursor::setupKeys( RESET_DINSTATE( dinState); m_uiIndexNum = pIxd->uiIndexNum; + if( RC_BAD( rc = checkTransaction( pDb))) { goto Exit; } + m_DefaultSet.fromKey.uiRefPosition = 0; m_DefaultSet.untilKey.uiRefPosition = 0; m_DefaultSet.fromKey.bExclusiveKey = FALSE; @@ -218,13 +213,12 @@ RCODE FSIndexCursor::setupKeys( { goto Exit; } - /* - Here is a rundown of how the data is setup after this call. - Default.FROM key - block address and current element offset and - generated FROM key. - Default.UNTIL key - full stack setup and the generated UNTIL key - curKeyPos - pKey is the first key positioned the full stack is setup. - */ + + // Here is a rundown of how the data is setup after this call. + // Default.FROM key - block address and current element offset and + // generated FROM key. + // Default.UNTIL key - full stack setup and the generated UNTIL key + // curKeyPos - pKey is the first key positioned the full stack is setup. f_memcpy( m_curKeyPos.pKey, m_DefaultSet.fromKey.pKey, m_curKeyPos.uiKeyLen = m_DefaultSet.fromKey.uiKeyLen); @@ -238,26 +232,30 @@ RCODE FSIndexCursor::setupKeys( m_DefaultSet.untilKey.uiDomain = ZERO_DOMAIN; // Want any of the counts back? + if( puiLeafBlocksBetween || puiTotalKeys || puiTotalRefs) { if( RC_OK( rc = setKeyPosition( pDb, TRUE, &m_DefaultSet.fromKey, &m_curKeyPos))) { // Copy the b-tree information to the from key. + m_DefaultSet.fromKey.uiBlockAddr = m_curKeyPos.uiBlockAddr; m_DefaultSet.fromKey.uiDomain = m_curKeyPos.uiDomain; m_DefaultSet.fromKey.uiBlockTransId = m_curKeyPos.uiBlockTransId; m_DefaultSet.fromKey.uiCurElm = m_curKeyPos.uiCurElm; // All keys bewteen FROM and UNTIL may be gone. + if( FS_COMPARE_KEYS( FALSE, &m_curKeyPos, TRUE, &m_DefaultSet.untilKey) <= 0) { - rc = setKeyPosition( pDb, TRUE /* Going Forward so position is exclusive */, - &m_DefaultSet.untilKey, &m_DefaultSet.untilKey); + rc = setKeyPosition( pDb, TRUE, + &m_DefaultSet.untilKey, &m_DefaultSet.untilKey); rc = (rc == FERR_EOF_HIT) ? FERR_OK: rc; // Restore the original UNTIL key - throws away what the last key is. + f_memcpy( m_DefaultSet.untilKey.pKey, pUntilKey, m_DefaultSet.untilKey.uiKeyLen = uiUntilKeyLen); } @@ -278,6 +276,7 @@ RCODE FSIndexCursor::setupKeys( if( RC_BAD( rc)) { // Empty tree or empty set case. + if( rc == FERR_EOF_HIT || rc == FERR_BOF_HIT) { if( puiLeafBlocksBetween) @@ -332,7 +331,7 @@ Desc: Setup a cursor with just a single FROM/UNTIL key. RCODE FSIndexCursor::setupKeys( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, FLMBYTE * pFromKey, FLMUINT uiFromKeyLen, FLMUINT uiFromRecordId, @@ -351,6 +350,7 @@ RCODE FSIndexCursor::setupKeys( m_DefaultSet.pNext = m_DefaultSet.pPrev = NULL; // FROM key + m_DefaultSet.fromKey.uiRecordId = uiFromRecordId; m_DefaultSet.fromKey.uiDomain = uiFromRecordId ? DRN_DOMAIN( uiFromRecordId) + 1: MAX_DOMAIN; @@ -360,6 +360,7 @@ RCODE FSIndexCursor::setupKeys( m_DefaultSet.fromKey.bExclusiveKey = FALSE; // UNTIL key + m_DefaultSet.untilKey.uiRecordId = uiUntilRecordId; m_DefaultSet.untilKey.uiDomain = uiUntilRecordId ? DRN_DOMAIN( uiUntilRecordId) + 1: ZERO_DOMAIN; @@ -374,6 +375,7 @@ RCODE FSIndexCursor::setupKeys( // If this is a positioning index we need to setup the FROM/UNTIL // btrees to get the FROM/UNTIL reference positions. + if( pIxd->uiFlags & IXD_POSITIONING) { if( RC_BAD( rc = setupForPositioning( pDb))) @@ -418,7 +420,9 @@ RCODE FSIndexCursor::setupForPositioning( { goto Exit; } + // Copy the key back. + f_memcpy( pSrcSet->untilKey.pKey, pTempKey, pSrcSet->untilKey.uiKeyLen = uiTempKeyLen); @@ -440,11 +444,14 @@ RCODE FSIndexCursor::setupForPositioning( goto Exit; } m_pCurSet = m_pFirstSet; + // Copy the b-tree information to the from key. + m_pCurSet->fromKey.uiBlockAddr = m_curKeyPos.uiBlockAddr; m_pCurSet->fromKey.uiDomain = m_curKeyPos.uiDomain; m_pCurSet->fromKey.uiBlockTransId = m_curKeyPos.uiBlockTransId; m_pCurSet->fromKey.uiCurElm = m_curKeyPos.uiCurElm; + if( m_pIxd->uiFlags & IXD_POSITIONING) { if( RC_BAD( rc = FSGetBtreeRefPosition( pDb, @@ -465,9 +472,12 @@ RCODE FSIndexCursor::setupForPositioning( { goto Exit; } + // Copy the key back. + f_memcpy( pSrcSet->fromKey.pKey, pTempKey, pSrcSet->fromKey.uiKeyLen = uiTempKeyLen); + if( m_pIxd->uiFlags & IXD_POSITIONING) { if( RC_BAD( rc = FSGetBtreeRefPosition( pDb, @@ -479,13 +489,14 @@ RCODE FSIndexCursor::setupForPositioning( } } } + Exit: + return( rc); } /**************************************************************************** -Public: unionKeys -Desc: Merge the input cursors fromUntil sets as a result of a UNION. +Desc: Merge the input cursors fromUntil sets as a result of a UNION. ****************************************************************************/ RCODE FSIndexCursor::unionKeys( FSIndexCursor * pFSCursor) @@ -498,6 +509,7 @@ RCODE FSIndexCursor::unionKeys( KEYSET * pPrevDestSet; // We need to release all of the blocks. Too complex + pFSCursor->releaseBlocks(); releaseBlocks(); pInputSet = pFSCursor->getFromUntilSets(); @@ -512,7 +524,8 @@ RCODE FSIndexCursor::unionKeys( if( RC_BAD( rc = f_calloc( sizeof( KEYSET), &pCurDestSet))) { goto Exit; - } + } + if( !pSrcSet) { f_memcpy( pCurDestSet, pInputSet, sizeof( KEYSET)); @@ -551,8 +564,8 @@ RCODE FSIndexCursor::unionKeys( if( bUntilKeyGreaterThan) { - if( ((pSrcSet = pSrcSet->pNext) == NULL) - || !FSCompareKeyPos( pInputSet, pSrcSet, + if( ((pSrcSet = pSrcSet->pNext) == NULL) || + !FSCompareKeyPos( pInputSet, pSrcSet, &bFromKeyLessThan, &bUntilKeyGreaterThan)) { f_memcpy( &pCurDestSet->untilKey, &pInputSet->untilKey, @@ -563,8 +576,8 @@ RCODE FSIndexCursor::unionKeys( } else { - if( ((pInputSet = pInputSet->pNext) == NULL) - || !FSCompareKeyPos( pInputSet, pSrcSet, + if( ((pInputSet = pInputSet->pNext) == NULL) || + !FSCompareKeyPos( pInputSet, pSrcSet, &bFromKeyLessThan, &bUntilKeyGreaterThan)) { f_memcpy( &pCurDestSet->untilKey, @@ -577,6 +590,7 @@ RCODE FSIndexCursor::unionKeys( } // Link in. + pCurDestSet->pNext = NULL; if( !pDestSet) { @@ -589,6 +603,7 @@ RCODE FSIndexCursor::unionKeys( pCurDestSet->pPrev = pPrevDestSet; } } + // We went to the trouble of having a default set allocated with this class. // Undo the last allocation. if( pDestSet) then pCurDestSet can be used. @@ -607,16 +622,17 @@ RCODE FSIndexCursor::unionKeys( } f_free( &pCurDestSet); } + m_bAtBOF = TRUE; m_pCurSet = NULL; Exit: + return( rc); } /**************************************************************************** -Public: intersectKeys -Desc: Intersect the from/until key sets of pFSCursor into 'this'. +Desc: Intersect the from/until key sets of pFSCursor into 'this'. ****************************************************************************/ RCODE FSIndexCursor::intersectKeys( FDB * pDb, @@ -645,6 +661,7 @@ RCODE FSIndexCursor::intersectKeys( &bFromKeyLessThan, &bUntilKeyGreaterThan)) { // Keys do NOT overlap - go to the next set section. + if( bFromKeyLessThan) { pInputSet = pInputSet->pNext; @@ -662,8 +679,10 @@ RCODE FSIndexCursor::intersectKeys( if( RC_BAD( rc = f_calloc( sizeof( KEYSET), &pCurDestSet))) { goto Exit; - } + } + pCurDestSet->pNext = NULL; + if( !pDestSet) { pDestSet = pCurDestSet; @@ -676,11 +695,13 @@ RCODE FSIndexCursor::intersectKeys( } // Take the highest FROM key. + f_memcpy( &pCurDestSet->fromKey, bFromKeyLessThan ? &pSrcSet->fromKey : &pInputSet->fromKey, sizeof( KEYPOS)); // Take the lowest until key and position to the next set. + if( bUntilKeyGreaterThan) { f_memcpy( &pCurDestSet->untilKey, &pSrcSet->untilKey, sizeof( KEYPOS)); @@ -696,7 +717,9 @@ RCODE FSIndexCursor::intersectKeys( // We went to the trouble of having a default set allocated with this class. // Undo the last allocation. if( pDestSet) then pCurDestSet can be used. + freeSets(); + if( pDestSet) { f_memcpy( &m_DefaultSet, pCurDestSet, sizeof( KEYSET)); @@ -709,13 +732,16 @@ RCODE FSIndexCursor::intersectKeys( { m_pFirstSet = &m_DefaultSet; } + f_free( &pCurDestSet); } + m_bAtBOF = TRUE; m_pCurSet = NULL; // If this is a positioning index we need to setup the FROM/UNTIL // btrees to get the FROM/UNTIL reference positions. + if( m_pIxd->uiFlags & IXD_POSITIONING) { if( RC_BAD( rc = setupForPositioning( pDb))) @@ -725,14 +751,13 @@ RCODE FSIndexCursor::intersectKeys( } Exit: + return( rc); } - /**************************************************************************** -Public: compareKeyRange -Desc: Specific compare for a key range against the - key ranges in this cursor. +Desc: Specific compare for a key range against the key ranges in this + cursor. ****************************************************************************/ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. @@ -746,7 +771,7 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. FLMBOOL * pbUntilGreaterThan) // F T F { FLMBOOL bKeysOverlap = FALSE; - KEYSET * pSrcSet; // Current source set + KEYSET * pSrcSet; // Current source set FLMINT iFromCmp; FLMINT iUntilCmp; FLMINT iFromUntilCmp; @@ -764,6 +789,7 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. if( iFromCmp < 0) { // Move from left-most to right-most to see where the overlap is. + iUntilFromCmp = FSCompareKeys( TRUE, pUntilKey, uiUntilKeyLen, bExclusiveUntil, @@ -771,12 +797,14 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. pSrcSet->fromKey.pKey, pSrcSet->fromKey.uiKeyLen, pSrcSet->fromKey.bExclusiveKey); + if( iUntilFromCmp < 0) { *pbUntilKeyInSet = FALSE; *pbUntilGreaterThan = FALSE; goto Exit; } + if( iUntilFromCmp == 0) { bKeysOverlap = TRUE; @@ -784,12 +812,15 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. *pbUntilGreaterThan = FALSE; goto Exit; } + // UNTIL > pSrcSet->fromKey + iUntilCmp = FSCompareKeys( TRUE, pUntilKey, uiUntilKeyLen, bExclusiveUntil, TRUE, pSrcSet->untilKey.pKey, pSrcSet->untilKey.uiKeyLen, pSrcSet->untilKey.bExclusiveKey); + if( iUntilCmp <= 0) { bKeysOverlap = TRUE; @@ -797,12 +828,15 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. *pbUntilGreaterThan = FALSE; goto Exit; } + bKeysOverlap = TRUE; + // Try the next source set to see if the UNTIL key is in a set. } else { // Move from left-most to right-most to see where the overlap is. + if( iFromCmp == 0) { bKeysOverlap = TRUE; @@ -814,6 +848,7 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. TRUE, pSrcSet->untilKey.pKey, pSrcSet->untilKey.uiKeyLen, pSrcSet->untilKey.bExclusiveKey); + if( iFromUntilCmp <= 0) { bKeysOverlap = TRUE; @@ -823,11 +858,13 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. continue; } } + iUntilCmp = FSCompareKeys( TRUE, pUntilKey, uiUntilKeyLen, bExclusiveFrom, TRUE, pSrcSet->untilKey.pKey, pSrcSet->untilKey.uiKeyLen, pSrcSet->untilKey.bExclusiveKey); + if( iUntilCmp <= 0) { bKeysOverlap = TRUE; @@ -837,20 +874,23 @@ FLMBOOL FSIndexCursor::compareKeyRange( // Returns TRUE if keys overlap. } } } + *pbUntilKeyInSet = FALSE; *pbUntilGreaterThan = TRUE; + Exit: + return bKeysOverlap; } /**************************************************************************** -Desc: Compare two From/Until key positions. +Desc: Compare two From/Until key positions. ****************************************************************************/ FLMBOOL FSIndexCursor::FSCompareKeyPos( // TRUE if keys overlap KEYSET * pSet1, KEYSET * pSet2, - FLMBOOL * pbFromKeyLessThan, // pSet1->from < pSet2->from - FLMBOOL * pbUntilKeyGreaterThan) // pSet1->until > pSet2->until + FLMBOOL * pbFromKeyLessThan, // pSet1->from < pSet2->from + FLMBOOL * pbUntilKeyGreaterThan) // pSet1->until > pSet2->until { if( FS_COMPARE_KEYS( TRUE, &pSet1->untilKey, FALSE, &pSet2->fromKey) < 0) @@ -859,6 +899,7 @@ FLMBOOL FSIndexCursor::FSCompareKeyPos( // TRUE if keys overlap pbUntilKeyGreaterThan = FALSE; return FALSE; } + if( FS_COMPARE_KEYS( FALSE, &pSet1->fromKey, TRUE, &pSet2->untilKey) > 0) { *pbFromKeyLessThan = FALSE; @@ -874,15 +915,14 @@ FLMBOOL FSIndexCursor::FSCompareKeyPos( // TRUE if keys overlap *pbUntilKeyGreaterThan = (FLMBOOL) ((FS_COMPARE_KEYS( TRUE, &pSet1->untilKey, TRUE, &pSet2->untilKey) > 0) ? TRUE : FALSE); - return TRUE; + return (TRUE); } /**************************************************************************** Desc: Set information from the block into the KEYPOS structure. ****************************************************************************/ FINLINE void setKeyItemsFromBlock( - KEYPOS * pKeyPos - ) + KEYPOS * pKeyPos) { pKeyPos->uiBlockAddr = pKeyPos->pStack->uiBlkAddr; pKeyPos->uiCurElm = pKeyPos->pStack->uiCurElm; @@ -893,9 +933,8 @@ FINLINE void setKeyItemsFromBlock( } /**************************************************************************** -Protected: setKeyPosition -Desc: Set the key position given some KEYPOS structure. - Please note that the blocks in the stack may or may not be used. +Desc: Set the key position given some KEYPOS structure. + Please note that the blocks in the stack may or may not be used. ****************************************************************************/ RCODE FSIndexCursor::setKeyPosition( FDB * pDb, @@ -910,6 +949,7 @@ RCODE FSIndexCursor::setKeyPosition( FLMUINT uiTargetRecordId = pInKeyPos->uiRecordId; // May have to unuse the b-tree blocks. Then setup the stack. + if( !pOutKeyPos->bStackInUse) { FSInitStackCache( pOutKeyPos->Stack, BH_MAX_LEVELS); @@ -925,11 +965,14 @@ RCODE FSIndexCursor::setKeyPosition( { pSearchKey = pInKeyPos->pKey; } + // Setup the stack. + pOutKeyPos->pStack = pOutKeyPos->Stack; pOutKeyPos->Stack[0].pKeyBuf = pOutKeyPos->pKey; // All of the variables should be setup for the search. + if( RC_BAD( rc = FSBtSearch( pDb, m_pLFile, &pOutKeyPos->pStack, pSearchKey, pInKeyPos->uiKeyLen, uiTargetRecordId @@ -938,6 +981,7 @@ RCODE FSIndexCursor::setKeyPosition( { goto Exit; } + pOutKeyPos->uiBlockAddr = pOutKeyPos->pStack->uiBlkAddr; pOutKeyPos->uiCurElm = pOutKeyPos->pStack->uiCurElm; @@ -947,6 +991,7 @@ RCODE FSIndexCursor::setKeyPosition( rc = RC_SET( FERR_EOF_HIT); goto Exit; } + pOutKeyPos->uiKeyLen = pOutKeyPos->pStack->uiKeyLen; if( bGoingForward) @@ -962,8 +1007,9 @@ RCODE FSIndexCursor::setKeyPosition( BTSK * pStack; // Going backwards or to the last. May have positioned too far. - if( pOutKeyPos->pStack->uiCmpStatus == BT_END_OF_DATA - || FS_COMPARE_KEYS( TRUE, pOutKeyPos, TRUE, pInKeyPos) > 0) + + if( pOutKeyPos->pStack->uiCmpStatus == BT_END_OF_DATA || + FS_COMPARE_KEYS( TRUE, pOutKeyPos, TRUE, pInKeyPos) > 0) { uiTargetRecordId = 0; pStack = pOutKeyPos->pStack; @@ -980,33 +1026,41 @@ RCODE FSIndexCursor::setKeyPosition( { rc = RC_SET( FERR_BTREE_ERROR); } + goto Exit; } } } + // Position to the last continuation element of the previous element. + if( RC_BAD( rc = FSBtPrevElm( pDb, m_pLFile, pStack))) { if( rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } } } + // When using the positioning index, we must always have a complete stack. + if( !(m_pIxd->uiFlags & IXD_POSITIONING)) { pOutKeyPos->pStack->uiFlags = NO_STACK; } // Get the record ID at the leaf level of the b-tree. + if( uiTargetRecordId) { pOutKeyPos->uiRecordId = pInKeyPos->uiRecordId; rc = FSRefSearch( pOutKeyPos->pStack, &pOutKeyPos->DinState, &pOutKeyPos->uiRecordId); + if( rc == FERR_FAILURE) { rc = FERR_OK; @@ -1030,6 +1084,7 @@ RCODE FSIndexCursor::setKeyPosition( Exit: // Save state only on a good return value. + if( RC_OK( rc) || ((rc == FERR_EOF_HIT || rc == FERR_BOF_HIT) && pOutKeyPos->bStackInUse)) { @@ -1039,17 +1094,15 @@ Exit: { releaseKeyBlocks( pOutKeyPos); } + return( rc); } - /**************************************************************************** -Public: currentKey Desc: Return the current record and record id. VISIT: We may want to return BOF/EOF when positioned on an endpoint. ****************************************************************************/ - -RCODE FSIndexCursor::currentKey( // FERR_OK, FERR_NOT_FOUND, BOF/EOF_HIT, error +RCODE FSIndexCursor::currentKey( FDB * pDb, FlmRecord ** ppRecordKey, // Will replace what is there FLMUINT * puiRecordId) // Set the record ID @@ -1062,11 +1115,13 @@ RCODE FSIndexCursor::currentKey( // FERR_OK, FERR_NOT_FOUND, BOF/EOF_HIT, erro { goto Exit; } + if( m_bAtBOF) { rc = RC_SET( FERR_BOF_HIT); goto Exit; } + if( m_bAtEOF) { rc = RC_SET( FERR_EOF_HIT); @@ -1084,6 +1139,7 @@ RCODE FSIndexCursor::currentKey( // FERR_OK, FERR_NOT_FOUND, BOF/EOF_HIT, erro } // If this assert happens we have to code for it. + flmAssert( m_curKeyPos.uiRecordId != 0); if( ppRecordKey) @@ -1093,18 +1149,20 @@ RCODE FSIndexCursor::currentKey( // FERR_OK, FERR_NOT_FOUND, BOF/EOF_HIT, erro { goto Exit; } + (*ppRecordKey)->setID( m_curKeyPos.uiRecordId); } + if( puiRecordId) { *puiRecordId = m_curKeyPos.uiRecordId; } Exit: + return( rc); } - /**************************************************************************** Desc: Return the current record and record id. VISIT: We may want to return BOF/EOF when positioned on an endpoint. @@ -1112,7 +1170,7 @@ VISIT: We may want to return BOF/EOF when positioned on an endpoint. RCODE FSIndexCursor::currentKeyBuf( FDB * pDb, POOL * pPool, - FLMBYTE * * ppKeyBuf, + FLMBYTE ** ppKeyBuf, FLMUINT * puiKeyLen, FLMUINT * puiRecordId, FLMUINT * puiContainerId) @@ -1125,11 +1183,13 @@ RCODE FSIndexCursor::currentKeyBuf( { goto Exit; } + if( m_bAtBOF) { rc = RC_SET( FERR_BOF_HIT); goto Exit; } + if( m_bAtEOF) { rc = RC_SET( FERR_EOF_HIT); @@ -1147,6 +1207,7 @@ RCODE FSIndexCursor::currentKeyBuf( } // If this assert happens we have to code for it. + flmAssert( m_curKeyPos.uiRecordId != 0); if( ppKeyBuf) @@ -1164,6 +1225,7 @@ RCODE FSIndexCursor::currentKeyBuf( rc = RC_SET( FERR_MEM); goto Exit; } + f_memcpy( *ppKeyBuf, m_curKeyPos.pKey, m_curKeyPos.uiKeyLen); } else @@ -1171,10 +1233,12 @@ RCODE FSIndexCursor::currentKeyBuf( *ppKeyBuf = NULL; } } + if( puiRecordId) { *puiRecordId = m_curKeyPos.uiRecordId; } + if (puiContainerId) { if ((*puiContainerId = m_pIxd->uiContainerNum) == 0) @@ -1186,17 +1250,16 @@ RCODE FSIndexCursor::currentKeyBuf( } Exit: + return( rc); } - /**************************************************************************** -Public: firstKey Desc: Position to and return the first record. This is hard because positioning using the first key may actually position past or into another FROM/UNTIL set in the list. ****************************************************************************/ -RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error +RCODE FSIndexCursor::firstKey( FDB * pDb, FlmRecord ** ppRecordKey, // Will replace what is there FLMUINT * puiRecordId) // Set the record ID @@ -1207,6 +1270,7 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { goto Exit; } + if( !m_pFirstSet) { m_bAtBOF = FALSE; @@ -1215,9 +1279,9 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error goto Exit; } - // Complex Optimization: // If at BOF and stack is in use, the key is the first key! // This should only happen when firstKey is called the first time. + if( m_bAtBOF && m_curKeyPos.bStackInUse && m_pCurSet) { m_bAtBOF = FALSE; @@ -1226,6 +1290,7 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { m_pCurSet = m_pFirstSet; m_bAtBOF = m_bAtEOF = FALSE; + if( RC_BAD( rc = setKeyPosition( pDb, TRUE, &m_pCurSet->fromKey, &m_curKeyPos))) { @@ -1233,26 +1298,32 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { m_bAtEOF = TRUE; } + goto Exit; } } // Check to see if the key is within one of the FROM/UNTIL sets. + for(;;) { // Check to see if the current key <= UNTIL key. - if( FS_COMPARE_KEYS( FALSE, &m_curKeyPos, TRUE, &m_pCurSet->untilKey) <= 0) + if( FS_COMPARE_KEYS( FALSE, &m_curKeyPos, TRUE, + &m_pCurSet->untilKey) <= 0) { break; } - // Nope - UntilKey < current key. + + // Nope - UntilKey < current key. + if( !m_pCurSet->pNext) { rc = RC_SET( FERR_EOF_HIT); m_bAtEOF = TRUE; goto Exit; } + m_pCurSet = m_pCurSet->pNext; // If (current key < FROM key of the next set) we need to reposition. @@ -1266,6 +1337,7 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { m_bAtEOF = TRUE; } + goto Exit; } } @@ -1275,6 +1347,7 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { *puiRecordId = m_curKeyPos.uiRecordId; } + if( ppRecordKey) { if( RC_BAD( rc = flmIxKeyOutput( m_pIxd, m_curKeyPos.pKey, @@ -1282,23 +1355,26 @@ RCODE FSIndexCursor::firstKey( // FERR_OK, FERR_BOF_HIT or error { goto Exit; } + (*ppRecordKey)->setID( m_curKeyPos.uiRecordId); } Exit: + if( m_bAtEOF) { // The saved state is not pointing anywhere specific in the B-tree. + releaseKeyBlocks( &m_curKeyPos); } + return( rc); } /**************************************************************************** -Public: nextKey Desc: Position to the next key and the first reference of that key. ****************************************************************************/ -RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error +RCODE FSIndexCursor::nextKey( FDB * pDb, FlmRecord ** ppRecordKey, FLMUINT * puiRecordId) @@ -1312,11 +1388,13 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error { goto Exit; } + if( m_bAtEOF) { rc = RC_SET( FERR_EOF_HIT); goto Exit; } + if( m_bAtBOF) { rc = firstKey( pDb, ppRecordKey, puiRecordId); @@ -1336,7 +1414,9 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error { m_bAtEOF = TRUE; } + // May return FERR_EOF_HIT if all remaining keys are deleted. + goto Exit; } } @@ -1354,16 +1434,20 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error { if( RC_BAD( rc = FSBtNextElm( pDb, m_pLFile, pStack))) { - // b-tree corrupt if FERR_BT_END_OF_DATA . + // b-tree corrupt if FERR_BT_END_OF_DATA + if( rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_BTREE_ERROR); } + goto Exit; } pCurElm = CURRENT_ELM( pStack); } + // Now go to the next element. + if( RC_BAD( rc = FSBtNextElm( pDb, m_pLFile, pStack))) { if( rc == FERR_BT_END_OF_DATA) @@ -1371,14 +1455,17 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error m_bAtEOF = TRUE; rc = RC_SET( FERR_EOF_HIT); } + goto Exit; } + bKeyGone = TRUE; m_curKeyPos.uiKeyLen = m_curKeyPos.pStack->uiKeyLen; } // Could have positioned after the current sets until key before // the FROM key of the next set. + iCmp = FS_COMPARE_KEYS( FALSE, &m_curKeyPos, TRUE, &m_pCurSet->untilKey); if( iCmp <= 0) { @@ -1387,20 +1474,26 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error FSRefFirst( pStack, &m_curKeyPos.DinState, &m_curKeyPos.uiDomain); break; } + // Go to the next set if there is one. + if( !m_pCurSet->pNext) { m_bAtEOF = TRUE; rc = RC_SET( FERR_EOF_HIT); goto Exit; } + m_pCurSet = m_pCurSet->pNext; + // The key may fit in the next set. + iCmp = FS_COMPARE_KEYS( FALSE, &m_curKeyPos, FALSE, &m_pCurSet->fromKey); if( iCmp < 0) { // Reposition using the from key. - if( RC_BAD( rc = setKeyPosition( pDb, TRUE, &m_pCurSet->fromKey, &m_curKeyPos))) + if( RC_BAD( rc = setKeyPosition( pDb, TRUE, + &m_pCurSet->fromKey, &m_curKeyPos))) { if( rc == FERR_EOF_HIT) { @@ -1415,6 +1508,7 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error { *puiRecordId = m_curKeyPos.uiRecordId; } + if( ppRecordKey) { if( RC_BAD( rc = flmIxKeyOutput( m_pIxd, m_curKeyPos.pKey, @@ -1422,20 +1516,23 @@ RCODE FSIndexCursor::nextKey( // FERR_OK, FERR_EOF_HIT or error { goto Exit; } + (*ppRecordKey)->setID( m_curKeyPos.uiRecordId); } Exit: + if( m_bAtEOF) { // The saved state is not pointing anywhere specific in the B-tree. + releaseKeyBlocks( &m_curKeyPos); } + return( rc); } /**************************************************************************** -Public: nextRef Desc: Position to the next referece of the current key. ****************************************************************************/ RCODE FSIndexCursor::nextRef( // FERR_OK, FERR_EOF_HIT or error @@ -1450,12 +1547,14 @@ RCODE FSIndexCursor::nextRef( // FERR_OK, FERR_EOF_HIT or error { goto Exit; } + flmAssert( m_pCurSet != NULL); bKeyGone = bRefGone = FALSE; if( !m_curKeyPos.bStackInUse) { // Take care of any re-read of a block if we changed transactions. + if( RC_BAD( rc = reposition( pDb, FALSE, FALSE, &bKeyGone, TRUE, FALSE, &bRefGone))) { @@ -1475,6 +1574,7 @@ RCODE FSIndexCursor::nextRef( // FERR_OK, FERR_EOF_HIT or error { rc = RC_SET( FERR_EOF_HIT); } + goto Exit; } else @@ -1482,22 +1582,23 @@ RCODE FSIndexCursor::nextRef( // FERR_OK, FERR_EOF_HIT or error setKeyItemsFromBlock( &m_curKeyPos); } } + if( puiRecordId) { *puiRecordId = m_curKeyPos.uiRecordId; } Exit: + return( rc); } /**************************************************************************** -Public: lastKey -Desc: Position to and return the last record. - This is hard because positioning using the first key may actually - position past or into another FROM/UNTIL set in the list. +Desc: Position to and return the last record. + This is hard because positioning using the first key may actually + position past or into another FROM/UNTIL set in the list. ****************************************************************************/ -RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error +RCODE FSIndexCursor::lastKey( FDB * pDb, FlmRecord ** ppRecordKey, // Will replace what is there FLMUINT * puiRecordId) // Set the record ID @@ -1508,6 +1609,7 @@ RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error { goto Exit; } + m_pCurSet = m_pFirstSet; if( !m_pCurSet) { @@ -1518,10 +1620,12 @@ RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error } // Position to the last set. + while( m_pCurSet->pNext) { m_pCurSet = m_pCurSet->pNext; } + m_bAtBOF = m_bAtEOF = FALSE; for(;;) @@ -1530,39 +1634,49 @@ RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error &m_curKeyPos))) { // Returns an error or FERR_EOF_HIT. + if( rc != FERR_EOF_HIT) + { goto Exit; + } // Position to the previous key if possible. + if( m_curKeyPos.pStack->uiBlkAddr == BT_END) { m_bAtBOF = TRUE; rc = RC_SET( FERR_BOF_HIT); goto Exit; } + // Went past the until key. Go back one. + if( RC_BAD( rc = FSBtPrevElm( pDb, m_pLFile, m_curKeyPos.pStack))) { if( rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } } // We may have positioned before the FROM key of this set. - if( FS_COMPARE_KEYS( FALSE, &m_pCurSet->fromKey, FALSE, &m_curKeyPos) <= 0) + if( FS_COMPARE_KEYS( FALSE, &m_pCurSet->fromKey, + FALSE, &m_curKeyPos) <= 0) { break; } + if( !m_pCurSet->pPrev) { rc = RC_SET( FERR_BOF_HIT); m_bAtBOF = TRUE; goto Exit; } + m_pCurSet = m_pCurSet->pPrev; } @@ -1576,6 +1690,7 @@ RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error { *puiRecordId = m_curKeyPos.uiRecordId; } + if( ppRecordKey) { if( RC_BAD( rc = flmIxKeyOutput( m_pIxd, m_curKeyPos.pKey, @@ -1583,24 +1698,25 @@ RCODE FSIndexCursor::lastKey( // FERR_OK, FERR_EOF_HIT or error { goto Exit; } + (*ppRecordKey)->setID( m_curKeyPos.uiRecordId); } Exit: + if( rc == FERR_BOF_HIT) { // The saved state is not pointing anywhere specific in the B-tree. releaseKeyBlocks( &m_curKeyPos); } + return( rc); } - /**************************************************************************** -Public: prevKey -Desc: Position to the PREVIOUS key and the LAST reference of that key. +Desc: Position to the PREVIOUS key and the LAST reference of that key. ****************************************************************************/ -RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error +RCODE FSIndexCursor::prevKey( FDB * pDb, FlmRecord ** ppRecordKey, FLMUINT * puiRecordId) @@ -1614,11 +1730,13 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error { goto Exit; } + if( m_bAtBOF) { rc = RC_SET( FERR_BOF_HIT); goto Exit; } + if( !m_pCurSet || m_bAtEOF) { rc = lastKey( pDb, ppRecordKey, puiRecordId); @@ -1635,14 +1753,17 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error FALSE, FALSE, &bRefGone))) { // May return FERR_EOF_HIT if all remaining keys are deleted. + if( rc != FERR_BOF_HIT && rc != FERR_EOF_HIT) { goto Exit; } + m_bAtBOF = TRUE; rc = RC_SET( FERR_BOF_HIT); } } + for(;;) { if( !bKeyGone) @@ -1654,13 +1775,16 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error { if( RC_BAD( rc = FSBtPrevElm( pDb, m_pLFile, pStack))) { - // b-tree corrupt if FERR_BT_END_OF_DATA . + // b-tree corrupt if FERR_BT_END_OF_DATA + if( rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_BTREE_ERROR); } + goto Exit; } + pCurElm = CURRENT_ELM( pStack); } @@ -1668,19 +1792,24 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error if( RC_BAD(rc = FSBtPrevElm( pDb, m_pLFile, pStack))) { - // b-tree corrupt if FERR_BT_END_OF_DATA . + // b-tree corrupt if FERR_BT_END_OF_DATA + if( rc == FERR_BT_END_OF_DATA) { m_bAtBOF = TRUE; rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } + bKeyGone = TRUE; m_curKeyPos.uiKeyLen = m_curKeyPos.pStack->uiKeyLen; } + // Could have positioned after the current sets until key before // the FROM key of the next set. + if( FS_COMPARE_KEYS( FALSE, &m_curKeyPos, TRUE, &m_pCurSet->fromKey) >= 0) { setKeyItemsFromBlock( &m_curKeyPos); @@ -1688,19 +1817,24 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error FSRefLast( pStack, &m_curKeyPos.DinState, &m_curKeyPos.uiDomain); break; } + // Go to the previous set if there is one. + if( !m_pCurSet->pPrev) { m_bAtBOF = TRUE; rc = RC_SET( FERR_BOF_HIT); goto Exit; } + m_pCurSet = m_pCurSet->pPrev; // The key may fit in the previous set. + if( FS_COMPARE_KEYS( FALSE, &m_curKeyPos, FALSE, &m_pCurSet->fromKey) > 0) { // Reposition using the from key. + if( RC_BAD( rc = setKeyPosition( pDb, FALSE, &m_pCurSet->untilKey, &m_curKeyPos))) { @@ -1709,6 +1843,7 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error m_bAtBOF = TRUE; rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } } @@ -1718,6 +1853,7 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error { *puiRecordId = m_curKeyPos.uiRecordId; } + if( ppRecordKey) { if( RC_BAD( rc = flmIxKeyOutput( m_pIxd, m_curKeyPos.pKey, @@ -1725,23 +1861,25 @@ RCODE FSIndexCursor::prevKey( // FERR_OK, FERR_BOF_HIT or error { goto Exit; } + (*ppRecordKey)->setID( m_curKeyPos.uiRecordId); } Exit: + if( rc == FERR_BOF_HIT) { // The saved state is not pointing anywhere specific in the B-tree. releaseKeyBlocks( &m_curKeyPos); } + return( rc); } /**************************************************************************** -Public: prevRef -Desc: Position to the previous referece of the current key. +Desc: Position to the previous referece of the current key. ****************************************************************************/ -RCODE FSIndexCursor::prevRef( // FERR_OK, FERR_BOF_HIT or error +RCODE FSIndexCursor::prevRef( FDB * pDb, FLMUINT * puiRecordId) // Set the record ID { @@ -1759,19 +1897,23 @@ RCODE FSIndexCursor::prevRef( // FERR_OK, FERR_BOF_HIT or error if( !m_curKeyPos.bStackInUse) { // Take care of any re-read of a block if we changed transactions. + if( RC_BAD( rc = reposition( pDb, FALSE, FALSE, &bKeyGone, FALSE, TRUE, &bRefGone))) { // May return FERR_EOF_HIT if all preceeding references are deleted. + if( rc == FERR_EOF_HIT) { rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } flmAssert( !bKeyGone); } + if( !bRefGone) { if( RC_BAD( rc = FSRefPrev( pDb, m_pLFile, m_curKeyPos.pStack, @@ -1781,6 +1923,7 @@ RCODE FSIndexCursor::prevRef( // FERR_OK, FERR_BOF_HIT or error { rc = RC_SET( FERR_BOF_HIT); } + goto Exit; } else @@ -1788,22 +1931,22 @@ RCODE FSIndexCursor::prevRef( // FERR_OK, FERR_BOF_HIT or error setKeyItemsFromBlock( &m_curKeyPos); } } + if( puiRecordId) { *puiRecordId = m_curKeyPos.uiRecordId; } Exit: + return( rc); } - /**************************************************************************** -Public: reposition -Desc: Reposition to the current key + recordId. If the current key - is gone we may reposition past the UNTIL key and should check. +Desc: Reposition to the current key + recordId. If the current key + is gone we may reposition past the UNTIL key and should check. ****************************************************************************/ -RCODE FSIndexCursor::reposition( // FERR_OK, FERR_EOF/BOF_HIT, FERR_NOT_FOUND +RCODE FSIndexCursor::reposition( FDB * pDb, FLMBOOL bCanPosToNextKey, // May be TRUE if bPosToPrevKey is FALSE FLMBOOL bCanPosToPrevKey, // May be TRUE if bPosToNextKey is FALSE @@ -1818,12 +1961,14 @@ RCODE FSIndexCursor::reposition( // FERR_OK, FERR_EOF/BOF_HIT, FERR_NOT_FOUND FLMUINT uiTargetRecordId; uiTargetRecordId = m_curKeyPos.uiRecordId; + // May have to unuse the b-tree blocks. Then setup the stack again. flmAssert( !m_curKeyPos.bStackInUse); *pbKeyGone = *pbRefGone = FALSE; // Re-read the block and see if it is the same block. + if( m_curKeyPos.uiBlockAddr == BT_END) { bReread = TRUE; @@ -1837,6 +1982,7 @@ RCODE FSIndexCursor::reposition( // FERR_OK, FERR_EOF/BOF_HIT, FERR_NOT_FOUND { goto Exit; } + rc = FERR_OK; bReread = TRUE; } @@ -1936,6 +2082,7 @@ RCODE FSIndexCursor::reposition( // FERR_OK, FERR_EOF/BOF_HIT, FERR_NOT_FOUND else if( !bCanPosToNextRef) { // We have an error positioning. Return NOT_FOUND + rc = RC_SET( FERR_NOT_FOUND); } } @@ -1946,7 +2093,7 @@ Exit: } /**************************************************************************** -Desc: Save the current key position. +Desc: Save the current key position. ****************************************************************************/ void FSIndexCursor::saveCurrKeyPos( KEYPOS * pSaveKeyPos) @@ -1958,7 +2105,7 @@ void FSIndexCursor::saveCurrKeyPos( } /**************************************************************************** -Desc: Restore the current key position. +Desc: Restore the current key position. ****************************************************************************/ void FSIndexCursor::restoreCurrKeyPos( KEYPOS * pSaveKeyPos) @@ -1977,8 +2124,8 @@ RCODE FSIndexCursor::getKeySet( FLMUINT uiKeyLen, KEYSET ** ppKeySet) { - RCODE rc = FERR_OK; - KEYSET * pKeySet; + RCODE rc = FERR_OK; + KEYSET * pKeySet; pKeySet = m_pFirstSet; while (pKeySet) @@ -2010,23 +2157,25 @@ RCODE FSIndexCursor::getKeySet( pKeySet = pKeySet->pNext; } + if( !pKeySet) { rc = RC_SET( FERR_NOT_FOUND); goto Exit; } + Exit: + *ppKeySet = pKeySet; return( rc); } /**************************************************************************** -Public: positionTo -Desc: Position to the input key + recordId. +Desc: Position to the input key + recordId. ****************************************************************************/ RCODE FSIndexCursor::positionTo( FDB * pDb, - FLMBYTE * pKey, // Returns FERR_OK, FERR_EOF_HIT + FLMBYTE * pKey, FLMUINT uiKeyLen, FLMUINT uiRecordId) { @@ -2040,7 +2189,9 @@ RCODE FSIndexCursor::positionTo( { goto Exit; } + // A key with a non-zero key length must be passed in. + flmAssert( uiKeyLen != 0); // Make sure we fall inside one of the key ranges and @@ -2057,8 +2208,8 @@ RCODE FSIndexCursor::positionTo( { goto Exit; } + saveCurrKeyPos( pSaveKeyPos); - releaseKeyBlocks( &m_curKeyPos); m_curKeyPos.uiKeyLen = uiKeyLen; f_memcpy( m_curKeyPos.pKey, pKey, uiKeyLen); @@ -2072,24 +2223,27 @@ RCODE FSIndexCursor::positionTo( restoreCurrKeyPos( pSaveKeyPos); goto Exit; } + m_bAtEOF = FALSE; m_bAtBOF = FALSE; m_pCurSet = pKeySet; + Exit: + if (pSaveKeyPos) { f_free( &pSaveKeyPos); } + return( rc); -}; +} /**************************************************************************** -Public: positionToDomain -Desc: Position to the input key + domain +Desc: Position to the input key + domain ****************************************************************************/ RCODE FSIndexCursor::positionToDomain( FDB * pDb, - FLMBYTE * pKey, // Returns FERR_OK, FERR_EOF_HIT + FLMBYTE * pKey, FLMUINT uiKeyLen, FLMUINT uiDomain) { @@ -2112,8 +2266,7 @@ RCODE FSIndexCursor::positionToDomain( // save the current key position so we can restore it // if the reposition call fails. - if( RC_BAD( rc = f_alloc( sizeof( KEYPOS), - &pSaveKeyPos))) + if( RC_BAD( rc = f_alloc( sizeof( KEYPOS), &pSaveKeyPos))) { goto Exit; } @@ -2122,8 +2275,8 @@ RCODE FSIndexCursor::positionToDomain( { goto Exit; } + saveCurrKeyPos( pSaveKeyPos); - releaseKeyBlocks( &m_curKeyPos); m_curKeyPos.uiKeyLen = uiKeyLen; f_memcpy( m_curKeyPos.pKey, pKey, uiKeyLen); @@ -2137,20 +2290,23 @@ RCODE FSIndexCursor::positionToDomain( restoreCurrKeyPos( pSaveKeyPos); goto Exit; } + m_bAtEOF = FALSE; m_bAtBOF = FALSE; m_pCurSet = pKeySet; + Exit: + if (pSaveKeyPos) { f_free( &pSaveKeyPos); } + return( rc); -}; +} /**************************************************************************** -Public: savePosition -Desc: Save the current position. +Desc: Save the current position. ****************************************************************************/ RCODE FSIndexCursor::savePosition( void) { @@ -2163,16 +2319,17 @@ RCODE FSIndexCursor::savePosition( void) goto Exit; } } + f_memcpy( m_pSavedPos, &m_curKeyPos, sizeof( KEYPOS)); m_curKeyPos.bStackInUse = FALSE; Exit: + return( rc); } /**************************************************************************** -Public: restorePosition -Desc: Save the current position. +Desc: ****************************************************************************/ RCODE FSIndexCursor::restorePosition( void) { @@ -2180,14 +2337,13 @@ RCODE FSIndexCursor::restorePosition( void) { releaseKeyBlocks( &m_curKeyPos); f_memcpy( &m_curKeyPos, m_pSavedPos, sizeof(KEYPOS)); - // The key blocks may still be in use. } - return FERR_OK; + return (FERR_OK); } /**************************************************************************** -Desc: Compare two key positions as they would be ordered in the index. +Desc: Compare two key positions as they would be ordered in the index. ****************************************************************************/ FSTATIC FLMINT FSCompareKeys( // negative is '<', 0 is '=', position='>' FLMBOOL bKey1IsUntilKey, // TRUE (until key) or FALSE (from key) @@ -2203,7 +2359,7 @@ FSTATIC FLMINT FSCompareKeys( // negative is '<', 0 is '=', position='>' // Handle the first key and last key issues. - if( !uiKeyLen1) // FROM or UNTIL key at end point? + if( !uiKeyLen1) // FROM or UNTIL key at end point? { if( !bKey1IsUntilKey) // FROM key { @@ -2226,9 +2382,10 @@ FSTATIC FLMINT FSCompareKeys( // negative is '<', 0 is '=', position='>' } } - // Compare the key buffers. No FIRST or LAST key now. else if( uiKeyLen1 > uiKeyLen2) { + // Compare the key buffers. No FIRST or LAST key now. + if( (iCmp = f_memcmp( pKey1, pKey2, uiKeyLen2)) == 0) { iCmp = 1; @@ -2241,7 +2398,7 @@ FSTATIC FLMINT FSCompareKeys( // negative is '<', 0 is '=', position='>' iCmp = -1; } } - else // Key lengths are equal + else { if( (iCmp = f_memcmp( pKey1, pKey2, uiKeyLen1)) == 0) { @@ -2271,38 +2428,14 @@ FSTATIC FLMINT FSCompareKeys( // negative is '<', 0 is '=', position='>' iCmp = bExclusiveKey1 ? -1 : 1; } } -#if 0 - if( iCmp == 0) - { - // Compare the record Id. Value of 0 means ALL record Ids. - // Remember that RecordIds for the same key are DESCENDING. - - if( uiRecordId1 != uiRecordId2) - { - if( uiRecordId1 == 0) - { - iCmp = bKey1IsUntilKey ? 1 : -1; - } - else if( uiRecordId2 == 0) - { - iCmp = bKey2IsUntilKey ? -1 : 1; - } - else - { - // Don't trust (ui - ui) to return a signed value. - iCmp = (uiRecordId1 > uiRecordId2) ? -1 : 1; - } - } - } -#endif } } - return iCmp; + + return (iCmp); } - /**************************************************************************** -Desc: Allocate and return the first and last keys in an index. +Desc: Allocate and return the first and last keys in an index. ****************************************************************************/ RCODE FSIndexCursor::getFirstLastKeys( FLMBYTE ** ppFirstKey, @@ -2321,11 +2454,13 @@ RCODE FSIndexCursor::getFirstLastKeys( *pbLastKeyExclusive = TRUE; goto Exit; } + if( RC_BAD( rc = f_alloc( pCurSet->fromKey.uiKeyLen, ppFirstKey))) { goto Exit; } + *puiFirstKeyLen = pCurSet->fromKey.uiKeyLen; f_memcpy( *ppFirstKey, pCurSet->fromKey.pKey, *puiFirstKeyLen); @@ -2341,21 +2476,24 @@ RCODE FSIndexCursor::getFirstLastKeys( { f_free( ppFirstKey); } + goto Exit; } + *puiLastKeyLen = pCurSet->untilKey.uiKeyLen; f_memcpy( *ppLastKey, pCurSet->untilKey.pKey, *puiLastKeyLen); *pbLastKeyExclusive = pCurSet->untilKey.bExclusiveKey; Exit: + return( rc); } /**************************************************************************** -Desc: Set the absolute position in a positioning index relative to the - FROM/UNTIL keys in all of the key sets. Supports multiple key sets. +Desc: Set the absolute position in a positioning index relative to the + FROM/UNTIL keys in all of the key sets. Supports multiple key sets. ****************************************************************************/ -RCODE FSIndexCursor::setAbsolutePosition( // FERR_FAILURE - index not positionable +RCODE FSIndexCursor::setAbsolutePosition( FDB * pDb, FLMUINT uiRefPosition) // 0 -> BOF, -1 -> EOF points, one based { @@ -2369,35 +2507,44 @@ RCODE FSIndexCursor::setAbsolutePosition( // FERR_FAILURE - index not positionab rc = RC_SET( FERR_FAILURE); goto Exit; } + if( RC_BAD( rc = checkTransaction( pDb))) { goto Exit; } // Zero value position to BOF + if( uiRefPosition == 0 || uiRefPosition == 1) { // Go to the first reference. + if( RC_OK( rc = firstKey( pDb, NULL, NULL))) { if( uiRefPosition == 0) { // Should return FERR_BOF_HIT + rc = prevKey( pDb, NULL, NULL); } } + goto Exit; } // High-values value position to EOF + if( uiRefPosition == (FLMUINT) -1) { // Position to EOF + if( RC_OK( rc = lastKey( pDb, NULL, NULL))) { // Should return FERR_EOF_HIT + rc = nextKey( pDb, NULL, NULL); } + goto Exit; } @@ -2422,14 +2569,18 @@ RCODE FSIndexCursor::setAbsolutePosition( // FERR_FAILURE - index not positionab break; } } + if( !uiBtreeRefPosition) { // Position to EOF + if( RC_OK( rc = lastKey( pDb, NULL, NULL))) { // Should return FERR_EOF_HIT + rc = nextKey( pDb, NULL, NULL); } + goto Exit; } @@ -2443,17 +2594,19 @@ RCODE FSIndexCursor::setAbsolutePosition( // FERR_FAILURE - index not positionab { goto Exit; } + m_curKeyPos.bStackInUse = TRUE; setKeyItemsFromBlock( &m_curKeyPos); m_bAtBOF = m_bAtEOF = FALSE; Exit: + return( rc); } /**************************************************************************** -Desc: Get the absolute position in a positioning index. - Supports multiple sets. +Desc: Get the absolute position in a positioning index. + Supports multiple sets. ****************************************************************************/ RCODE FSIndexCursor::getAbsolutePosition( FDB * pDb, @@ -2470,15 +2623,18 @@ RCODE FSIndexCursor::getAbsolutePosition( rc = RC_SET( FERR_FAILURE); goto Exit; } + if( RC_BAD( rc = checkTransaction( pDb))) { goto Exit; } + if( m_bAtBOF) { *puiRefPosition = 0; goto Exit; } + if( m_bAtEOF) { *puiRefPosition = (FLMUINT) -1; @@ -2489,6 +2645,7 @@ RCODE FSIndexCursor::getAbsolutePosition( { FLMBOOL bKeyGone; FLMBOOL bRefGone; + if( RC_BAD( rc = reposition( pDb, FALSE, FALSE, &bKeyGone, FALSE, FALSE, &bRefGone))) { @@ -2505,6 +2662,7 @@ RCODE FSIndexCursor::getAbsolutePosition( { goto Exit; } + uiRefPosition = (uiBtreeRefPosition - m_pCurSet->fromKey.uiRefPosition) + 1; for( pTempSet = m_pCurSet->pPrev; pTempSet; pTempSet = pTempSet->pPrev) @@ -2516,16 +2674,17 @@ RCODE FSIndexCursor::getAbsolutePosition( } Exit: + if( RC_OK( rc)) { *puiRefPosition = uiRefPosition; } + return( rc); } - /**************************************************************************** -Desc: Get the total number of reference for all of the sets. +Desc: Get the total number of reference for all of the sets. ****************************************************************************/ RCODE FSIndexCursor::getTotalReferences( FDB * pDb, @@ -2543,6 +2702,7 @@ RCODE FSIndexCursor::getTotalReferences( { goto Exit; } + *pbTotalsEstimated = FALSE; // We have to be careful not to change the current position in any way. @@ -2564,6 +2724,7 @@ RCODE FSIndexCursor::getTotalReferences( goto Exit; } } + // Compute the counts the old fashion way. f_memcpy( pTempSet, pKeySet, sizeof( KEYSET)); @@ -2574,14 +2735,17 @@ RCODE FSIndexCursor::getTotalReferences( pTempSet->untilKey.Stack[uiStackPos].pSCache = NULL; pTempSet->untilKey.Stack[uiStackPos].pBlk = NULL; } + pTempSet->fromKey.bStackInUse = FALSE; pTempSet->untilKey.bStackInUse = FALSE; // Search down the tree and get the counts. + if( RC_OK( rc = setKeyPosition( pDb, TRUE, &pTempSet->fromKey, &pTempSet->fromKey))) { // All keys bewteen low and high may be gone. + if( FS_COMPARE_KEYS( FALSE, &pTempSet->fromKey, TRUE, &pKeySet->untilKey) > 0) { @@ -2593,9 +2757,11 @@ RCODE FSIndexCursor::getTotalReferences( &pTempSet->untilKey, &pTempSet->untilKey); } } + if( RC_BAD( rc)) { // Empty tree case. + if( rc == FERR_EOF_HIT || rc == FERR_BOF_HIT) { rc = FERR_OK; @@ -2613,23 +2779,27 @@ RCODE FSIndexCursor::getTotalReferences( { goto Exit; } + uiTotalRefs += uiRefCount; } + releaseKeyBlocks( &pTempSet->fromKey); releaseKeyBlocks( &pTempSet->untilKey); } Exit: + if( pTempSet) { releaseKeyBlocks( &pTempSet->fromKey); releaseKeyBlocks( &pTempSet->untilKey); f_free( &pTempSet); } + if( RC_OK(rc)) { *puiTotalRefs = uiTotalRefs; } + return( rc); } - diff --git a/flaim/src/fscursor.h b/flaim/src/fscursor.h index 52a1bcf..c2df13e 100644 --- a/flaim/src/fscursor.h +++ b/flaim/src/fscursor.h @@ -26,18 +26,21 @@ #define FSCURSOR_H #include "fpackon.h" + // IMPORTANT NOTE: No other include files should follow this one except // for fpackoff.h -class F_Base; - -typedef struct KeyPosition +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct KEYPOS { FLMUINT uiKeyLen; FLMUINT uiRecordId; FLMBOOL bExclusiveKey; // State information + FLMUINT uiRefPosition; FLMUINT uiDomain; FLMUINT uiBlockTransId; @@ -46,24 +49,24 @@ typedef struct KeyPosition DIN_STATE DinState; // Stack and key information + BTSK * pStack; FLMBOOL bStackInUse; - // VISIT: Add bIsUntilKey boolean. BTSK Stack [BH_MAX_LEVELS]; FLMBYTE pKey [MAX_KEY_SIZ + 4]; // + 4 is for safety } KEYPOS; -typedef struct Key_Set * KEYSET_p; -typedef struct Key_Set +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct KEYSET { KEYPOS fromKey; KEYPOS untilKey; - KEYSET_p pNext; - KEYSET_p pPrev; - + KEYSET * pNext; + KEYSET * pPrev; } KEYSET; - /**************************************************************************** Desc: File system implementation of a cursor for an index. ****************************************************************************/ @@ -76,152 +79,147 @@ public: virtual ~FSIndexCursor(); // Reset the cursor back to an empty state. - void reset(); + + void reset( void); // Reset the transaction on this cursor. + RCODE resetTransaction( - FDB * pDb); + FDB * pDb); // Release all b-tree blocks back to the cache. + void releaseBlocks( void); RCODE setupKeys( - FDB * pDb, - IXD_p pIxd, - QPREDICATE_p * ppQPredicateList, - FLMBOOL * pbDoRecMatch, - FLMBOOL * pbDoKeyMatch, - FLMUINT * puiLeafBlocksBetween, - FLMUINT * puiTotalKeys, - FLMUINT * puiTotalRefs, - FLMBOOL * pbTotalsEstimated); + FDB * pDb, + IXD * pIxd, + QPREDICATE ** ppQPredicateList, + FLMBOOL * pbDoRecMatch, + FLMBOOL * pbDoKeyMatch, + FLMUINT * puiLeafBlocksBetween, + FLMUINT * puiTotalKeys, + FLMUINT * puiTotalRefs, + FLMBOOL * pbTotalsEstimated); RCODE setupKeys( - FDB * pDb, - IXD_p pIxd, - FLMBYTE * pFromKey, - FLMUINT uiFromKeyLen, - FLMUINT uiFromRecordId, - FLMBYTE * pUntilKey, - FLMUINT uiUntilKeyLen, - FLMUINT uiUntilRecordId, - FLMBOOL bExclusiveUntil); + FDB * pDb, + IXD * pIxd, + FLMBYTE * pFromKey, + FLMUINT uiFromKeyLen, + FLMUINT uiFromRecordId, + FLMBYTE * pUntilKey, + FLMUINT uiUntilKeyLen, + FLMUINT uiUntilRecordId, + FLMBOOL bExclusiveUntil); RCODE unionKeys( - FSIndexCursor * pFSCursor); + FSIndexCursor * pFSCursor); RCODE intersectKeys( - FDB * pDb, - FSIndexCursor * pFSCursor); + FDB * pDb, + FSIndexCursor * pFSCursor); FLMBOOL compareKeyRange( - FLMBYTE * pFromKey, - FLMUINT uiFromKeyLen, - FLMBOOL bExclusiveFrom, - FLMBYTE * pUntilKey, - FLMUINT uiUntilKeyLen, - FLMBOOL bExclusiveUntil, - FLMBOOL * pbUntilKeyInSet, - FLMBOOL * pbUntilGreaterThan); + FLMBYTE * pFromKey, + FLMUINT uiFromKeyLen, + FLMBOOL bExclusiveFrom, + FLMBYTE * pUntilKey, + FLMUINT uiUntilKeyLen, + FLMBOOL bExclusiveUntil, + FLMBOOL * pbUntilKeyInSet, + FLMBOOL * pbUntilGreaterThan); - // Returns FERR_OK, FERR_BOF_HIT, FERR_EOF_HIT or error RCODE currentKey( - FDB * pDb, - FlmRecord ** pPrecordKey, - FLMUINT * puiRecordId); + FDB * pDb, + FlmRecord ** pPrecordKey, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_BOF_HIT, FERR_EOF_HIT or error RCODE currentKeyBuf( - FDB * pDb, - POOL * pPool, - FLMBYTE ** ppKeyBuf, - FLMUINT * puiKeyLen, - FLMUINT * puiRecordId, - FLMUINT * puiContainerId); + FDB * pDb, + POOL * pPool, + FLMBYTE ** ppKeyBuf, + FLMUINT * puiKeyLen, + FLMUINT * puiRecordId, + FLMUINT * puiContainerId); - // Returns FERR_OK, FERR_BOF_HIT or error RCODE firstKey( - FDB * pDb, - FlmRecord ** pPrecordKey, - FLMUINT * puiRecordId); + FDB * pDb, + FlmRecord ** pPrecordKey, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE lastKey( - FDB * pDb, - FlmRecord ** pPrecordKey, - FLMUINT * puiRecordId); + FDB * pDb, + FlmRecord ** pPrecordKey, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE nextKey( - FDB * pDb, - FlmRecord ** pPrecordKey, - FLMUINT * puiRecordId); + FDB * pDb, + FlmRecord ** pPrecordKey, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_BOF_HIT or error RCODE prevKey( - FDB * pDb, - FlmRecord ** pPrecordKey, - FLMUINT * puiRecordId); + FDB * pDb, + FlmRecord ** pPrecordKey, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE nextRef( - FDB * pDb, - FLMUINT * puiRecordId); + FDB * pDb, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_BOF_HIT or error RCODE prevRef( - FDB * pDb, - FLMUINT * puiRecordId); + FDB * pDb, + FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_NOT_FOUND if not found or error. RCODE positionTo( - FDB * pDb, - FLMBYTE * pKey, - FLMUINT uiKeyLen, - FLMUINT uiRecordId = 0); + FDB * pDb, + FLMBYTE * pKey, + FLMUINT uiKeyLen, + FLMUINT uiRecordId = 0); - // Returns FERR_OK, FERR_NOT_FOUND if not found or error. RCODE positionToDomain( - FDB * pDb, - FLMBYTE * pKey, - FLMUINT uiKeyLen, - FLMUINT uiDomain); + FDB * pDb, + FLMBYTE * pKey, + FLMUINT uiKeyLen, + FLMUINT uiDomain); - // Does this index support native absolute positioning? - FLMBOOL isAbsolutePositionable() + FLMBOOL isAbsolutePositionable( void) { return (m_pIxd->uiFlags & IXD_POSITIONING) ? TRUE : FALSE; } // Set absolute position (if not supported returns FERR_FAILURE). // uiPosition of zero positions to BOF, ~0 to EOF, one based value. + RCODE setAbsolutePosition( - FDB * pDb, - FLMUINT uiRefPosition); + FDB * pDb, + FLMUINT uiRefPosition); // Get absolute position (if not supported returns FERR_FAILURE). // uiPosition of zero positions to BOF, ~0 to EOF, one based value. + RCODE getAbsolutePosition( - FDB * pDb, - FLMUINT * puiRefPosition); + FDB * pDb, + FLMUINT * puiRefPosition); // Get the total number of reference with all from/until sets. // Does not have to support absolute positioning. + RCODE getTotalReferences( - FDB * pDb, - FLMUINT * puiTotalRefs, - FLMBOOL * pbTotalEstimated); + FDB * pDb, + FLMUINT * puiTotalRefs, + FLMBOOL * pbTotalEstimated); RCODE savePosition( void); RCODE restorePosition( void); RCODE getFirstLastKeys( - FLMBYTE ** ppFirstKey, - FLMUINT * puiFirstKeyLen, - FLMBYTE ** ppLastKey, - FLMUINT * puiLastKeyLen, - FLMBOOL * pbLastKeyExclusive); + FLMBYTE ** ppFirstKey, + FLMUINT * puiFirstKeyLen, + FLMBYTE ** ppLastKey, + FLMUINT * puiLastKeyLen, + FLMBOOL * pbLastKeyExclusive); protected: @@ -238,28 +236,28 @@ private: FDB * pDb); FLMBOOL FSCompareKeyPos( - KEYSET * pSet1, - KEYSET * pSet2, - FLMBOOL * pbFromKeysLessThan, - FLMBOOL * pbUntilKeysGreaterThan); + KEYSET * pSet1, + KEYSET * pSet2, + FLMBOOL * pbFromKeysLessThan, + FLMBOOL * pbUntilKeysGreaterThan); RCODE setKeyPosition( - FDB * pDb, - FLMBOOL bGoingForward, - KEYPOS * pInKeyPos, - KEYPOS * pOutKeyPos); + FDB * pDb, + FLMBOOL bGoingForward, + KEYPOS * pInKeyPos, + KEYPOS * pOutKeyPos); RCODE reposition( - FDB * pDb, - FLMBOOL bCanPosToNextKey, - FLMBOOL bCanPosToPrevKey, - FLMBOOL * pbKeyGone, - FLMBOOL bCanPosToNextRef, - FLMBOOL bCanPosToPrevRef, - FLMBOOL * pbRefGone); + FDB * pDb, + FLMBOOL bCanPosToNextKey, + FLMBOOL bCanPosToPrevKey, + FLMBOOL * pbKeyGone, + FLMBOOL bCanPosToNextRef, + FLMBOOL bCanPosToPrevRef, + FLMBOOL * pbRefGone); void releaseKeyBlocks( - KEYPOS * pKeyPos) + KEYPOS * pKeyPos) { if( pKeyPos->bStackInUse) { @@ -269,7 +267,7 @@ private: } RCODE checkTransaction( - FDB * pDb) + FDB * pDb) { return (RCODE) ((m_uiCurrTransId != pDb->LogHdr.uiCurrTransID || m_uiBlkChangeCnt != pDb->uiBlkChangeCnt) @@ -278,64 +276,62 @@ private: } RCODE setupForPositioning( - FDB * pDb); + FDB * pDb); // Save the current key position into pSaveKeyPos + void saveCurrKeyPos( - KEYPOS * pSaveKeyPos); + KEYPOS * pSaveKeyPos); // Restore the current key position from pSaveKeyPos - void restoreCurrKeyPos( - KEYPOS * pSaveKeyPos); - - // Returns FERR_OK, FERR_NOT_FOUND if no key set. - RCODE getKeySet( - FLMBYTE * pKey, - FLMUINT uiKeyLen, - KEYSET ** ppKeySet); - - // Database information - FLMUINT m_uiCurrTransId; - FLMUINT m_uiBlkChangeCnt; - FLMBOOL m_bIsUpdateTrans; - FLMUINT m_uiIndexNum; - LFILE * m_pLFile; - IXD * m_pIxd; - - // Contains a list of all of the FROM/UNTIL sets - KEYSET * m_pFirstSet; - // State information. - KEYSET * m_pCurSet; - FLMBOOL m_bAtBOF; // Before the first key. - FLMBOOL m_bAtEOF; // After the last key. + void restoreCurrKeyPos( + KEYPOS * pSaveKeyPos); - KEYPOS m_curKeyPos; // Current key position - KEYPOS * m_pSavedPos; // Saved position - KEYSET m_DefaultSet; // Single minimum FROM/UNTIL key + RCODE getKeySet( + FLMBYTE * pKey, + FLMUINT uiKeyLen, + KEYSET ** ppKeySet); + + FLMUINT m_uiCurrTransId; + FLMUINT m_uiBlkChangeCnt; + FLMBOOL m_bIsUpdateTrans; + FLMUINT m_uiIndexNum; + LFILE * m_pLFile; + IXD * m_pIxd; + KEYSET * m_pFirstSet; + KEYSET * m_pCurSet; + FLMBOOL m_bAtBOF; + FLMBOOL m_bAtEOF; + KEYPOS m_curKeyPos; + KEYPOS * m_pSavedPos; + KEYSET m_DefaultSet; }; -typedef struct RecPosition +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct RECPOS { FLMUINT uiRecordId; FLMUINT uiBlockTransId; FLMUINT uiBlockAddr; BTSK * pStack; FLMBOOL bStackInUse; - FLMBOOL bExclusiveKey; // True if an UNTIL key. + FLMBOOL bExclusiveKey; BTSK Stack [BH_MAX_LEVELS]; FLMBYTE pKey [DIN_KEY_SIZ]; } RECPOS; -// The record set will always have inclusive FROM/UNTIL values. -typedef struct Record_Set * RECSET_p; -typedef struct Record_Set +/**************************************************************************** +Desc: The record set will always have inclusive FROM/UNTIL values. +****************************************************************************/ +typedef struct RECSET { RECPOS fromKey; RECPOS untilKey; - RECSET_p pNext; - RECSET_p pPrev; - + RECSET * pNext; + RECSET * pPrev; } RECSET; /**************************************************************************** @@ -350,9 +346,11 @@ public: virtual ~FSDataCursor(); // Reset this cursor back to an initial state. - void reset(); + + void reset( void); // Reset the transaction on this cursor. + RCODE resetTransaction( FDB * pDb); @@ -383,36 +381,30 @@ public: FlmRecord ** pPrecord, FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_BOF_HIT or error RCODE firstRec( FDB * pDb, FlmRecord ** pPrecord, FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE lastRec( FDB * pDb, FlmRecord ** pPrecord, FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE nextRec( FDB * pDb, FlmRecord ** pPrecord, FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_BOF_HIT or error RCODE prevRec( FDB * pDb, FlmRecord ** pPrecord, FLMUINT * puiRecordId); - // Returns FERR_OK, FERR_NOT_FOUND or error RCODE positionTo( FDB * pDb, FLMUINT uiRecordId); - // Returns FERR_OK, FERR_EOF_HIT or error RCODE positionToOrAfter( FDB * pDb, FLMUINT * puiRecordId); @@ -441,6 +433,7 @@ private: pRecPos->bStackInUse = FALSE; } } + RCODE setRecPosition( FDB * pDb, FLMBOOL bGoingForward, @@ -468,25 +461,18 @@ private: : FERR_OK); } - // Database information FLMUINT m_uiCurrTransId; FLMUINT m_uiBlkChangeCnt; FLMBOOL m_bIsUpdateTrans; FLMUINT m_uiContainer; LFILE * m_pLFile; - - // Contains a list of all of the FROM/UNTIL sets RECSET * m_pFirstSet; - - // State information. RECSET * m_pCurSet; - FLMBOOL m_bAtBOF; // Before the first key. - FLMBOOL m_bAtEOF; // After the last key. - - RECPOS m_curRecPos; // Current key position - RECPOS * m_pSavedPos; // Saved position - RECSET m_DefaultSet; // Single minimum FROM/UNTIL key - + FLMBOOL m_bAtBOF; + FLMBOOL m_bAtEOF; + RECPOS m_curRecPos; + RECPOS * m_pSavedPos; + RECSET m_DefaultSet; }; #include "fpackoff.h" diff --git a/flaim/src/fsdatacu.cpp b/flaim/src/fsdatacu.cpp index 7eba78c..3f19545 100644 --- a/flaim/src/fsdatacu.cpp +++ b/flaim/src/fsdatacu.cpp @@ -25,7 +25,7 @@ #include "flaimsys.h" /**************************************************************************** -Public: Constructor +Desc: ****************************************************************************/ FSDataCursor::FSDataCursor() { @@ -37,7 +37,7 @@ FSDataCursor::FSDataCursor() } /**************************************************************************** -Public: Destructor +Desc: ****************************************************************************/ FSDataCursor::~FSDataCursor() { @@ -46,8 +46,7 @@ FSDataCursor::~FSDataCursor() } /**************************************************************************** -Public: reset -Desc: Resets any allocations, keys, state, etc. +Desc: Resets any allocations, keys, state, etc. ****************************************************************************/ void FSDataCursor::reset( void) { @@ -69,10 +68,9 @@ void FSDataCursor::reset( void) /**************************************************************************** -Public: resetTransaction -Desc: Resets to a new transaction that may change the read consistency of - the query. This is usually an old view error internal or external of - this class. +Desc: Resets to a new transaction that may change the read consistency of + the query. This is usually an old view error internal or external of + this class. ****************************************************************************/ RCODE FSDataCursor::resetTransaction( FDB * pDb) @@ -89,9 +87,7 @@ RCODE FSDataCursor::resetTransaction( m_uiBlkChangeCnt = pDb->uiBlkChangeCnt; m_bIsUpdateTrans = (pDb->uiTransType == FLM_UPDATE_TRANS) ? TRUE : FALSE; - /* - Need to release all stacks that are currently in use. - */ + // Need to release all stacks that are currently in use. for( pTmpSet = m_pFirstSet; pTmpSet; pTmpSet = pTmpSet->pNext) { @@ -142,10 +138,8 @@ void FSDataCursor::freeSets( void) /**************************************************************************** -Public: releaseBlocks -Desc: Releases the cache blocks back to cache. +Desc: Releases the cache blocks back to cache. ****************************************************************************/ - void FSDataCursor::releaseBlocks( void) { RECSET * pCurSet; @@ -163,10 +157,9 @@ void FSDataCursor::releaseBlocks( void) } /**************************************************************************** -Public: setupRange -Desc: Setup the from and until keys in the cursor. Return counts - after positioning to the from and until key in the index. - This code does not work with multiple key sets of FROM/UNTIL keys. +Desc: Setup the from and until keys in the cursor. Return counts + after positioning to the from and until key in the index. + This code does not work with multiple key sets of FROM/UNTIL keys. ****************************************************************************/ RCODE FSDataCursor::setupRange( FDB * pDb, @@ -272,8 +265,7 @@ Exit: } /**************************************************************************** -Public: unionRange -Desc: Merge the input cursors fromUntil sets as a result of a UNION. +Desc: Merge the input cursors fromUntil sets as a result of a UNION. ****************************************************************************/ RCODE FSDataCursor::unionRange( FSDataCursor * pFSCursor) @@ -420,8 +412,7 @@ Exit: } /**************************************************************************** -Public: intersectRange -Desc: Intersect the from/until key sets of pFSCursor into 'this'. +Desc: Intersect the from/until key sets of pFSCursor into 'this'. ****************************************************************************/ RCODE FSDataCursor::intersectRange( FSDataCursor * pFSCursor) @@ -548,11 +539,9 @@ FLMBOOL FSDataCursor::FSCompareRecPos( // TRUE if keys overlap } /**************************************************************************** -Public: currentRec Desc: Return the current record and record id. VISIT: We may want to return BOF/EOF when positioned on an endpoint. ****************************************************************************/ - RCODE FSDataCursor::currentRec( // FERR_OK, FERR_EOF_HIT or error FDB * pDb, FlmRecord ** ppRecord, // Will replace what is there @@ -595,15 +584,14 @@ Exit: } /**************************************************************************** -Public: firstRec -Desc: Position to and return the first record. - This is hard because positioning using the first key may actually - position past or into another FROM/UNTIL set in the list. +Desc: Position to and return the first record. + This is hard because positioning using the first key may actually + position past or into another FROM/UNTIL set in the list. ****************************************************************************/ -RCODE FSDataCursor::firstRec( // FERR_OK, FERR_EOF_HIT or error +RCODE FSDataCursor::firstRec( FDB * pDb, FlmRecord ** ppRecord, // Will replace what is there - FLMUINT * puiRecordId) // Set the record ID + FLMUINT * puiRecordId) // Set the record ID { RCODE rc; @@ -777,14 +765,13 @@ Exit: } /**************************************************************************** -Public: lastRec -Desc: Position to and return the last record. - This is hard because positioning using the first key may actually - position past or into another FROM/UNTIL set in the list. +Desc: Position to and return the last record. + This is hard because positioning using the first key may actually + position past or into another FROM/UNTIL set in the list. ****************************************************************************/ -RCODE FSDataCursor::lastRec( // FERR_OK, FERR_BOF_HIT or error +RCODE FSDataCursor::lastRec( FDB * pDb, - FlmRecord ** ppRecord, // Will replace what is there + FlmRecord ** ppRecord, // Will replace what is there FLMUINT * puiRecordId) // Set the record ID { RCODE rc; @@ -912,10 +899,9 @@ Exit: } /**************************************************************************** -Public: nextRec -Desc: Position to the next key and the first reference of that key. +Desc: Position to the next key and the first reference of that key. ****************************************************************************/ -RCODE FSDataCursor::nextRec( // FERR_OK, FERR_EOF_HIT or error +RCODE FSDataCursor::nextRec( FDB * pDb, FlmRecord ** ppRecord, FLMUINT * puiRecordId) @@ -1045,10 +1031,9 @@ Exit: } /**************************************************************************** -Public: prevRec -Desc: Position to the PREVIOUS record. +Desc: Position to the PREVIOUS record. ****************************************************************************/ -RCODE FSDataCursor::prevRec( // FERR_OK, FERR_EOF_HIT or error +RCODE FSDataCursor::prevRec( FDB * pDb, FlmRecord ** ppRecord, FLMUINT * puiRecordId) @@ -1295,10 +1280,9 @@ Exit: } /**************************************************************************** -Public: positionTo -Desc: Position to the input key + recordId. +Desc: Position to the input key + recordId. ****************************************************************************/ -RCODE FSDataCursor::positionTo( // FERR_NOT_FOUND if outside set or not found +RCODE FSDataCursor::positionTo( FDB * pDb, FLMUINT uiRecordId) { @@ -1331,10 +1315,9 @@ Exit: }; /**************************************************************************** -Public: positionToOrAfter -Desc: Position to the input key + recordId. +Desc: Position to the input key + recordId. ****************************************************************************/ -RCODE FSDataCursor::positionToOrAfter( // FERR_EOF_HIT or error. +RCODE FSDataCursor::positionToOrAfter( FDB * pDb, FLMUINT * puiRecordId) { @@ -1382,8 +1365,7 @@ Exit: }; /**************************************************************************** -Public: savePosition -Desc: Save the current position. +Desc: Save the current position. ****************************************************************************/ RCODE FSDataCursor::savePosition( void) { @@ -1404,8 +1386,7 @@ Exit: } /**************************************************************************** -Public: restorePosition -Desc: Save the current position. +Desc: Save the current position. ****************************************************************************/ RCODE FSDataCursor::restorePosition( void) { @@ -1417,5 +1398,3 @@ RCODE FSDataCursor::restorePosition( void) return FERR_OK; } - - diff --git a/flaim/src/fsdelelm.cpp b/flaim/src/fsdelelm.cpp index 813ed3b..1d59a6a 100644 --- a/flaim/src/fsdelelm.cpp +++ b/flaim/src/fsdelelm.cpp @@ -1,737 +1,797 @@ -//------------------------------------------------------------------------- -// Desc: Delete element from b-tree block. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsdelelm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*************************************************************************** -Desc: Delete the current element from a b-tree block and write block. - The stack must point to the next element after the deleted element. - The next element could be in a different block so be careful. -Notes: The order of the high level if's is VERY important. - The order of changing the blocks is not important because of logging. -*****************************************************************************/ -RCODE FSBtDelete( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV - ) -{ - RCODE rc; - BTSK_p pStack = *pStackRV; - SCACHE * pTmpSCache; - FLMBYTE * pBlk; - FLMBOOL bReleaseTmpCache = FALSE; - FLMUINT uiNextBlk; - FLMUINT uiPrevBlk; - FLMUINT uiLastElm; /* Offset of last element in a block */ - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMBYTE pLEMBuffer[ 12 ]; /* Last element marker buffer */ - - /* Log block before modifying it */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - goto Exit; - - // If this is a non-leaf positioning index, update parent counts. - if( pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) - { - if( pStack->uiLevel) - { - FLMUINT uiRefCount; - FLMBYTE * pElm = pStack->pBlk + pStack->uiCurElm; - - // Reduce the counts from the parent up. - uiRefCount = FB2UD( &pElm[ BNE_CHILD_COUNT]); - if( RC_BAD( rc = FSChangeBlkCounts( pDb, pStack, - (FLMINT) (0 - uiRefCount) ))) - { - goto Exit; - } - } - } - - if( RC_BAD(rc = FSBlkDelElm( pStack ))) - goto Exit; - - /** - *** Take care of deletion of the ONLY element in the block. - *** There is NO WAY this could be a root or right end block because - *** of the last element marker (LEM) takes up 2 or 4 bytes - **/ - if( pStack->uiBlkEnd == BH_OVHD) - { - /** - *** Free up this empty block and fixup the NEXT/PREV links. - **/ - uiNextBlk = FB2UD( &pStack->pBlk[ BH_NEXT_BLK ]); - rc = FSBlockFixLinks( pDb, pLFile, pStack->pSCache); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - if( RC_BAD( rc)) - goto Exit; - - /** - *** Remove the element that pointed to this block - **/ - - if( RC_OK( rc = FSDelParentElm( pDb, pLFile, &pStack ))) - { - pStack->uiBlkAddr = uiNextBlk; - /* Read the next block and set stack to point to next element */ - if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiNextBlk, pStack))) - { - pStack->uiCurElm = BH_OVHD; - - /**------------------------------------------------------------ - *** Added 07/15/93 - *** Need to reset keybuf[] for deletes in a while loop like the - *** data record delete code in fsrecupd.c. - *** This may be cause of some corruptions while deleting - *** lots of records. - ***-----------------------------------------------------------*/ - FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM ); - } - } - *pStackRV = pStack; - } - /** Deleting a RIGHT MOST B-tree block (along the right side). - *** Check if only the LEM (last element marker) is left in the block. - *** A block CANNOT contain just a LEM. Move the LEM & free the block. - *** - *** There are 3 cases to watch for: - *** EMPTY B-TREE - free the root/block save next record in lfArea - *** EMPTY ROOT - free root and goto child & make that root - *** EMPTY BLOCK - cannot contain only a LEM - move to previous block - *** - *** Must not move LASST DRN Marker - there is no need to do this. - *** - **/ - else if( (FB2UD( &pStack->pBlk[ BH_NEXT_BLK ]) == BT_END) - && ( (pStack->uiBlkEnd == BH_OVHD + uiElmOvhd ) - // || ( (pLFile->uiLfType == LF_CONTAINER) - // && (stack->uiBlkEnd == BH_OVHD + DRN_LAST_MARKER_LEN+ uiElmOvhd) - // && (stack->uiBlkType == BHT_LEAF) - ) ) //) - { - /** - *** EMPTY B-TREE - *** Level is not in the current LFILE version so check if the root - *** block is the same as this block. - **/ - if( (pStack->uiBlkType == BHT_LEAF) - && (pLFile->uiRootBlk == pStack->uiBlkAddr )) /* Root is leaf */ - { - /** - *** Return the empty root block to the system - *** Code (11/26/91) supports empty b-trees. We have gone back - *** and forth on returning empty root blocks to the system. - *** Setup stack for emtpy state and modify the LFILE on disk. - *** - *** The data record b-tree can NEVER be empty because of - *** the next record DRN record should always hang around. - *** - *** ALL CALLING ROUTINES MUST CHECK for( STACK->uiBlkAddr == BT_END) - **/ - pStack->uiBlkAddr = BT_END; - { - /* Get the next DRN and save in the LFD */ - FLMBYTE * ptr = &pStack->pBlk[ BH_OVHD ]; - ptr += BBE_GETR_KL( ptr ) + BBE_KEY; - pLFile->uiNextDrn = (FLMUINT) FB2UD( ptr); - } - - rc = FSBlockFree( pDb, pStack->pSCache); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - if( RC_BAD( rc)) - goto Exit; - - pLFile->uiRootBlk = BT_END; - rc = flmLFileWrite( pDb, pLFile); - } - - /** - *** EMPTY ROOT BLOCK - *** - *** Remove root block and set new root block to child. - **/ - else if( pLFile->uiRootBlk == pStack->uiBlkAddr) - { - // Obtain child block and set to lfArea to assign new root block - - uiNextBlk = FSChildBlkAddr( pStack ); - - rc = FSBlockFree( pDb, pStack->pSCache); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - - if( RC_BAD( rc)) - { - goto Exit; - } - - pLFile->uiRootBlk = uiNextBlk; - - if( RC_BAD( rc = flmLFileWrite( pDb, pLFile))) - { - goto Exit; - } - - // Assign the new root block - - if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, - uiNextBlk, NULL, &pTmpSCache))) - { - goto Exit; - } - bReleaseTmpCache = TRUE; - - if( RC_BAD( rc = ScaLogPhysBlk( pDb, &pTmpSCache))) - { - goto Exit; - } - - // Set the root block flag on this block & mark dirty - - BH_SET_ROOT_BLK( pTmpSCache->pucBlk ); - ScaReleaseCache( pTmpSCache, FALSE); - bReleaseTmpCache = FALSE; - - /** - *** Date Added: 8/19/93 - *** It is possible to add an element so that a new root block - *** gets created AND THEN Deleted. I saw this on OS2 when they - *** got up to 6 levels in the btree. Because of this the ROOT - *** block in the stack MUST always be pStack[0]. - *** The three lines below do this. Tested on Brad Daw's db. - **/ - - shiftN( (FLMBYTE *) pStack + sizeof(BTSK), - sizeof(BTSK) * pStack->uiLevel, /* think uiLevel + 1 - 1 */ - 0-(sizeof(BTSK))); - - /* - We don't want a pointer to the same shared cache in two different - elements of the pStack. NULL out the one that was moved down. - */ - - (pStack + pStack->uiLevel + 1)->pSCache = NULL; - (pStack + pStack->uiLevel + 1)->pBlk = NULL; - pStack--; /* Point 1 element BEFORE stack starts ! */ - *pStackRV = pStack; - - /* Don't worry about positioning to the next element - root gone */ - } - else - { - /** - *** ONLY LAST ELEMENT MARKER (LEM) REMAINS - *** (leaf or (non-leaf but NOT ROOT)) - *** A block must NEVER contain only the last element marker (LEM). - *** This may free up a leaf block or a non-leaf block but never - *** a root block (root checks above.) - *** - *** This is the most complex case. - *** Move the last element marker (LEM) to the end of the - *** previous block. Be carefull to delete the - *** correct element in the parent block. - *** The algorithm states that there MUST ALWAYS be room to insert - *** the LEM into a block without splitting that block. - *** - *** Because of logging the block modifications do not need to be - *** flushed in a specific order to prevent corruption. - */ - - uiPrevBlk = FB2UD( &pStack->pBlk[ BH_PREV_BLK ]); - - /* Save the last element marker, may be a non-leaf element */ - f_memcpy( pLEMBuffer, &pStack->pBlk[ BH_OVHD ], uiElmOvhd ); - - /* Free the block */ - rc = FSBlockFree( pDb, pStack->pSCache); - pStack->pSCache = NULL; - pStack->pBlk = NULL; - if( RC_BAD( rc)) - goto Exit; - - /* Pop stack - point to parent */ - pStack--; - /** - *** Modify the parent blocks last element marker (LEM) to point to - *** the new last block. THEN delete the previous element that - *** also points to the new last block. - **/ - /* Read the parent block */ - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, - pStack->uiBlkAddr, pStack))) - { - goto Exit; - } - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - { - goto Exit; - } - - /* Change where element points to in the last element marker (LEM) */ - - FSSetChildBlkAddr( BLK_ELM_ADDR( pStack, pStack->uiCurElm), - uiPrevBlk, pStack->uiElmOvhd ); - - /* FSBtPrevElm may return -1 which is NOT OK */ - if( RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack))) - { - rc = (rc == FERR_BT_END_OF_DATA) - ? RC_SET( FERR_BTREE_ERROR) - : rc ; - goto Exit; - } - /* Delete the element that points to the new last block */ - if( RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack))) - goto Exit; - - pStack++; - - /** - *** Read in the new last block - *** Move in the old LEM to the end of the block - *** Position pStack to LEM - **/ - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, uiPrevBlk, pStack))) - { - goto Exit; - } - - /* Log block before modifying */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - goto Exit; - - pBlk = pStack->pBlk; - /* Set the pStack elements */ - uiLastElm = pStack->uiBlkEnd; - pStack->uiCurElm = uiLastElm; - - /* Place the LEM (last element marker) in the block */ - f_memcpy( &pBlk[ uiLastElm ], pLEMBuffer, uiElmOvhd ); - - /* Set next block pointer to BT_END */ - UD2FBA( BT_END, &pBlk[ BH_NEXT_BLK ]); - - /* Adjust end pointers */ - pStack->uiBlkEnd = uiLastElm + uiElmOvhd; - UW2FBA( (FLMUINT16)pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]); - - *pStackRV = pStack; - } - } - /** - *** Deleted the LAST (but NOT ONLY) element in the block. - *** The parent block must have its current element changed to reflect - *** the new last element key in this block. The algoritm MUST insert - *** the next last element key and THEN delete the old key or - *** you may have a new root block which is your next block! - *** Comentary: Some b-tree algorithms have key markers that are shorter - *** in the non-leaf blocks. This right-end non-leaf trunctaion is a - *** very good idea, but ALL of the b-tree code has to conform to this - *** rule and it is not a trivial thing to support. - */ - else if( pStack->uiBlkEnd == pStack->uiCurElm) - { - pBlk = pStack->pBlk; - - /* Double check in case of corrupt this is not a right most block */ - if( FB2UD( &pBlk[ BH_NEXT_BLK ]) != BT_END) - { - rc = FSNewLastBlkElm( pDb, pLFile, &pStack, - FSNLBE_LESS | FSNLBE_POSITION ); - *pStackRV = pStack; - } - } - /** - *** Else - normal delete - everything should be correct and the - *** stack is positioned to the next element after the deleted element. - *** The pKeyBuf[] however, is NOT always set to be the current elms key. - *** Check to see if there is room to make a 3/2 combine & do it. - **/ - else if( pStack->uiBlkEnd <= - (FFILE_MIN_FILL * pDb->pFile->FileHdr.uiBlockSize / 100)) - { - rc = FSCombineBlks( pDb, pLFile, &pStack ); - *pStackRV = pStack; /* Stack may have changed */ - } -Exit: - if (bReleaseTmpCache) - { - ScaReleaseCache( pTmpSCache, FALSE); - } - return( rc); -} - -/**************************************************************************** -Desc: Delete the parent element from where you are at in the stack. -Notes: In the future we should either pin down the current block or - reread it in. -****************************************************************************/ -RCODE FSDelParentElm( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV - ) -{ - RCODE rc; - BTSK_p pStack = *pStackRV; /* Stack pointer */ - - pStack--; - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) - goto Exit; - - /* Ignore status value from FSBtScanTo - just position for delete */ - - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, (FLMUINT) 0))) - goto Exit; - - /* FSBlkBuildPKC( pStack, pStack->pKeyBuf ); - but does not build key from current element Much faster than scanTo() */ - - /* Call will position to the next element which pts to the next blk */ - - rc = FSBtDelete( pDb, pLFile, &pStack ); - -Exit: - pStack++; /* Go down the pStack to the original level */ - *pStackRV = pStack; - return( rc ); -} - -/**************************************************************************** -Desc: There is a new last block element, store key in parent and - remove current element if( uiFlags & FSNLBE_LESS or GREATER is set -Notes: Take note of the uiFlags - they can change what is done -****************************************************************************/ -RCODE FSNewLastBlkElm( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV, - FLMUINT uiFlags) // FSNLBE_GREATER, *_LESS, CK_COMBINE, POSITION or 0 -{ - RCODE rc; - BTSK_p pStack = *pStackRV; - FLMBYTE * pBlk = pStack->pBlk; - FLMBYTE * pCurElm; // Points to the current last element - FLMUINT uiOldCurElm = pStack->uiCurElm; - FLMUINT uiNextBlk = 0; - FLMUINT uiDomain = 0; // Domain is index reference range - FLMUINT uiElmLen; // Element length - FLMUINT uiKeyLen; - FLMUINT uiNewElmOvhd; - FLMUINT uiRefCount; - FLMBYTE * pKey; - FLMBYTE pElmBuffer[ MAX_KEY_SIZ + BNE_KEY_COUNTS_START + BNE_DOMAIN_LEN ]; - - uiNewElmOvhd = (pStack-1)->uiElmOvhd; - uiElmLen = uiNewElmOvhd; - - if( uiNewElmOvhd == BNE_DATA_OVHD) - { - pKey = pElmBuffer; - } - else - { - pElmBuffer[ BBE_PKC ] = 0; // Set PKC, DOMAIN to zero - pElmBuffer[ BBE_KL ] = 0; - pKey = pElmBuffer + uiNewElmOvhd; - - // Only update the counts if the inserting a key and not replacing. - if( uiNewElmOvhd == BNE_KEY_COUNTS_START) - { - if( RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, - pStack->uiBlkEnd, NULL, NULL, &uiRefCount))) - { - goto Exit; - } - UD2FBA( uiRefCount, &pElmBuffer[ BNE_CHILD_COUNT]); - } - } - - // Build the pElmBuffer[] with the new last key in the block - - FSSetChildBlkAddr( pElmBuffer, pStack->uiBlkAddr, uiNewElmOvhd); - - if( (uiNextBlk = FB2UD( &pBlk[ BH_NEXT_BLK ])) == BT_END) - { - if( uiNewElmOvhd == BNE_DATA_OVHD) - { - UD2FBA( 0xFFFFFFFF, pElmBuffer); - } - uiKeyLen = 0; - uiElmLen = uiNewElmOvhd; - goto no_domain; - } - // else - fall through - pStack->uiCurElm = pStack->uiBlkEnd;// Position past last element - FSBtPrevElm( pDb, pLFile, pStack ); // Build full key in pKeyBuf[] - uiKeyLen = pStack->uiKeyLen; - - // Copy the key - if( uiNewElmOvhd == BNE_DATA_OVHD) - { - flmCopyDrnKey( pElmBuffer, pStack->pKeyBuf); - } - else if( uiKeyLen) - { - f_memcpy( &pElmBuffer[ uiNewElmOvhd ], pStack->pKeyBuf, uiKeyLen ); - BBE_SET_KL( pElmBuffer, uiKeyLen ); - uiElmLen += uiKeyLen; - } - - - // If this is a boundqed index reference set then store DOMAIN - pCurElm = CURRENT_ELM( pStack ); - - uiDomain = ( pLFile->uiLfType == LF_INDEX) - ? FSGetDomain( &pCurElm, pStack->uiElmOvhd ) - : (FLMUINT) 0; - if( uiDomain) - { - BNE_SET_DOMAIN( pElmBuffer ); - pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain >> 16 ); - pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain >> 8 ); - pElmBuffer[ uiElmLen++ ] = (FLMBYTE) (uiDomain & 0xFF); - } - -no_domain: - - /** - *** Go to the parent block, insert new element - *** and delete the old last element in the block. - *** Pinning the current block is not suggested because - *** you could pin number of (levels - 1) blocks. - **/ - pStack--; - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) - goto Exit; - - /* If greater you should be positioned AFTER the matching element */ - if( pStack->uiBlkEnd > BH_OVHD) /* Don't call if NO elements */ - { - /* Set up the pStack elements for insert - passing keyLen sets up pStack*/ - - if( RC_BAD(rc = FSBtScanTo( pStack, pKey, uiKeyLen, uiDomain ))) - goto Exit; - } - else - pStack->uiPrevElmPKC = pStack->uiPKC = 0; - - /* Insert the element into the parent block - watch for splits! */ - if( RC_OK( rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuffer, uiElmLen))) - { - if( uiFlags & FSNLBE_LESS ) - { - /* Go to the next element, may read a new block! */ - if( RC_OK( rc = FSBtNextElm( pDb, pLFile, pStack ))) - { - if( RC_OK( rc = FSBtDelete( pDb, pLFile, &pStack ))) - { - /* Now position to the current element - back one */ - if( !(uiFlags & FSNLBE_POSITION)) - { - rc = FSBtPrevElm( pDb, pLFile, pStack ); - rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; - } - } - else - { - rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; - } - } - } - else if( uiFlags & FSNLBE_GREATER ) - { - if( RC_OK( rc = FSBtPrevElm( pDb, pLFile, pStack ))) - if( RC_OK(rc = FSBtDelete( pDb, pLFile, &pStack ))) - { - /* Position to the next element if flag is set */ - if( uiFlags & FSNLBE_POSITION) - { - rc = FSBtNextElm( pDb, pLFile, pStack ); - rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; - } - } - } - } -Exit: - /**----------------------------------------------------------- - *** Pop the pStack and position to next element - *** in the block that you expect to be positioned to. - *** You should be positioned to the correct parent element. - ***----------------------------------------------------------*/ - pStack++; - *pStackRV = pStack; /* Update callers pStack */ - if( RC_OK(rc)) - { - if( ( uiFlags & FSNLBE_POSITION ) && (uiNextBlk != BT_END )) - { - pStack->uiBlkAddr = uiNextBlk; - uiOldCurElm = BH_OVHD; - } - /* Read the next block and set pStack. */ - if( RC_OK( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) - { - pStack->uiCurElm = uiOldCurElm; /* Restore original curElm value */ - FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM ); - } - } - return( rc ); -} - -/*************************************************************************** -Desc: Delete the current element from a b-tree block without writing block. - The pStack must point to the next element after the deleted element. -Notes: Code handles deletion of an element at any level of the b-tree. -*****************************************************************************/ -RCODE FSBlkDelElm( - BTSK_p pStack /* Stack of variables for each level */ - ) -{ - RCODE rc; - FLMBYTE * pDelElm; /* Points to deleted element */ - FLMBYTE * pCurElm; /* Points to current elm to move down*/ - FLMBYTE * pBlk = pStack->pBlk;/* Points to block for speed */ - - FLMUINT uiCurElmOfs; /* Current (next) element's offset */ - FLMUINT uiDelElmPkc; /* # of carry bytes for deleted elm */ - FLMUINT uiCurElmPkc; /* Current element's Prev key count */ - FLMUINT uiCurElmKeyLen; /* Current element's key length */ - FLMUINT uiOldCurElm = pStack->uiCurElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; /* Element overhead for block */ - FLMINT iDelElmSize; /* Deleted element's size - signed !!*/ - FLMINT iPkcLost; /* Number bytes to expand for next elm*/ - /* MUST be a signed word value */ - - pDelElm = &pBlk[ pStack->uiCurElm ]; - - if( RC_OK(rc = FSBlkNextElm( pStack ))) - { - /** - *** Setup to remove what pDelElm is pointing to - *** This is NOT the last element in the block so move down - *** the rest of the block data. - **/ - uiCurElmOfs = pStack->uiCurElm; - iDelElmSize = (FLMINT)(uiCurElmOfs - uiOldCurElm); - pCurElm = &pBlk[ uiCurElmOfs ]; - - if( pStack->uiBlkType != BHT_NON_LEAF_DATA) - { - uiDelElmPkc = (FLMUINT)(BBE_GET_PKC( pDelElm )); - uiCurElmPkc = (FLMUINT)(BBE_GET_PKC( pCurElm )); - - /* If current element uses bytes from the deleted element... */ - if( uiCurElmPkc > uiDelElmPkc) - { - iPkcLost = (FLMINT)(uiCurElmPkc - uiDelElmPkc); - - /** Create the new deleted element and setup for the shiftN() below - *** moving pCurElm. - **/ - uiCurElmPkc -= iPkcLost; - uiCurElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm ) + iPkcLost); - - BBE_SET_PKC( pDelElm, uiCurElmPkc ); /* Clears all bits */ - BBE_SET_KL( pDelElm, uiCurElmKeyLen ); - *pDelElm |= (FLMBYTE)(BBE_IS_FIRST_LAST(pCurElm )); - - if( pStack->uiBlkType == BHT_LEAF) - { - BBE_SET_RL( pDelElm, BBE_GET_RL( pCurElm )); - } - else - { - f_memcpy( pDelElm + BNE_CHILD_BLOCK, - pCurElm + BNE_CHILD_BLOCK, uiElmOvhd - BNE_CHILD_BLOCK ); - } - - /* Adjust iDelElmSize & uiCurElmOfs to delete current element overhead */ - iDelElmSize -= iPkcLost; - uiCurElmOfs += uiElmOvhd; - - /* Move any extra bytes from the deleted element refered in curElm */ - f_memcpy( pDelElm + uiElmOvhd, &pStack->pKeyBuf[uiDelElmPkc], iPkcLost); - - /* Fall through and copy the rest of the block down */ - } - } - - /* Shift down - starting at pCurElm */ - shiftN( &pBlk[ uiCurElmOfs ], pStack->uiBlkEnd - uiCurElmOfs, - (FLMINT)(0 - iDelElmSize) ); - - pStack->uiBlkEnd -= iDelElmSize; - } - else if( rc == FERR_BT_END_OF_DATA) - { - rc = FERR_OK; - if( pStack->uiCurElm == pStack->uiBlkEnd) /* Deleted last element in blk */ - pStack->uiBlkEnd = uiOldCurElm; - else - { - /* Need to move the last element marker (LEM) down */ - /* This should only be used on leaf blocks - suggest using shiftN() */ - pBlk[ uiOldCurElm ] = BBE_FIRST_FLAG | BBE_LAST_FLAG; - pBlk[ uiOldCurElm + BBE_KL ] = pBlk[ uiOldCurElm + BBE_RL ] = 0; - pStack->uiBlkEnd = uiOldCurElm + uiElmOvhd; - } - } - else - goto Exit; - - /* Modify the element end offset & restore curElm & prevElm on pStack */ - UW2FBA( (FLMUINT16) pStack->uiBlkEnd, &pBlk[ BH_BLK_END ]); - pStack->uiCurElm = uiOldCurElm; -Exit: - return( rc ); -} - -/**************************************************************************** -Desc: Sets the parent element's child block value -****************************************************************************/ -void FSSetChildBlkAddr( - FLMBYTE * pElement, - FLMUINT uiBlkAddr, - FLMUINT uiBlkOvhd) -{ - FLMBYTE * pChildAddr; - - - if( uiBlkOvhd == BNE_KEY_START || uiBlkOvhd == BNE_KEY_COUNTS_START) - { - pChildAddr = pElement + BNE_CHILD_BLOCK; - UD2FBA( uiBlkAddr, pChildAddr ); - } - else if( uiBlkOvhd == BNE_DATA_OVHD) - { - pChildAddr = pElement + BNE_DATA_CHILD_BLOCK; - UD2FBA( uiBlkAddr, pChildAddr ); - } - return; -} +//------------------------------------------------------------------------- +// Desc: Delete element from b-tree block. +// Tabs: 3 +// +// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsdelelm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +/*************************************************************************** +Desc: Delete the current element from a b-tree block and write block. + The stack must point to the next element after the deleted element. + The next element could be in a different block so be careful. +Notes: The order of the high level if's is VERY important. + The order of changing the blocks is not important because of logging. +*****************************************************************************/ +RCODE FSBtDelete( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV) +{ + RCODE rc; + BTSK * pStack = *pStackRV; + SCACHE * pTmpSCache; + FLMBYTE * pBlk; + FLMBOOL bReleaseTmpCache = FALSE; + FLMUINT uiNextBlk; + FLMUINT uiPrevBlk; + FLMUINT uiLastElm; // Offset of last element in a block + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMBYTE pLEMBuffer[12]; // Last element marker buffer + + // Log block before modifying it + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + // If this is a non-leaf positioning index, update parent counts. + + if (pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) + { + if (pStack->uiLevel) + { + FLMUINT uiRefCount; + FLMBYTE* pElm = pStack->pBlk + pStack->uiCurElm; + + // Reduce the counts from the parent up. + + uiRefCount = FB2UD( &pElm[BNE_CHILD_COUNT]); + + if (RC_BAD( rc = FSChangeBlkCounts( pDb, pStack, + (FLMINT) (0 - uiRefCount)))) + { + goto Exit; + } + } + } + + if (RC_BAD( rc = FSBlkDelElm( pStack))) + { + goto Exit; + } + + // Take care of deletion of the ONLY element in the block. There is NO + // WAY this could be a root or right end block because of the last + // element marker (LEM) takes up 2 or 4 bytes + + if (pStack->uiBlkEnd == BH_OVHD) + { + + // Free up this empty block and fixup the NEXT/PREV links. + + uiNextBlk = FB2UD( &pStack->pBlk[BH_NEXT_BLK]); + + rc = FSBlockFixLinks( pDb, pLFile, pStack->pSCache); + + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + if (RC_BAD( rc)) + { + goto Exit; + } + + // Remove the element that pointed to this block + + if (RC_OK( rc = FSDelParentElm( pDb, pLFile, &pStack))) + { + pStack->uiBlkAddr = uiNextBlk; + + // Read the next block and set stack to point to next element + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, uiNextBlk, pStack))) + { + pStack->uiCurElm = BH_OVHD; + FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM); + } + } + + *pStackRV = pStack; + } + + // Deleting a RIGHT MOST B-tree block (along the right side). Check if + // only the LEM (last element marker) is left in the block. A block + // CANNOT contain just a LEM. Move the LEM and free the block. There are + // 3 cases to watch for: + // + // EMPTY B-TREE - free the root/block save next record in lfArea + // EMPTY ROOT - free root and goto child and make that root + // EMPTY BLOCK - cannot contain only a LEM - move to previous block + // + // Must not move last DRN Marker - there is no need to do this. + + else if ((FB2UD( &pStack->pBlk[BH_NEXT_BLK]) == BT_END) && + ((pStack->uiBlkEnd == BH_OVHD + uiElmOvhd))) + { + + // EMPTY B-TREE Level is not in the current LFILE version so check + // if the root block is the same as this block. + + if ((pStack->uiBlkType == BHT_LEAF) && + (pLFile->uiRootBlk == pStack->uiBlkAddr)) // Root is leaf + { + + // Return the empty root block to the system + // Code supports empty b-trees. We have gone back and forth on + // returning empty root blocks to the system. Setup stack for + // emtpy state and modify the LFILE on disk. The data record + // b-tree can NEVER be empty because of the next record DRN + // record should always hang around. ALL CALLING ROUTINES MUST + // CHECK for STACK->uiBlkAddr == BT_END. + + pStack->uiBlkAddr = BT_END; + { + + // Get the next DRN and save in the LFD + + FLMBYTE * ptr = &pStack->pBlk[BH_OVHD]; + + ptr += BBE_GETR_KL( ptr) + BBE_KEY; + pLFile->uiNextDrn = (FLMUINT) FB2UD( ptr); + } + + rc = FSBlockFree( pDb, pStack->pSCache); + + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + if (RC_BAD( rc)) + { + goto Exit; + } + + pLFile->uiRootBlk = BT_END; + rc = flmLFileWrite( pDb, pLFile); + } + + // EMPTY ROOT BLOCK Remove root block and set new root block to + // child. + + else if (pLFile->uiRootBlk == pStack->uiBlkAddr) + { + + // Obtain child block and set to lfArea to assign new root block + + uiNextBlk = FSChildBlkAddr( pStack); + + rc = FSBlockFree( pDb, pStack->pSCache); + + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + if (RC_BAD( rc)) + { + goto Exit; + } + + pLFile->uiRootBlk = uiNextBlk; + + if (RC_BAD( rc = flmLFileWrite( pDb, pLFile))) + { + goto Exit; + } + + // Assign the new root block + + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiNextBlk, NULL, + &pTmpSCache))) + { + goto Exit; + } + + bReleaseTmpCache = TRUE; + + if (RC_BAD( rc = ScaLogPhysBlk( pDb, &pTmpSCache))) + { + goto Exit; + } + + // Set the root block flag on this block & mark dirty + + BH_SET_ROOT_BLK( pTmpSCache->pucBlk); + ScaReleaseCache( pTmpSCache, FALSE); + bReleaseTmpCache = FALSE; + + // It is possible to add an element so that a new root block + // gets created AND THEN Deleted. Because of this + // the ROOT block in the stack MUST always be pStack[0]. The + // three lines below do this. + + shiftN( (FLMBYTE*) pStack + sizeof(BTSK), + sizeof(BTSK) * pStack->uiLevel, // think uiLevel + 1 - 1 + 0 - (sizeof(BTSK))); + + // We don't want a pointer to the same shared cache in two + // different elements of the pStack. NULL out the one that was + // moved down. + + (pStack + pStack->uiLevel + 1)->pSCache = NULL; + (pStack + pStack->uiLevel + 1)->pBlk = NULL; + pStack--; + *pStackRV = pStack; + + // Don't worry about positioning to the next element - root gone + } + else + { + // ONLY LAST ELEMENT MARKER (LEM) REMAINS (leaf or (non-leaf but + // NOT ROOT)). A block must NEVER contain only the last element + // marker (LEM). This may free up a leaf block or a non-leaf + // block but never a root block (root checks above.) This is the + // most complex case. Move the last element marker (LEM) to the + // end of the previous block. Be carefull to delete the correct + // element in the parent block. The algorithm states that there + // MUST ALWAYS be room to insert the LEM into a block without + // splitting that block. Because of logging the block + // modifications do not need to be flushed in a specific order to + // prevent corruption. + + uiPrevBlk = FB2UD( &pStack->pBlk[BH_PREV_BLK]); + + // Save the last element marker, may be a non-leaf element + + f_memcpy( pLEMBuffer, &pStack->pBlk[BH_OVHD], uiElmOvhd); + + // Free the block + + rc = FSBlockFree( pDb, pStack->pSCache); + + pStack->pSCache = NULL; + pStack->pBlk = NULL; + + if (RC_BAD( rc)) + { + goto Exit; + } + + // Pop stack - point to parent + + pStack--; + + // Modify the parent blocks last element marker (LEM) to point to + // the new last block. THEN delete the previous element that also + // points to the new last block. Read the parent block. + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + { + goto Exit; + } + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + // Change where element points to in the last element marker (LEM) + + FSSetChildBlkAddr( BLK_ELM_ADDR( pStack, pStack->uiCurElm), uiPrevBlk, + pStack->uiElmOvhd); + + // FSBtPrevElm may return -1 which is NOT OK + + if (RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack))) + { + rc = (rc == FERR_BT_END_OF_DATA) ? RC_SET( FERR_BTREE_ERROR) : rc; + goto Exit; + } + + // Delete the element that points to the new last block + + if (RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack))) + { + goto Exit; + } + + pStack++; + + // Read in the new last block Move in the old LEM to the end of + // the block Position pStack to LEM + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, uiPrevBlk, pStack))) + { + goto Exit; + } + + // Log block before modifying + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + pBlk = pStack->pBlk; + + // Set the pStack elements + + uiLastElm = pStack->uiBlkEnd; + pStack->uiCurElm = uiLastElm; + + // Place the LEM (last element marker) in the block + + f_memcpy( &pBlk[uiLastElm], pLEMBuffer, uiElmOvhd); + + // Set next block pointer to BT_END + + UD2FBA( BT_END, &pBlk[BH_NEXT_BLK]); + + // Adjust end pointers + + pStack->uiBlkEnd = uiLastElm + uiElmOvhd; + UW2FBA( (FLMUINT16) pStack->uiBlkEnd, &pBlk[BH_BLK_END]); + + *pStackRV = pStack; + } + } + + // Deleted the LAST (but not only) element in the block. The parent + // block must have its current element changed to reflect the new last + // element key in this block. The algoritm MUST insert the next last + // element key and THEN delete the old key or you may have a new root + // block which is your next block! Comentary: Some b-tree algorithms + // have key markers that are shorter in the non-leaf blocks. This + // right-end non-leaf trunctaion is a very good idea, but ALL of the + // b-tree code has to conform to this rule and it is not a trivial + // thing to support. + + else if (pStack->uiBlkEnd == pStack->uiCurElm) + { + pBlk = pStack->pBlk; + + // Double check in case of corrupt this is not a right most block + + if (FB2UD( &pBlk[BH_NEXT_BLK]) != BT_END) + { + rc = FSNewLastBlkElm( pDb, pLFile, &pStack, + FSNLBE_LESS | FSNLBE_POSITION); + *pStackRV = pStack; + } + } + + // Else - normal delete - everything should be correct and the stack is + // positioned to the next element after the deleted element. The + // pKeyBuf[] however, is NOT always set to be the current elms key. + // Check to see if there is room to make a 3/2 combine and do it. + + else if (pStack->uiBlkEnd <= + (FFILE_MIN_FILL * pDb->pFile->FileHdr.uiBlockSize / 100)) + { + rc = FSCombineBlks( pDb, pLFile, &pStack); + *pStackRV = pStack; // Stack may have changed + } + +Exit: + + if (bReleaseTmpCache) + { + ScaReleaseCache( pTmpSCache, FALSE); + } + + return (rc); +} + +/**************************************************************************** +Desc: Delete the parent element from where you are at in the stack. +Notes: In the future we should either pin down the current block or + reread it in. +****************************************************************************/ +RCODE FSDelParentElm( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV) +{ + RCODE rc; + BTSK * pStack = *pStackRV; + + pStack--; + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + { + goto Exit; + } + + // Ignore status value from FSBtScanTo - just position for delete + + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, (FLMUINT) 0))) + { + goto Exit; + } + + // Call will position to the next element which pts to the next blk + + rc = FSBtDelete( pDb, pLFile, &pStack); + +Exit: + + pStack++; // Go down the pStack to the original level + *pStackRV = pStack; + + return (rc); +} + +/**************************************************************************** +Desc: There is a new last block element, store key in parent and + remove current element if( uiFlags & FSNLBE_LESS or GREATER is set +Notes: Take note of the uiFlags - they can change what is done +****************************************************************************/ +RCODE FSNewLastBlkElm( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMUINT uiFlags) // FSNLBE_GREATER, *_LESS, CK_COMBINE, POSITION or 0 +{ + RCODE rc; + BTSK* pStack = *pStackRV; + FLMBYTE * pBlk = pStack->pBlk; + FLMBYTE * pCurElm; // Points to the current last element + FLMUINT uiOldCurElm = pStack->uiCurElm; + FLMUINT uiNextBlk = 0; + FLMUINT uiDomain = 0; // Domain is index reference range + FLMUINT uiElmLen; // Element length + FLMUINT uiKeyLen; + FLMUINT uiNewElmOvhd; + FLMUINT uiRefCount; + FLMBYTE * pKey; + FLMBYTE pElmBuffer[MAX_KEY_SIZ + BNE_KEY_COUNTS_START + BNE_DOMAIN_LEN]; + + uiNewElmOvhd = (pStack - 1)->uiElmOvhd; + uiElmLen = uiNewElmOvhd; + + if (uiNewElmOvhd == BNE_DATA_OVHD) + { + pKey = pElmBuffer; + } + else + { + pElmBuffer[BBE_PKC] = 0; // Set PKC, DOMAIN to zero + pElmBuffer[BBE_KL] = 0; + pKey = pElmBuffer + uiNewElmOvhd; + + // Only update the counts if the inserting a key and not replacing. + + if (uiNewElmOvhd == BNE_KEY_COUNTS_START) + { + if (RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, pStack->uiBlkEnd, + NULL, NULL, &uiRefCount))) + { + goto Exit; + } + + UD2FBA( uiRefCount, &pElmBuffer[BNE_CHILD_COUNT]); + } + } + + // Build the pElmBuffer[] with the new last key in the block + + FSSetChildBlkAddr( pElmBuffer, pStack->uiBlkAddr, uiNewElmOvhd); + + if ((uiNextBlk = FB2UD( &pBlk[BH_NEXT_BLK])) == BT_END) + { + if (uiNewElmOvhd == BNE_DATA_OVHD) + { + UD2FBA( 0xFFFFFFFF, pElmBuffer); + } + + uiKeyLen = 0; + uiElmLen = uiNewElmOvhd; + goto no_domain; + } + + // else - fall through + + pStack->uiCurElm = pStack->uiBlkEnd; // Position past last element + FSBtPrevElm( pDb, pLFile, pStack); // Build full key in pKeyBuf[] + uiKeyLen = pStack->uiKeyLen; + + // Copy the key + + if (uiNewElmOvhd == BNE_DATA_OVHD) + { + flmCopyDrnKey( pElmBuffer, pStack->pKeyBuf); + } + else if (uiKeyLen) + { + f_memcpy( &pElmBuffer[uiNewElmOvhd], pStack->pKeyBuf, uiKeyLen); + BBE_SET_KL( pElmBuffer, uiKeyLen); + uiElmLen += uiKeyLen; + } + + // If this is a boundqed index reference set then store DOMAIN + + pCurElm = CURRENT_ELM( pStack); + + uiDomain = (pLFile->uiLfType == LF_INDEX) + ? FSGetDomain( &pCurElm, pStack->uiElmOvhd) + : (FLMUINT) 0; + + if (uiDomain) + { + BNE_SET_DOMAIN( pElmBuffer); + + pElmBuffer[uiElmLen++] = (FLMBYTE) (uiDomain >> 16); + pElmBuffer[uiElmLen++] = (FLMBYTE) (uiDomain >> 8); + pElmBuffer[uiElmLen++] = (FLMBYTE) (uiDomain & 0xFF); + } + +no_domain: + + // Go to the parent block, insert new element and delete the old last + // element in the block. Pinning the current block is not suggested + // because you could pin number of (levels - 1) blocks. + + pStack--; + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + { + goto Exit; + } + + // If greater you should be positioned AFTER the matching element + + if (pStack->uiBlkEnd > BH_OVHD) // Don't call if NO elements + { + + // Set up the pStack elements for insert - passing keyLen sets up + // pStack + + if (RC_BAD( rc = FSBtScanTo( pStack, pKey, uiKeyLen, uiDomain))) + { + goto Exit; + } + } + else + { + pStack->uiPrevElmPKC = pStack->uiPKC = 0; + } + + // Insert the element into the parent block - watch for splits! + + if (RC_OK( rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuffer, uiElmLen))) + { + if (uiFlags & FSNLBE_LESS) + { + + // Go to the next element, may read a new block! + + if (RC_OK( rc = FSBtNextElm( pDb, pLFile, pStack))) + { + if (RC_OK( rc = FSBtDelete( pDb, pLFile, &pStack))) + { + + // Now position to the current element - back one + + if (!(uiFlags & FSNLBE_POSITION)) + { + rc = FSBtPrevElm( pDb, pLFile, pStack); + rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; + } + } + else + { + rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; + } + } + } + else if (uiFlags & FSNLBE_GREATER) + { + if (RC_OK( rc = FSBtPrevElm( pDb, pLFile, pStack))) + { + if (RC_OK( rc = FSBtDelete( pDb, pLFile, &pStack))) + { + + // Position to the next element if flag is set + + if (uiFlags & FSNLBE_POSITION) + { + rc = FSBtNextElm( pDb, pLFile, pStack); + rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; + } + } + } + } + } + +Exit: + + // Pop the pStack and position to next element in the block that you + // expect to be positioned to. You should be positioned to the correct + // parent element. + + pStack++; + *pStackRV = pStack; // Update caller's pStack + + if (RC_OK( rc)) + { + if ((uiFlags & FSNLBE_POSITION) && (uiNextBlk != BT_END)) + { + pStack->uiBlkAddr = uiNextBlk; + uiOldCurElm = BH_OVHD; + } + + // Read the next block and set pStack. + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + { + pStack->uiCurElm = uiOldCurElm; // Restore original curElm value + FSBlkBuildPKC( pStack, pStack->pKeyBuf, FSBBPKC_AT_CURELM); + } + } + + return (rc); +} + +/*************************************************************************** +Desc: Delete the current element from a b-tree block without writing block. + The pStack must point to the next element after the deleted element. +Notes: Code handles deletion of an element at any level of the b-tree. +*****************************************************************************/ +RCODE FSBlkDelElm( + BTSK * pStack) // Stack of variables for each level +{ + RCODE rc; + FLMBYTE* pDelElm; // Points to deleted element + FLMBYTE* pCurElm; // Points to current elm to move down + FLMBYTE* pBlk = pStack->pBlk; // Points to block for speed + + FLMUINT uiCurElmOfs; // Current (next) element's offset + FLMUINT uiDelElmPkc; // # of carry bytes for deleted elm + FLMUINT uiCurElmPkc; // Current element's Prev key count + FLMUINT uiCurElmKeyLen; // Current element's key length + FLMUINT uiOldCurElm = pStack->uiCurElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMINT iDelElmSize; // Deleted element's size + FLMINT iPkcLost; // Number bytes to expand for next elm + + pDelElm = &pBlk[pStack->uiCurElm]; + + if (RC_OK( rc = FSBlkNextElm( pStack))) + { + + // Setup to remove what pDelElm is pointing to. This is NOT the last + // element in the block so move down the rest of the block data. + + uiCurElmOfs = pStack->uiCurElm; + iDelElmSize = (FLMINT) (uiCurElmOfs - uiOldCurElm); + pCurElm = &pBlk[uiCurElmOfs]; + + if (pStack->uiBlkType != BHT_NON_LEAF_DATA) + { + uiDelElmPkc = (FLMUINT) (BBE_GET_PKC( pDelElm)); + uiCurElmPkc = (FLMUINT) (BBE_GET_PKC( pCurElm)); + + // If current element uses bytes from the deleted element... + + if (uiCurElmPkc > uiDelElmPkc) + { + iPkcLost = (FLMINT) (uiCurElmPkc - uiDelElmPkc); + + // Create the new deleted element and setup for the shiftN() + // below moving pCurElm. + + uiCurElmPkc -= iPkcLost; + uiCurElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm) + iPkcLost); + + BBE_SET_PKC( pDelElm, uiCurElmPkc); // Clears all bits + BBE_SET_KL( pDelElm, uiCurElmKeyLen); + *pDelElm |= (FLMBYTE) (BBE_IS_FIRST_LAST( pCurElm)); + + if (pStack->uiBlkType == BHT_LEAF) + { + BBE_SET_RL( pDelElm, BBE_GET_RL( pCurElm)); + } + else + { + f_memcpy( pDelElm + BNE_CHILD_BLOCK, pCurElm + BNE_CHILD_BLOCK, + uiElmOvhd - BNE_CHILD_BLOCK); + } + + // Adjust iDelElmSize and uiCurElmOfs to delete current element + // overhead + + iDelElmSize -= iPkcLost; + uiCurElmOfs += uiElmOvhd; + + // Move any extra bytes from the deleted element refered in + // curElm + + f_memcpy( pDelElm + uiElmOvhd, &pStack->pKeyBuf[uiDelElmPkc], + iPkcLost); + + // Fall through and copy the rest of the block down + + } + } + + // Shift down - starting at pCurElm + + shiftN( &pBlk[uiCurElmOfs], pStack->uiBlkEnd - uiCurElmOfs, + (FLMINT) (0 - iDelElmSize)); + + pStack->uiBlkEnd -= iDelElmSize; + } + else if (rc == FERR_BT_END_OF_DATA) + { + rc = FERR_OK; + if (pStack->uiCurElm == pStack->uiBlkEnd) + { + // Deleted last element in blk + + pStack->uiBlkEnd = uiOldCurElm; + } + else + { + + // Need to move the last element marker (LEM) down; + // This should only be used on leaf blocks + + pBlk[uiOldCurElm] = BBE_FIRST_FLAG | BBE_LAST_FLAG; + pBlk[uiOldCurElm + BBE_KL] = pBlk[uiOldCurElm + BBE_RL] = 0; + pStack->uiBlkEnd = uiOldCurElm + uiElmOvhd; + } + } + else + { + goto Exit; + } + + // Modify the element end offset & restore curElm & prevElm on pStack + + UW2FBA( (FLMUINT16) pStack->uiBlkEnd, &pBlk[BH_BLK_END]); + pStack->uiCurElm = uiOldCurElm; + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Sets the parent element's child block value +****************************************************************************/ +void FSSetChildBlkAddr( + FLMBYTE * pElement, + FLMUINT uiBlkAddr, + FLMUINT uiBlkOvhd) +{ + FLMBYTE * pChildAddr; + + if (uiBlkOvhd == BNE_KEY_START || uiBlkOvhd == BNE_KEY_COUNTS_START) + { + pChildAddr = pElement + BNE_CHILD_BLOCK; + UD2FBA( uiBlkAddr, pChildAddr); + } + else if (uiBlkOvhd == BNE_DATA_OVHD) + { + pChildAddr = pElement + BNE_DATA_CHILD_BLOCK; + UD2FBA( uiBlkAddr, pChildAddr); + } + + return; +} diff --git a/flaim/src/fsinselm.cpp b/flaim/src/fsinselm.cpp index 23e64fe..d5343e5 100644 --- a/flaim/src/fsinselm.cpp +++ b/flaim/src/fsinselm.cpp @@ -1,370 +1,382 @@ -//------------------------------------------------------------------------- -// Desc: Insert an element into a b-tree block. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsinselm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE FSBlkInsElm( - BTSK_p stk, - FLMBYTE * pElm, - FLMUINT uiElmLen, - FLMUINT uiBlkSize); - -/**************************************************************************** -Desc: Replace the current element with the input element. Both elements - must contain EXACTLY the same key. element[] must contain full key. - This gets complex if the input element causes a block split. - If so, then call FSBtDelete() and then call FSBtInsert() to split - the block. -Notes: This is NOT a recursive routine like FSBtInsert() is. Does not work - with non-leaf blocks! -****************************************************************************/ -RCODE FSBtReplace( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV, - FLMBYTE * pElement, - FLMUINT uiElmLen) -{ - RCODE rc; - BTSK_p pStack = *pStackRV; - FLMBYTE * pCurElm = CURRENT_ELM( pStack ); - FLMBYTE * pMovePoint; - FLMUINT uiCurRecOfs = (FLMUINT) BBE_REC_OFS( pCurElm); - FLMUINT uiCurRecLen = (FLMUINT) BBE_GET_RL( pCurElm); - - FLMUINT uiElmRecOfs = BBE_REC_OFS( pElement); - FLMUINT uiElmRecLen = BBE_GET_RL( pElement); - FLMUINT uiBytesFree; - FLMUINT uiArea; - FLMINT iDistance; - - /** - *** Set bsBlkEnd because of bug somewhere in the system. - *** This MUST be found as soon as possible. April 23, 1992 (SWP) - *** - **/ - pStack->uiBlkEnd = (FLMUINT) FB2UW( &pStack->pBlk[ BH_ELM_END ] ); - - uiBytesFree = pDb->pFile->FileHdr.uiBlockSize - - (pStack->uiBlkEnd + BBE_LEM_LEN); - - /* Code around signed compare problems to see if pElement will fit */ - if( (uiElmRecLen <= uiCurRecLen) || /* pElement len < curElm */ - (uiBytesFree >= (uiElmRecLen - uiCurRecLen))) /* Enough bytes free */ - { - /* Log the block before modifying it. */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - return( rc); - pCurElm = CURRENT_ELM( pStack); - - /* There is room to move things around in the block */ - iDistance = (FLMINT)(uiElmRecLen - uiCurRecLen); /* Could be positive or negitive*/ - uiArea = pStack->uiBlkEnd - (pStack->uiCurElm + uiCurRecOfs); - pMovePoint = &pCurElm[ uiCurRecOfs ]; - - if( uiElmRecLen < uiCurRecLen) /* Move UP <<-- the data in the block*/ - { - uiArea += iDistance; /* iDistance is negitive */ - pMovePoint -= iDistance; /* Add |distance| to pMovePoint */ - } - if( iDistance) - { - shiftN( pMovePoint, uiArea, iDistance ); - pStack->uiBlkEnd += iDistance; - UW2FBA( (FLMUINT16)pStack->uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END )); - } - /* Change the record length */ - BBE_SET_RL( pCurElm, BBE_GET_RL( pElement )); - - f_memcpy( &pCurElm[ uiCurRecOfs ], &pElement[ uiElmRecOfs ], uiElmRecLen); - } - else - { - /** - *** Remove the pElement and reinsert the pElement - *** The pElement better contain the entire key! ! ! - *** Must call FSBtDelete() because cannot just call - *** FSBlkDelElm() because SHOULD NOT call FSBtInsert() inserting - *** the last item in the block because you don't have a true - *** last pElement in the block that reflects the parent. - *** - *** Note: There may not be a FULL_STACK, if adding to the end. - *** FSBtDelete() should never get complex if adding to the end. - *** FSBtDelete() needs a FULL_STACK when deleting the last pElement - *** in the block. - **/ - - FLMUINT uiKeyLen = (FLMUINT) BBE_GET_KL( pElement); - - if( RC_BAD(rc = FSBtDelete( pDb, pLFile, &pStack ))) - return( rc ); - - /* Setup the pStack and bsKeyBuf[] for the insert */ - if( RC_BAD(rc = FSBtScanTo( pStack, &pElement[ BBE_KEY ], - uiKeyLen, 0))) - goto Exit; - - rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen ); - - *pStackRV = pStack; /* Stack could change on you ! ! ! */ - } -Exit: - return( rc ); -} - -/*************************************************************************** -Desc: Insert an pElement/key into a logical b-tree with split support. - Supports insertion of a new leaf element in the b-tree structure. - This is a complex recursive routine if a block needs to be split. - Inserts pElement[] between the previous and current elements. - Compress both pElement[] via pStack->uiPrevElmPKC and - current element by the difference of the current elements PKC and - pStack->wPKC. The PKC value of pElement[] must be ZERO! -*****************************************************************************/ -RCODE FSBtInsert( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV, - FLMBYTE * pElement, - FLMUINT uiElmLen) -{ - RCODE rc; - BTSK_p pStack = *pStackRV; - FLMUINT uiBlkSize = pDb->pFile->FileHdr.uiBlockSize; - - /* Log the block before modifying it. */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - goto Exit; - - /* See if there is enough room for the insertion in the block */ - - if( RC_OK( rc = FSBlkInsElm( pStack, pElement, uiElmLen, uiBlkSize))) - { - // If this is a non-leaf positioning index, update parent counts. - if( pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) - { - if( pStack->uiLevel) - { - rc = FSChangeBlkCounts( pDb, pStack, - FB2UD( &pElement[ BNE_CHILD_COUNT])); - } - } - } - else if( rc == FERR_BLOCK_FULL) - { - // No room to insert, split the block and reinsert */ - // FSBlkSplit() could make a recursive call back to FSBtInsert() - - rc = FSBlkSplit( pDb, pLFile, pStackRV, pElement, uiElmLen ); - } - -Exit: - return( rc); -} - -/*************************************************************************** -Desc: Insert an pElement (any type) into a block & compress the key. - Used only by FSBtInsert() and FSBlkSplit(). -Notes: Variables on the stack are used to save referencing the stack struct. - This will insert AFTER the last element in the block. This is - very complex code because of having regular and extended elements - and coding leaf and non-leaf elements within the same routine. -*****************************************************************************/ -FSTATIC RCODE FSBlkInsElm( - BTSK_p pStack, /* Stack holding all state info */ - FLMBYTE * pElement, /* The input element to insert */ - FLMUINT uiElmLen, /* Length of the element */ - FLMUINT uiBlkSize /* Size of the stack block */ - ) -{ - RCODE rc = RC_SET( FERR_BLOCK_FULL); /* Set default for no room */ - FLMBYTE * pCurElm; - FLMUINT uiShiftLen, uiShiftDist; /* Shift length and shift distance */ - FLMUINT uiNewElmPkc; /* Number of carry btyes for elm */ - FLMUINT uiNewElmLen = uiElmLen - pStack->uiPrevElmPKC; - /* Total length of elm */ - FLMUINT uiNewElmKeyLen; /* New element's key length */ - FLMUINT uiCurElmPkc; - FLMUINT uiCurElmKeyLen; - FLMUINT uiDiff; /* # of bytes to compress on curElm */ - FLMUINT uiBlkEnd = pStack->uiBlkEnd; /* Value of wBlkEnd */ - FLMUINT uiElmOvhd = pStack->uiElmOvhd;/* Element overhead */ - - uiNewElmPkc = pStack->uiPrevElmPKC; - uiNewElmKeyLen = BBE_GET_KL( pElement) - uiNewElmPkc; - - /** - *** If there is room, then compress current element and - *** insert new element. There must ALWAYS be room for the - *** last element marker (LEM). - *** "uiDiff" not in computation because of the complexity of - *** determining uiDiff before this compare; thus perform a - *** split that wasn't needed. This is OK because blocks should - *** have some breathing room anyway. - **/ - if( (uiBlkEnd + uiElmOvhd + uiNewElmLen) <= uiBlkSize) - { - /** - *** There is enough space in the block for the element. - *** Shift up higher elements compressing more the current element. - *** The key in keyBuf must be the curElm key and NOT prevElm! - *** pStack->wPKC & pStackPvElmPKC be valid from btScan() - **/ - pCurElm = CURRENT_ELM( pStack ); - - if( pStack->uiCurElm < uiBlkEnd ) - { - /** - *** uiDiff = additional bytes to compress on the current element. - *** There is no way diff can be negative (unless buggy code). - **/ - - if( uiElmOvhd != BNE_DATA_OVHD) - uiCurElmPkc = BBE_GET_PKC( pCurElm ); - else - uiCurElmPkc = 0; - - if( (uiDiff = (FLMUINT) (pStack->uiPKC - uiCurElmPkc)) >= MAX_KEY_SIZ) - { - return( RC_SET( FERR_BTREE_ERROR) ); - } - if( uiDiff == 0) - { - /** If there is no "diff" then current element does not - *** change. Move element down so many bytes and go on. - **/ - if( uiBlkEnd <= pStack->uiCurElm) - return( RC_SET( FERR_BTREE_ERROR) ); - shiftN( pCurElm, (FLMUINT)(uiBlkEnd - pStack->uiCurElm), uiNewElmLen ); - } - else - { - /** - *** Move from the current element down so many bytes to fit - *** the new element. - **/ - uiCurElmKeyLen = (FLMUINT) BBE_GET_KL( pCurElm ); - uiCurElmPkc += uiDiff; /* Compress more into PKC */ - /* Check if uiCurElmPkc has overflowed the max. value */ - if( uiCurElmPkc > BBE_PKC_MAX) - { - uiDiff -= uiCurElmPkc - BBE_PKC_MAX; /* Could set diff to 0 */ - uiCurElmPkc = BBE_PKC_MAX; - } - uiCurElmKeyLen -= uiDiff; /* Remove diff bytes from key */ - - /* Shift from the current element's key+diff to end of block */ - uiShiftLen = (uiBlkEnd - (pStack->uiCurElm + uiElmOvhd + uiDiff)); - uiShiftDist = (FLMUINT)(uiNewElmLen - uiDiff); - - /* Change block end value to compensate for uiDiff & curElm change*/ - uiBlkEnd -= uiDiff; - - /* Move up the current element in two statments to re-compress */ - shiftN( pCurElm + uiElmOvhd + uiDiff, uiShiftLen, uiShiftDist ); - - /* Output the new current element overhead */ - FSSetElmOvhd( pCurElm + uiNewElmLen, uiElmOvhd, uiCurElmPkc, - uiCurElmKeyLen, pCurElm ); - } - } - else - { - /** - *** Else insert at the end of the block. - *** These are special controlled inserts - *** "Danger: Don't try this at home" - **/ - ; /* BUG: Use to be uiElmLen -= uiNewElmPkc; */ - - if( pStack->uiCurElm != uiBlkEnd ) - { - return( RC_SET( FERR_BTREE_ERROR)); - } - } - - /* Create the new elements element overhead portion */ - FSSetElmOvhd( pCurElm, uiElmOvhd, uiNewElmPkc, uiNewElmKeyLen, pElement ); - - /* Move the part of the key and the rest of the record */ - if( uiElmLen - (uiElmOvhd + uiNewElmPkc)) - { - f_memcpy( pCurElm + uiElmOvhd, - &pElement[ uiElmOvhd + uiNewElmPkc ], - uiElmLen - (uiElmOvhd + uiNewElmPkc) ); - } - /* Reset the block end */ - uiBlkEnd += uiNewElmLen; - pStack->uiBlkEnd = uiBlkEnd; - - UW2FBA( uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END )); - rc = FERR_OK; - } - return( rc ); -} - -/**************************************************************************** -Desc: Set the element overhead given the needed values -****************************************************************************/ -FLMUINT FSSetElmOvhd( - FLMBYTE * pElement, - FLMUINT uiElmOvhd, - FLMUINT uiPkc, - FLMUINT uiKeyLen, - FLMBYTE * origElm - ) -{ - FLMBYTE byFirstByte; - - if( uiElmOvhd == BBE_KEY ) - { - byFirstByte = (FLMBYTE)((*origElm & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) + uiPkc); - if( uiKeyLen > 0xFF) - { - byFirstByte |= (FLMBYTE)(((uiKeyLen) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS); - } - *pElement++ = byFirstByte; - *pElement++ = (FLMBYTE) uiKeyLen; - *pElement++ = origElm[ BBE_RL ]; - } - else if( uiElmOvhd == BNE_DATA_OVHD) - { - f_memcpy( pElement, origElm, BNE_DATA_OVHD); - } - else - { - byFirstByte = (FLMBYTE)((*origElm & (BBE_FIRST_FLAG|BBE_LAST_FLAG)) + uiPkc); - if( uiKeyLen > 0xFF) - { - byFirstByte |= (FLMBYTE)(((uiKeyLen) >> BBE_KL_SHIFT_BITS) & BBE_KL_HBITS); - } - *pElement++ = byFirstByte; - *pElement++ = (FLMBYTE) uiKeyLen; - // Will copy 3 bytes for 2x dbs and 4 bytes ro 3x dbs. - f_memcpy( pElement, &origElm[ BNE_CHILD_BLOCK], - uiElmOvhd - BNE_CHILD_BLOCK ); - } - - return( uiElmOvhd ); -} +//------------------------------------------------------------------------- +// Desc: Insert an element into a b-tree block. +// Tabs: 3 +// +// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsinselm.cpp 12284 2006-01-19 14:54:14 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC RCODE FSBlkInsElm( + BTSK * stk, + FLMBYTE * pElm, + FLMUINT uiElmLen, + FLMUINT uiBlkSize); + +/**************************************************************************** +Desc: Replace the current element with the input element. Both elements + must contain EXACTLY the same key. element[] must contain full key. + This gets complex if the input element causes a block split. + If so, then call FSBtDelete() and then call FSBtInsert() to split + the block. +****************************************************************************/ +RCODE FSBtReplace( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMBYTE * pElement, + FLMUINT uiElmLen) +{ + RCODE rc; + BTSK * pStack = *pStackRV; + FLMBYTE * pCurElm = CURRENT_ELM( pStack); + FLMBYTE * pMovePoint; + FLMUINT uiCurRecOfs = (FLMUINT) BBE_REC_OFS( pCurElm); + FLMUINT uiCurRecLen = (FLMUINT) BBE_GET_RL( pCurElm); + FLMUINT uiElmRecOfs = BBE_REC_OFS( pElement); + FLMUINT uiElmRecLen = BBE_GET_RL( pElement); + FLMUINT uiBytesFree; + FLMUINT uiArea; + FLMINT iDistance; + + // Set bsBlkEnd because of bug somewhere in the system. This MUST be + // found as soon as possible. April 23, 1992 (SWP) + + pStack->uiBlkEnd = (FLMUINT) FB2UW( &pStack->pBlk[BH_ELM_END]); + uiBytesFree = pDb->pFile->FileHdr.uiBlockSize - + (pStack->uiBlkEnd + BBE_LEM_LEN); + + // Code around signed compare problems to see if pElement will fit + + if ((uiElmRecLen <= uiCurRecLen) || + (uiBytesFree >= (uiElmRecLen - uiCurRecLen))) + { + + // Log the block before modifying it. + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + return (rc); + } + + pCurElm = CURRENT_ELM( pStack); + + // There is room to move things around in the block + + iDistance = (FLMINT) (uiElmRecLen - uiCurRecLen); + uiArea = pStack->uiBlkEnd - (pStack->uiCurElm + uiCurRecOfs); + pMovePoint = &pCurElm[uiCurRecOfs]; + + if (uiElmRecLen < uiCurRecLen) + { + uiArea += iDistance; // iDistance is negitive + pMovePoint -= iDistance; // Add |distance| to pMovePoint + } + + if (iDistance) + { + shiftN( pMovePoint, uiArea, iDistance); + pStack->uiBlkEnd += iDistance; + UW2FBA( (FLMUINT16) pStack->uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END)); + } + + // Change the record length + + BBE_SET_RL( pCurElm, BBE_GET_RL( pElement)); + f_memcpy( &pCurElm[uiCurRecOfs], &pElement[uiElmRecOfs], uiElmRecLen); + } + else + { + FLMUINT uiKeyLen = (FLMUINT) BBE_GET_KL( pElement); + + if (RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack))) + { + return (rc); + } + + // Setup the pStack and bsKeyBuf[] for the insert + + if (RC_BAD( rc = FSBtScanTo( pStack, &pElement[BBE_KEY], uiKeyLen, 0))) + { + goto Exit; + } + + rc = FSBtInsert( pDb, pLFile, &pStack, pElement, uiElmLen); + *pStackRV = pStack; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Insert an pElement/key into a logical b-tree with split support. + Supports insertion of a new leaf element in the b-tree structure. +****************************************************************************/ +RCODE FSBtInsert( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMBYTE * pElement, + FLMUINT uiElmLen) +{ + RCODE rc; + BTSK * pStack = *pStackRV; + FLMUINT uiBlkSize = pDb->pFile->FileHdr.uiBlockSize; + + // Log the block before modifying it. + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + // See if there is enough room for the insertion in the block + + if (RC_OK( rc = FSBlkInsElm( pStack, pElement, uiElmLen, uiBlkSize))) + { + + // If this is a non-leaf positioning index, update parent counts. + + if (pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) + { + if (pStack->uiLevel) + { + rc = FSChangeBlkCounts( pDb, pStack, + FB2UD( &pElement[BNE_CHILD_COUNT])); + } + } + } + else if (rc == FERR_BLOCK_FULL) + { + + // No room to insert, split the block and reinsert + + rc = FSBlkSplit( pDb, pLFile, pStackRV, pElement, uiElmLen); + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Insert an pElement (any type) into a block & compress the key. +****************************************************************************/ +FSTATIC RCODE FSBlkInsElm( + BTSK * pStack, // Stack holding all state info + FLMBYTE * pElement, // The input element to insert + FLMUINT uiElmLen, // Length of the element + FLMUINT uiBlkSize) // Size of the stack block +{ + RCODE rc = RC_SET( FERR_BLOCK_FULL); + FLMBYTE * pCurElm; + FLMUINT uiShiftLen; + FLMUINT uiShiftDist; + FLMUINT uiNewElmPkc; + FLMUINT uiNewElmLen = uiElmLen - pStack->uiPrevElmPKC; + FLMUINT uiNewElmKeyLen; + FLMUINT uiCurElmPkc; + FLMUINT uiCurElmKeyLen; + FLMUINT uiDiff; + FLMUINT uiBlkEnd = pStack->uiBlkEnd; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + + uiNewElmPkc = pStack->uiPrevElmPKC; + uiNewElmKeyLen = BBE_GET_KL( pElement) - uiNewElmPkc; + + // If there is room, then compress current element and insert new + // element. There must ALWAYS be room for the last element marker + // (LEM). "uiDiff" not in computation because of the complexity of + // determining uiDiff before this compare; + // thus perform a split that wasn't needed. This is OK because blocks + // should have some breathing room anyway. + + if ((uiBlkEnd + uiElmOvhd + uiNewElmLen) <= uiBlkSize) + { + // There is enough space in the block for the element. Shift up + // higher elements compressing more the current element. The key in + // keyBuf must be the curElm key and NOT prevElm! pStack->wPKC and + // pStackPvElmPKC be valid from btScan() + + pCurElm = CURRENT_ELM( pStack); + + if (pStack->uiCurElm < uiBlkEnd) + { + + // uiDiff = additional bytes to compress on the current element. + // There is no way diff can be negative (unless buggy code). + + if (uiElmOvhd != BNE_DATA_OVHD) + { + uiCurElmPkc = BBE_GET_PKC( pCurElm); + } + else + { + uiCurElmPkc = 0; + } + + if ((uiDiff = (FLMUINT) (pStack->uiPKC - uiCurElmPkc)) >= MAX_KEY_SIZ) + { + return (RC_SET( FERR_BTREE_ERROR)); + } + + if (uiDiff == 0) + { + + // If there is no "diff" then current element does not change. + // Move element down so many bytes and go on. + + if (uiBlkEnd <= pStack->uiCurElm) + { + return (RC_SET( FERR_BTREE_ERROR)); + } + + shiftN( pCurElm, (FLMUINT) (uiBlkEnd - pStack->uiCurElm), + uiNewElmLen); + } + else + { + + // Move from the current element down so many bytes to fit the + // new element. + + uiCurElmKeyLen = (FLMUINT) BBE_GET_KL( pCurElm); + uiCurElmPkc += uiDiff; + + // Check if uiCurElmPkc has overflowed the max. value + + if (uiCurElmPkc > BBE_PKC_MAX) + { + uiDiff -= uiCurElmPkc - BBE_PKC_MAX; // Could set diff to 0 + uiCurElmPkc = BBE_PKC_MAX; + } + + uiCurElmKeyLen -= uiDiff; // Remove diff bytes + + // Shift from the current element's key+diff to end of block + + uiShiftLen = (uiBlkEnd - (pStack->uiCurElm + uiElmOvhd + uiDiff)); + uiShiftDist = (FLMUINT) (uiNewElmLen - uiDiff); + + // Change block end value to compensate for uiDiff and curElm + // change + + uiBlkEnd -= uiDiff; + + // Move up the current element in two statments to re-compress + + shiftN( pCurElm + uiElmOvhd + uiDiff, uiShiftLen, uiShiftDist); + + // Output the new current element overhead + + FSSetElmOvhd( pCurElm + uiNewElmLen, uiElmOvhd, uiCurElmPkc, + uiCurElmKeyLen, pCurElm); + } + } + else + { + + // Else insert at the end of the block. These are special + // controlled inserts + + if (pStack->uiCurElm != uiBlkEnd) + { + return (RC_SET( FERR_BTREE_ERROR)); + } + } + + // Create the new elements element overhead portion + + FSSetElmOvhd( pCurElm, uiElmOvhd, uiNewElmPkc, uiNewElmKeyLen, pElement); + + // Move the part of the key and the rest of the record + + if (uiElmLen - (uiElmOvhd + uiNewElmPkc)) + { + f_memcpy( pCurElm + uiElmOvhd, &pElement[uiElmOvhd + uiNewElmPkc], + uiElmLen - (uiElmOvhd + uiNewElmPkc)); + } + + // Reset the block end + + uiBlkEnd += uiNewElmLen; + pStack->uiBlkEnd = uiBlkEnd; + + UW2FBA( uiBlkEnd, BLK_ELM_ADDR( pStack, BH_ELM_END)); + rc = FERR_OK; + } + + return (rc); +} + +/**************************************************************************** +Desc: Set the element overhead given the needed values +****************************************************************************/ +FLMUINT FSSetElmOvhd( + FLMBYTE * pElement, + FLMUINT uiElmOvhd, + FLMUINT uiPkc, + FLMUINT uiKeyLen, + FLMBYTE * origElm) +{ + FLMBYTE byFirstByte; + + if (uiElmOvhd == BBE_KEY) + { + byFirstByte = (FLMBYTE) ((*origElm & + (BBE_FIRST_FLAG | BBE_LAST_FLAG)) + uiPkc); + if (uiKeyLen > 0xFF) + { + byFirstByte |= (FLMBYTE) (((uiKeyLen) >> BBE_KL_SHIFT_BITS) & + BBE_KL_HBITS); + } + + *pElement++ = byFirstByte; + *pElement++ = (FLMBYTE) uiKeyLen; + *pElement++ = origElm[BBE_RL]; + } + else if (uiElmOvhd == BNE_DATA_OVHD) + { + f_memcpy( pElement, origElm, BNE_DATA_OVHD); + } + else + { + byFirstByte = (FLMBYTE) ((*origElm & + (BBE_FIRST_FLAG | BBE_LAST_FLAG)) + uiPkc); + + if (uiKeyLen > 0xFF) + { + byFirstByte |= (FLMBYTE) (((uiKeyLen) >> + BBE_KL_SHIFT_BITS) & BBE_KL_HBITS); + } + + *pElement++ = byFirstByte; + *pElement++ = (FLMBYTE) uiKeyLen; + + // Will copy 3 bytes for 2x dbs and 4 bytes ro 3x dbs. + + f_memcpy( pElement, &origElm[BNE_CHILD_BLOCK], + uiElmOvhd - BNE_CHILD_BLOCK); + } + + return (uiElmOvhd); +} diff --git a/flaim/src/fslfileu.cpp b/flaim/src/fslfileu.cpp index 12452dc..fbcaf60 100644 --- a/flaim/src/fslfileu.cpp +++ b/flaim/src/fslfileu.cpp @@ -46,7 +46,7 @@ FSTATIC RCODE flmFreeContainerBlocks( LFILE * pLFile); FSTATIC RCODE flmFreeIndexBlocks( - FDB_p pDb, + FDB * pDb, LFILE * pLFile, FLMBOOL bInvalidateLFile); @@ -596,8 +596,8 @@ RCODE flmLFileIndexBuild( // Don't index now. The RFL function INDEX_SET will // generate index keys. - if( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_3_02 && - pDb->pFile->FileHdr.uiVersionNum <= FLM_VER_4_51) + if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_3_02 && + pDb->pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51) { if( RC_BAD( rc = flmSetIxTrackerInfo( pDb, pIxd->uiIndexNum, 1, 0, TRANS_ID_OFFLINE, FALSE))) @@ -825,7 +825,7 @@ RCODE flmIndexSetOfRecords( if (!pIxd->uiContainerNum && !uiContainerNum) { - flmAssert( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_50); + flmAssert( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_50); bDoAllContainers = TRUE; } @@ -843,7 +843,8 @@ RCODE flmIndexSetOfRecords( #ifdef FLM_DEBUG if( !pIxd->uiContainerNum) { - flmAssert( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_50); + flmAssert( pDb->pFile->FileHdr.uiVersionNum >= + FLM_FILE_FORMAT_VER_4_50); } #endif @@ -1149,7 +1150,7 @@ RCODE flmIndexSetOfRecords( // Send indexing completed event notification - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIxNum, @@ -1284,7 +1285,7 @@ Exit: if( !pThread) { - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIxNum, @@ -1295,7 +1296,7 @@ Exit: } else if( uiLastDrn) { - if( gv_FlmSysData.EventHdrs[ F_EVENT_UPDATES].pEventCBList) + if( gv_FlmSysData.UpdateEvents.pEventCBList) { flmDoEventCallback( F_EVENT_UPDATES, F_EVENT_INDEXING_COMPLETE, (void *)uiIxNum, @@ -1463,7 +1464,7 @@ RCODE flmSetIxTrackerInfo( goto Exit; } - if( pDb->pFile->FileHdr.uiVersionNum >= FLM_VER_4_51) + if( pDb->pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_51) { FLMUINT32 ui32IndexSuspended = bSuspended ? 1 : 0; if( RC_BAD( rc = flmModField( pRecord, FLM_STATE_TAG, @@ -2260,7 +2261,7 @@ FSTATIC RCODE flmFreeIndexBlocks( goto Exit; } - if( pFile->FileHdr.uiVersionNum <= FLM_VER_4_51) + if( pFile->FileHdr.uiVersionNum <= FLM_FILE_FORMAT_VER_4_51) { // Background deletion is not supported. Must delete // the blocks of the LFILE now. @@ -2701,7 +2702,7 @@ FSTATIC RCODE flmRetrieveTrackerRec( POOL readPool; LFILE * pTrackerLFile; BTSK stackBuf[ BH_MAX_LEVELS]; - BTSK_p pStack = &stackBuf[ 0]; + BTSK * pStack = &stackBuf[ 0]; FLMBYTE ucKeyBuf[ DIN_KEY_SIZ]; FLMBYTE ucSearchKey[ DIN_KEY_SIZ]; FlmRecord * pTrackerRec = NULL; diff --git a/flaim/src/fsnext.cpp b/flaim/src/fsnext.cpp index 988b7ad..21149e0 100644 --- a/flaim/src/fsnext.cpp +++ b/flaim/src/fsnext.cpp @@ -1,435 +1,477 @@ -//------------------------------------------------------------------------- -// Desc: Traverse to next element in a b-tree. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsnext.cpp 12321 2006-01-19 15:55:00 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/** -*** The SENLenArray[] is used to find the length of an unsigned SEN value. -**/ - -FLMBYTE SENLenArray[] - = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 0 }; - - -/**************************************************************************** -Desc: Go to the next data record given a stack. -****************************************************************************/ -RCODE FSNextRecord( - FDB_p pDb, - LFILE * pLFile, - BTSK * pStack) -{ - RCODE rc; - FLMBYTE * pCurElm; - - pStack->uiFlags = NO_STACK; - pStack->uiKeyBufSize = DIN_KEY_SIZ; - pCurElm = CURRENT_ELM( pStack); - - // Scan over the current record till 'does continue' flag NOT set - - while( BBE_NOT_LAST( pCurElm)) - { - // First go to the next element - rc may return FERR_BT_END_OF_DATA - if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack))) - { - if( rc == FERR_BT_END_OF_DATA) // b-tree corrupt if FERR_BT_END_OF_DATA - rc = RC_SET( FERR_BTREE_ERROR); - goto Exit; - } - pCurElm = CURRENT_ELM( pStack); - } - - // Now go to the next element. - - if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack))) - { - if( rc == FERR_BT_END_OF_DATA) - rc = RC_SET( FERR_EOF_HIT); - goto Exit; - } - -Exit: - return( rc); -} - - -/**************************************************************************** -Desc: Go to the next reference given a valid cursor. -Out: cursor updated if there is a next reference -Return: RCODE FERR_OK | FERR_BT_END_OF_DATA (0xFFFF) or error -TODO: First call to DINNextVal() should be replaced with DINSkipVal() -****************************************************************************/ -RCODE FSRefNext( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p pStack, /* Small stack to hold btree variables*/ - DIN_STATE_p pState, /* Holds offset, one run number, etc.*/ - FLMUINT * puiDin) /* Last din used and returns din */ -{ - RCODE rc; /* Return code */ - FLMBYTE * pCurRef; /* Points to current reference */ - FLMBYTE * pCurElm; /* Points to current element */ - FLMUINT uiRefSize; /* Size of the record portion in the elm*/ - FLMUINT uiHasDomain; /* If value then there is a next elm */ - FLMUINT uiDin = *puiDin; - DIN_STATE savedState; - - /* Point to the start of the current reference */ - pCurRef = pCurElm = CURRENT_ELM( pStack ); - uiHasDomain = FSGetDomain( &pCurRef, pStack->uiElmOvhd ); - uiRefSize = (FLMUINT)(BBE_GET_RL(pCurElm) - - (pCurRef - BBE_REC_PTR(pCurElm))); - - if( pState->uiOffset < uiRefSize ) - DINNextVal( pCurRef, pState);/* Not at end, read current value */ - - if( pState->uiOffset >= uiRefSize) - { - /** - *** Read in the next element if a domain was found else FERR_BT_END_OF_DATA - **/ - if( !uiHasDomain) /* May use the DOES_CONT element flag */ - return( FERR_BT_END_OF_DATA ); - - if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack ))) - return( rc ); - - uiDin = FSRefFirst( pStack, pState, &uiHasDomain ); - } - else - { - /* Don't move the pState, stay put and get the next DIN value */ - savedState.uiOffset = pState->uiOffset; - savedState.uiOnes = pState->uiOnes; - - uiDin -= DINNextVal( pCurRef, &savedState ); - } - - *puiDin = uiDin; - return( FERR_OK ); -} - -/**************************************************************************** -Desc: Search for and position to the current (or next) reference asked for -Out: Updates the state for the position of *puiDin - Updates puiDin to be the matching or next LESS than *puiDin input. -Return: FERR_OK, FERR_FAILURE -positioned to next reference or past last ref -****************************************************************************/ -RCODE FSRefSearch( - BTSK_p pStack, /* Small stack to hold btree variables*/ - DIN_STATE_p pState, /* Holds offset, one run number, etc.*/ - FLMUINT * puiDin) /* Target uiDin & value that is returned*/ -{ - FLMBYTE * pCurRef; /* Points to current reference */ - FLMBYTE * pCurElm; /* Points to current element */ - FLMUINT uiRefSize; /* Size of the reference set */ - FLMUINT uiLastOffset; /* Last offset - used to back up */ - FLMUINT uiDelta; - FLMUINT uiTargetDin = *puiDin; - FLMUINT uiDin; - FLMUINT uiOneRuns; - DIN_STATE tempState; /* State information */ - FLMBYTE byValue; - - - /* Point to the start of the current reference */ - pCurRef = pCurElm = CURRENT_ELM( pStack ); - - (void) FSGetDomain( &pCurRef, pStack->uiElmOvhd ); - uiRefSize = (FLMUINT)(BBE_GET_RL(pCurElm) - - (pCurRef - BBE_REC_PTR(pCurElm))); - - RESET_DINSTATE_p( pState ); - RESET_DINSTATE( tempState ); - - uiLastOffset = tempState.uiOffset; - uiDin = DINNextVal( pCurRef, &tempState ); /* Read first reference */ - - if( uiDin > uiTargetDin) - { - while( tempState.uiOffset < uiRefSize ) - { - /* Get the current byte to see what kind of item it is */ - byValue = (FLMBYTE) pCurRef[ uiLastOffset = tempState.uiOffset ]; - - if( DIN_IS_REAL_ONE_RUN(byValue)) - { - uiOneRuns = DINOneRunVal( pCurRef, &tempState ); - /** - *** Check if one run is includes the target din - **/ - if( (uiDin - uiOneRuns) <= uiTargetDin) - { - uiOneRuns = (uiDin - uiTargetDin) - 1; /* Save state -zero based */ - pState->uiOffset = uiLastOffset; - pState->uiOnes = uiOneRuns; - uiDin = uiTargetDin; - break; - } - uiDin -= uiOneRuns; - } - else - { - uiDelta = DINNextVal( pCurRef, &tempState ); - /** - *** Check if next din value is equal or less than target din - **/ - - uiDin -= uiDelta; - if( uiDin <= uiTargetDin) - { - pState->uiOffset = uiLastOffset; - break; - } - } - } - pState->uiOffset = uiLastOffset; - } - - *puiDin = uiDin; - return( (uiDin == uiTargetDin) - ? FERR_OK - : RC_SET( FERR_FAILURE)); -} - -/**************************************************************************** -Desc: Get the next DIN value from the DIN set. Position to the next DIN - value within the set. -Out: state updated to point past the value returned. -Return: DIN value -Future: Could save the one run value as part of the state so we don't read - every time this is called to go to the next one run state. -****************************************************************************/ -FLMUINT DINNextVal( - FLMBYTE * puiDin, - DIN_STATE_p pState) -{ - FLMBYTE * pOneRun; - FLMBYTE * pCurDin; - FLMUINT uiTemp = 0; - FLMUINT uiOneRun; - FLMUINT uiStateOneRuns; - - pCurDin = puiDin + pState->uiOffset; - - switch( SENValLen( pCurDin)) - { - case 0: - uiOneRun = 0; - pOneRun = pCurDin + 1; /* Set for possible return past 1 run */ - if( *pCurDin < DIN_ONE_RUN_HV) - { - uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2; /* Min value is 2 */ - } - else if( *pCurDin == DIN_ONE_RUN_HV) - { - uiOneRun = SENNextVal( &pOneRun); - } - else - { - /* Invalid code found ! ! ! ERROR */ - pCurDin++; - uiTemp = 0; - break; - } - /* Handle the position of the one run */ - uiStateOneRuns = pState->uiOnes; - - uiTemp = 1; /* return 1 unless on last one run value */ - uiStateOneRuns++; /* Increment to next one run */ - if( uiStateOneRuns >= uiOneRun) /* If past the end... */ - { - pCurDin = pOneRun; /* Set to after the one runs */ - uiStateOneRuns = 0; /* This sets state of ones to zero*/ - } - pState->uiOnes = uiStateOneRuns; - break; - - case 1: - uiTemp = *pCurDin++; - break; - - case 2: - uiTemp = ((FLMUINT) (SEN_2B_MASK & *pCurDin++)) << 8; - goto DINNV_1_byte; - - case 3: - uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pCurDin++))) << 16; - goto DINNV_2_bytes; - - case 4: - uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pCurDin++))) << 24; - goto DINNV_3_bytes; - - case 5: - pCurDin++; - uiTemp = ((FLMUINT) *pCurDin++) << 24; -DINNV_3_bytes: - uiTemp += ((FLMUINT) *pCurDin++) << 16; -DINNV_2_bytes: - uiTemp += ((FLMUINT) *pCurDin++) << 8; -DINNV_1_byte: - uiTemp += *pCurDin++; - break; - } - /* Set the offset to point to the next reference */ - - pState->uiOffset = (FLMUINT) (pCurDin - puiDin); - - return( uiTemp); -} - -/**************************************************************************** -Desc: Get the next one run value and update the state information -Out: state updated to point to next DIN value -Return: value of one run - zero if bad code -****************************************************************************/ -FLMUINT DINOneRunVal( - FLMBYTE * puiDin, - DIN_STATE_p pState) -{ - FLMBYTE * pOneRun; - FLMBYTE * pCurDin; - FLMUINT uiOneRun; - - pCurDin = puiDin + pState->uiOffset; - - if( *pCurDin == 1) - { - pState->uiOffset++; - uiOneRun = 1; - } - else - { - uiOneRun = 0; - pOneRun = pCurDin + 1; - if( *pCurDin < DIN_ONE_RUN_HV) - { - uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2; /* Min value is 2 */ - } - else if( *pCurDin == DIN_ONE_RUN_HV) - { - uiOneRun = SENNextVal( &pOneRun); - } - else - { - uiOneRun = 0; /* Invald code found */ - } - - pState->uiOffset = (FLMUINT) (pOneRun - puiDin); - } - return( uiOneRun); -} - -/*************************************************************************** -Desc: Return the next SEN value. Update and return input pointer. - Does not support DIN, or signed SEN values. -Out: pSenRV points to the next SEN value -Return: value of SEN -Notes: goto's used to save code space and help get this faster -Future: This would be real nice in in-line assembly -*****************************************************************************/ -FLMUINT SENNextVal( - FLMBYTE ** pSenRV) /* Points to a SEN pointer */ -{ - FLMUINT uiTemp; - FLMBYTE * pSen = *pSenRV; - - switch( SENValLen( pSen)) - { - case 1: - uiTemp = *pSen; - break; - - case 2: - uiTemp = ((FLMUINT) (SEN_2B_MASK & *pSen++)) << 8; - uiTemp += *pSen; - break; - - case 3: - uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pSen++))) << 16; - goto SENNV_2_bytes; - - case 4: - uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pSen++))) << 24; - goto SENNV_3_bytes; - - case 5: - pSen++; - uiTemp = ((FLMUINT) *pSen++) << 24; -SENNV_3_bytes: - uiTemp += ((FLMUINT) *pSen++) << 16; -SENNV_2_bytes: - uiTemp += ((FLMUINT) *pSen++) << 8; - uiTemp += *pSen; - break; - - default: - uiTemp = 0; - break; - } - - *pSenRV = pSen + 1; - - return( uiTemp); -} - -/**************************************************************************** -Desc: Get the domain from a block type and current element pointer -Out: *curElmRV points after the DOMAIN area if present -Return: domain value or zero if DOMAIN is not represented -****************************************************************************/ -FLMUINT FSGetDomain( - FLMBYTE ** curElmRV, // [in] curElm, [out] pFirstRef - FLMUINT uiElmOvhd) -{ - FLMUINT uiDinDomain = 0; // Default return value - FLMBYTE * curElm = *curElmRV; - - if( uiElmOvhd == BBE_KEY ) // Leaf Block - { - // Normal leaf block, parse element to see if DOMAIN flag is present - curElm += BBE_REC_OFS( curElm ); - - // Skip past the update version information - if( *curElm == SEN_DOMAIN) - { - curElm++; - uiDinDomain = SENNextVal( &curElm ); - } - } - else // Non-leaf block - { - if( BNE_IS_DOMAIN( curElm )) - { - curElm += BBE_GET_KL( curElm ) + uiElmOvhd; - uiDinDomain = ((FLMUINT) *curElm++) << 16; - uiDinDomain |= ((FLMUINT16) *curElm++) << 8; - uiDinDomain |= *curElm++; - } - } - *curElmRV = curElm; - return( uiDinDomain ); -} +//------------------------------------------------------------------------- +// Desc: Traverse to next element in a b-tree. +// Tabs: 3 +// +// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsnext.cpp 12321 2006-01-19 15:55:00 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +// The SENLenArray[] is used to find the length of an unsigned SEN value. + +FLMBYTE SENLenArray[] = { 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 4, 5, 0 }; + +/*************************************************************************** +Desc: Go to the next data record given a stack. +***************************************************************************/ +RCODE FSNextRecord( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack) +{ + RCODE rc = FERR_OK; + FLMBYTE * pCurElm; + + pStack->uiFlags = NO_STACK; + pStack->uiKeyBufSize = DIN_KEY_SIZ; + pCurElm = CURRENT_ELM( pStack); + + // Scan over the current record till 'does continue' flag NOT set + + while (BBE_NOT_LAST( pCurElm)) + { + + // First go to the next element - rc may return FERR_BT_END_OF_DATA + + if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) + { + if (rc == FERR_BT_END_OF_DATA) + { + rc = RC_SET( FERR_BTREE_ERROR); + } + + goto Exit; + } + + pCurElm = CURRENT_ELM( pStack); + } + + // Now go to the next element. + + if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) + { + if (rc == FERR_BT_END_OF_DATA) + { + rc = RC_SET( FERR_EOF_HIT); + } + + goto Exit; + } + +Exit: + + return (rc); +} + +/*************************************************************************** +Desc: Go to the next reference given a valid cursor. +***************************************************************************/ +RCODE FSRefNext( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack, + DIN_STATE * pState, + FLMUINT * puiDin) +{ + RCODE rc = FERR_OK; + FLMBYTE * pCurRef; + FLMBYTE * pCurElm; + FLMUINT uiRefSize; + FLMUINT uiHasDomain; + FLMUINT uiDin = *puiDin; + DIN_STATE savedState; + + // Point to the start of the current reference + + pCurRef = pCurElm = CURRENT_ELM( pStack); + uiHasDomain = FSGetDomain( &pCurRef, pStack->uiElmOvhd); + uiRefSize = (FLMUINT) (BBE_GET_RL( pCurElm) - + (pCurRef - BBE_REC_PTR( pCurElm))); + + if (pState->uiOffset < uiRefSize) + { + DINNextVal( pCurRef, pState); + } + + if (pState->uiOffset >= uiRefSize) + { + + // Read in the next element if a domain was found else + // FERR_BT_END_OF_DATA + + if (!uiHasDomain) + { + // May use the DOES_CONT element flag + + return (FERR_BT_END_OF_DATA); + } + + if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) + { + return (rc); + } + + uiDin = FSRefFirst( pStack, pState, &uiHasDomain); + } + else + { + + // Don't move the pState, stay put and get the next DIN value + + savedState.uiOffset = pState->uiOffset; + savedState.uiOnes = pState->uiOnes; + + uiDin -= DINNextVal( pCurRef, &savedState); + } + + *puiDin = uiDin; + return (FERR_OK); +} + +/*************************************************************************** +Desc: Search for and position to the current (or next) reference +***************************************************************************/ +RCODE FSRefSearch( + BTSK * pStack, + DIN_STATE * pState, + FLMUINT * puiDin) +{ + FLMBYTE * pCurRef; + FLMBYTE * pCurElm; + FLMUINT uiRefSize; + FLMUINT uiLastOffset; + FLMUINT uiDelta; + FLMUINT uiTargetDin = *puiDin; + FLMUINT uiDin; + FLMUINT uiOneRuns; + DIN_STATE tempState; + FLMBYTE byValue; + + // Point to the start of the current reference + + pCurRef = pCurElm = CURRENT_ELM( pStack); + (void) FSGetDomain( &pCurRef, pStack->uiElmOvhd); + uiRefSize = (FLMUINT) (BBE_GET_RL( pCurElm) - + (pCurRef - BBE_REC_PTR( pCurElm))); + + RESET_DINSTATE_p( pState); + RESET_DINSTATE( tempState); + + uiLastOffset = tempState.uiOffset; + uiDin = DINNextVal( pCurRef, &tempState); + + if (uiDin > uiTargetDin) + { + while (tempState.uiOffset < uiRefSize) + { + + // Get the current byte to see what kind of item it is + + byValue = (FLMBYTE) pCurRef[uiLastOffset = tempState.uiOffset]; + + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + uiOneRuns = DINOneRunVal( pCurRef, &tempState); + + // Check if one run is includes the target din + + if ((uiDin - uiOneRuns) <= uiTargetDin) + { + uiOneRuns = (uiDin - uiTargetDin) - 1; + pState->uiOffset = uiLastOffset; + pState->uiOnes = uiOneRuns; + uiDin = uiTargetDin; + break; + } + + uiDin -= uiOneRuns; + } + else + { + uiDelta = DINNextVal( pCurRef, &tempState); + + // Check if next din value is equal or less than target din + + uiDin -= uiDelta; + if (uiDin <= uiTargetDin) + { + pState->uiOffset = uiLastOffset; + break; + } + } + } + + pState->uiOffset = uiLastOffset; + } + + *puiDin = uiDin; + return ((uiDin == uiTargetDin) ? FERR_OK : RC_SET( FERR_FAILURE)); +} + +/*************************************************************************** +Desc: Get the next DIN value from the DIN set. +***************************************************************************/ +FLMUINT DINNextVal( + FLMBYTE * puiDin, + DIN_STATE * pState) +{ + FLMBYTE * pOneRun; + FLMBYTE * pCurDin; + FLMUINT uiTemp = 0; + FLMUINT uiOneRun; + FLMUINT uiStateOneRuns; + + pCurDin = puiDin + pState->uiOffset; + + switch (SENValLen( pCurDin)) + { + case 0: + { + uiOneRun = 0; + pOneRun = pCurDin + 1; + + if (*pCurDin < DIN_ONE_RUN_HV) + { + uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2; + } + else if (*pCurDin == DIN_ONE_RUN_HV) + { + uiOneRun = SENNextVal( &pOneRun); + } + else + { + + // Invalid code found + + pCurDin++; + uiTemp = 0; + break; + } + + // Handle the position of the one run + + uiStateOneRuns = pState->uiOnes; + + // return 1 unless on last one run value + + uiTemp = 1; + uiStateOneRuns++; + + if (uiStateOneRuns >= uiOneRun) + { + pCurDin = pOneRun; // Set to after the one runs + uiStateOneRuns = 0; // This sets state of ones to zero + } + + pState->uiOnes = uiStateOneRuns; + break; + } + + case 1: + { + uiTemp = *pCurDin++; + break; + } + + case 2: + { + uiTemp = ((FLMUINT) (SEN_2B_MASK &*pCurDin++)) << 8; + goto DINNV_1_byte; + } + + case 3: + { + uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pCurDin++))) << 16; + goto DINNV_2_bytes; + } + + case 4: + { + uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pCurDin++))) << 24; + goto DINNV_3_bytes; + } + + case 5: + { + pCurDin++; + uiTemp = ((FLMUINT) * pCurDin++) << 24; + DINNV_3_bytes: + + uiTemp += ((FLMUINT) * pCurDin++) << 16; + DINNV_2_bytes: + + uiTemp += ((FLMUINT) * pCurDin++) << 8; + DINNV_1_byte: + + uiTemp += *pCurDin++; + break; + } + } + + // Set the offset to point to the next reference + + pState->uiOffset = (FLMUINT) (pCurDin - puiDin); + return (uiTemp); +} + +/*************************************************************************** +Desc: Get the next one run value and update the state information +***************************************************************************/ +FLMUINT DINOneRunVal( + FLMBYTE * puiDin, + DIN_STATE * pState) +{ + FLMBYTE * pOneRun; + FLMBYTE * pCurDin; + FLMUINT uiOneRun; + + pCurDin = puiDin + pState->uiOffset; + + if (*pCurDin == 1) + { + pState->uiOffset++; + uiOneRun = 1; + } + else + { + uiOneRun = 0; + pOneRun = pCurDin + 1; + + if (*pCurDin < DIN_ONE_RUN_HV) + { + uiOneRun = (*pCurDin - DIN_ONE_RUN_LV) + 2; + } + else if (*pCurDin == DIN_ONE_RUN_HV) + { + uiOneRun = SENNextVal( &pOneRun); + } + else + { + // Invald code found + + uiOneRun = 0; + } + + pState->uiOffset = (FLMUINT) (pOneRun - puiDin); + } + + return (uiOneRun); +} + +/*************************************************************************** +Desc: Return the next SEN value. +***************************************************************************/ +FLMUINT SENNextVal( + FLMBYTE ** pSenRV) +{ + FLMUINT uiTemp; + FLMBYTE * pSen = *pSenRV; + + switch (SENValLen( pSen)) + { + case 1: + { + uiTemp = *pSen; + break; + } + + case 2: + { + uiTemp = ((FLMUINT) (SEN_2B_MASK &*pSen++)) << 8; + uiTemp += *pSen; + break; + } + + case 3: + { + uiTemp = ((FLMUINT) (SEN_3B_MASK & (*pSen++))) << 16; + goto SENNV_2_bytes; + } + + case 4: + { + uiTemp = ((FLMUINT) (SEN_4B_MASK & (*pSen++))) << 24; + goto SENNV_3_bytes; + } + + case 5: + { + pSen++; + uiTemp = ((FLMUINT) * pSen++) << 24; + SENNV_3_bytes: + + uiTemp += ((FLMUINT) * pSen++) << 16; + SENNV_2_bytes: + + uiTemp += ((FLMUINT) * pSen++) << 8; + uiTemp += *pSen; + break; + } + + default: + { + uiTemp = 0; + break; + } + } + + *pSenRV = pSen + 1; + return (uiTemp); +} + +/*************************************************************************** +Desc: Get the domain from a block type and current element pointer +***************************************************************************/ +FLMUINT FSGetDomain( + FLMBYTE ** curElmRV, + FLMUINT uiElmOvhd) +{ + FLMUINT uiDinDomain = 0; + FLMBYTE * curElm = *curElmRV; + + if (uiElmOvhd == BBE_KEY) + { + + // Normal leaf block, parse element to see if DOMAIN flag is present + + curElm += BBE_REC_OFS( curElm); + + // Skip past the update version information + + if (*curElm == SEN_DOMAIN) + { + curElm++; + uiDinDomain = SENNextVal( &curElm); + } + } + else + { + if (BNE_IS_DOMAIN( curElm)) + { + curElm += BBE_GET_KL( curElm) + uiElmOvhd; + uiDinDomain = ((FLMUINT) * curElm++) << 16; + uiDinDomain |= ((FLMUINT16) * curElm++) << 8; + uiDinDomain |= *curElm++; + } + } + + *curElmRV = curElm; + return (uiDinDomain); +} diff --git a/flaim/src/fsprev.cpp b/flaim/src/fsprev.cpp index 240fda4..4881aa4 100644 --- a/flaim/src/fsprev.cpp +++ b/flaim/src/fsprev.cpp @@ -1,260 +1,273 @@ -//------------------------------------------------------------------------- -// Desc: Traverse to previous element in a b-tree. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsprev.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*************************************************************************** -Desc: Go to the previous element in the logical b-tree while building key -Out: stack set up for next element -Return: FERR_OK, FERR_BT_END_OF_DATA (0xFFFF) or error number -Note: This could be called at any level of the b-tree. -*****************************************************************************/ -RCODE FSBtPrevElm( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p pStack /* Stack of variables for each level */ - ) -{ - RCODE rc = FERR_OK; /* Return code */ - FLMUINT uiBlkAddr; - FLMUINT uiTargetElm; /* Target element to scan for */ - FLMUINT uiPrevElm = 0; - FLMUINT uiPrevKeyCnt = 0; - FLMUINT uiElmKeyLen = 0; - FLMUINT uiKeyBufSize = pStack->uiKeyBufSize; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMBYTE * pCurElm; /* Points to the current element */ - FLMBYTE * pBlk; - - /* Check if you are at or before the first element in the block */ - if( pStack->uiCurElm <= BH_OVHD) - { - pBlk = BLK_PTR( pStack ); - /* YES - read in the previous block & go to the last element */ - if( (uiBlkAddr = (FLMUINT) FB2UD( &pBlk[ BH_PREV_BLK ])) == BT_END) - { - /* Unless you are at the end */ - rc = FERR_BT_END_OF_DATA; - } - else - { - if( RC_OK(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) - { - /* Set blkEnd & curElm & adjust parent block to previous element */ - pBlk = pStack->pBlk; - pStack->uiCurElm = pStack->uiBlkEnd = pStack->uiBlkEnd; - if( pStack->uiFlags & FULL_STACK) - rc = FSAdjustStack( pDb, pLFile, pStack, FALSE); - } - } - } - /* Move down 1 before the current element */ - if( RC_OK(rc)) - { - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) - { - pStack->uiCurElm -= BNE_DATA_OVHD; - pBlk = pStack->pBlk; - pCurElm = &pBlk[ pStack->uiCurElm ]; - flmCopyDrnKey( pStack->pKeyBuf, pCurElm); - goto Exit; - } - - /* Set up pointing to first element in the block */ - uiTargetElm = pStack->uiCurElm; - pStack->uiCurElm = BH_OVHD; /* Start at first element */ - pBlk = pStack->pBlk; - - while( pStack->uiCurElm < uiTargetElm ) /* Loop till target is hit */ - { - pCurElm = &pBlk[ pStack->uiCurElm ]; - uiPrevKeyCnt = (FLMUINT) (BBE_GET_PKC( pCurElm )); - uiElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm )); - - if( uiElmKeyLen + uiPrevKeyCnt > uiKeyBufSize ) - { - rc = RC_SET( FERR_CACHE_ERROR); - goto Exit; - } - if( uiElmKeyLen) - { - f_memcpy( &pStack->pKeyBuf[ uiPrevKeyCnt ], - &pCurElm[ uiElmOvhd ], uiElmKeyLen ); - } - uiPrevElm = pStack->uiCurElm; - if( RC_BAD(rc = FSBlkNextElm( pStack ))) - { - rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; // Hide element end - break; /* Break out if at the end of the block */ - } - } - pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen; - pStack->uiCurElm = uiPrevElm; - } -Exit: - return( rc ); -} - - -/*************************************************************************** -Desc: Return the last DIN in the current element's reference list -Out: state information updated to refer to the last reference -Return: DIN the din of the last reference -Notes: The element must be the last continued element for a key. - This algorithm will not work for bit-vector types. -*****************************************************************************/ -FLMUINT FSRefLast( - BTSK_p pStack, /* Small stack to hold btree variables*/ - DIN_STATE_p pState, /* Holds offset, one run number, etc.*/ - FLMUINT * puiDomainRV) /* Returns the elements domain */ -{ - FLMBYTE * pCurElm = CURRENT_ELM( pStack ); - FLMBYTE * pCurRef; /* Points to start of references */ - FLMUINT uiRefSize; /* Size of the element's references */ - - /* Point past the domain, ignore return value */ - pCurRef = pCurElm; - *puiDomainRV = FSGetDomain( &pCurRef, pStack->uiElmOvhd ); - uiRefSize = (FLMUINT)(BBE_GET_RL(pCurElm) - (pCurRef - BBE_REC_PTR(pCurElm))); - - return FSGetPrevRef( pCurRef, pState, uiRefSize); -} - -/**************************************************************************** -Desc: Position and return the previous reference saving the state -Out: state updated from current position -Return: previous value from target -***************************************************************************/ -FLMUINT FSGetPrevRef( - FLMBYTE * pCurRef, // Points to start of references - DIN_STATE_p pState, // Holds tate information to get next - FLMUINT uiTarget) // Stop when the target is hit and back off -{ - FLMUINT uiDin ; /* Current din to compute and return */ - FLMUINT uiOneRuns = 0; - FLMUINT uiDelta = 0; - FLMUINT uiLastOffset = 0; /* Last offset - used to back up */ - FLMBYTE byValue; - - RESET_DINSTATE_p( pState ); - uiDin = DINNextVal( pCurRef, pState ); - - while( pState->uiOffset < uiTarget) - { - /* Get the current byte to see what kind of item it is */ - byValue = (FLMBYTE) pCurRef[ uiLastOffset = pState->uiOffset ]; - if( DIN_IS_REAL_ONE_RUN(byValue)) - { - uiDelta = 0; - uiOneRuns = DINOneRunVal( pCurRef, pState); - uiDin -= uiOneRuns; - } - else - { - uiDelta = DINNextVal( pCurRef, pState); - uiDin -= uiDelta; - } - } - /** - *** Hit the end of the reference set for the current element. - *** The current din is a correct return value. The pState structure - *** must be setup to refer to the last entry using uiLastOffset. - **/ - if(( pState->uiOffset = uiLastOffset) != 0) - { - if( uiDelta == 0) - { - /** One runs was the last entry, setup for one run state **/ - uiOneRuns--; /* uiOneRuns state is zero based */ - pState->uiOnes = uiOneRuns; - } - } - return( uiDin); -} - -/**************************************************************************** -Desc: Go to the previous reference given a valid cursor. -Out: cursor updated if there is a previous reference -Return: RCODE FERR_OK | FERR_BT_END_OF_DATA (0xFFFF) or error -****************************************************************************/ -RCODE FSRefPrev( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p pStack, /* Small stack to hold btree variables*/ - DIN_STATE_p pState, /* Holds offset, one run number, etc.*/ - FLMUINT * puiDinRV) /* Last din used and returns din */ -{ - RCODE rc; /* Return code */ - FLMBYTE * pCurRef; /* Points to current reference */ - FLMBYTE * pCurElm; /* Points to current element */ - FLMUINT uiDin = *puiDinRV; - FLMUINT uiDummyDomain; - FLMBYTE byValue; - - /* Point to the start of the current reference */ - pCurRef = pCurElm = CURRENT_ELM( pStack ); - FSGetDomain( &pCurRef, pStack->uiElmOvhd ); - - /* Was this the first reference */ - if( pState->uiOffset == 0) - { - /** - *** Read in the previous element or return FERR_BT_END_OF_DATA if first - **/ - - if( BBE_IS_FIRST( pCurElm)) - return( FERR_BT_END_OF_DATA ); - - if( RC_BAD(rc = FSBtPrevElm( pDb, pLFile, pStack ))) - return( rc ); - - uiDin = FSRefLast( pStack, pState, &uiDummyDomain ); - } - - /** - *** Start reading until hit the current state values - **/ - else - { - /* Get current byte - could be a 1 run */ - byValue = pCurRef[ pState->uiOffset ]; - - if( DIN_IS_REAL_ONE_RUN(byValue) && pState->uiOnes) - // 03/11/96 !(pState->uiOnes == 1)) - { - /** - *** One runs are easy if you are not on the first one run (above) - **/ - uiDin++; /* Previous din is one more */ - pState->uiOnes--; - } - else - { - uiDin = FSGetPrevRef( pCurRef, pState, pState->uiOffset); - } - } - - *puiDinRV = uiDin; - return( FERR_OK ); -} +//------------------------------------------------------------------------- +// Desc: Traverse to previous element in a b-tree. +// Tabs: 3 +// +// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsprev.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +/*************************************************************************** +Desc: Go to the previous element in the logical b-tree while building key +***************************************************************************/ +RCODE FSBtPrevElm( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack) +{ + RCODE rc = FERR_OK; + FLMUINT uiBlkAddr; + FLMUINT uiTargetElm; + FLMUINT uiPrevElm = 0; + FLMUINT uiPrevKeyCnt = 0; + FLMUINT uiElmKeyLen = 0; + FLMUINT uiKeyBufSize = pStack->uiKeyBufSize; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMBYTE * pCurElm; + FLMBYTE * pBlk; + + // Check if you are at or before the first element in the block + + if (pStack->uiCurElm <= BH_OVHD) + { + pBlk = BLK_PTR( pStack); + + // YES - read in the previous block & go to the last element + + if ((uiBlkAddr = (FLMUINT) FB2UD( &pBlk[BH_PREV_BLK])) == BT_END) + { + + // Unless you are at the end + + rc = FERR_BT_END_OF_DATA; + } + else + { + if (RC_OK( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + { + + // Set blkEnd & curElm and adjust parent block to previous + // element + + pBlk = pStack->pBlk; + pStack->uiCurElm = pStack->uiBlkEnd = pStack->uiBlkEnd; + + if (pStack->uiFlags & FULL_STACK) + { + rc = FSAdjustStack( pDb, pLFile, pStack, FALSE); + } + } + } + } + + // Move down 1 before the current element + + if (RC_OK( rc)) + { + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) + { + pStack->uiCurElm -= BNE_DATA_OVHD; + pBlk = pStack->pBlk; + pCurElm = &pBlk[pStack->uiCurElm]; + flmCopyDrnKey( pStack->pKeyBuf, pCurElm); + goto Exit; + } + + // Set up pointing to first element in the block + + uiTargetElm = pStack->uiCurElm; + pStack->uiCurElm = BH_OVHD; + pBlk = pStack->pBlk; + + while (pStack->uiCurElm < uiTargetElm) + { + pCurElm = &pBlk[pStack->uiCurElm]; + uiPrevKeyCnt = (FLMUINT) (BBE_GET_PKC( pCurElm)); + uiElmKeyLen = (FLMUINT) (BBE_GET_KL( pCurElm)); + + if (uiElmKeyLen + uiPrevKeyCnt > uiKeyBufSize) + { + rc = RC_SET( FERR_CACHE_ERROR); + goto Exit; + } + + if (uiElmKeyLen) + { + f_memcpy( &pStack->pKeyBuf[uiPrevKeyCnt], &pCurElm[uiElmOvhd], + uiElmKeyLen); + } + + uiPrevElm = pStack->uiCurElm; + if (RC_BAD( rc = FSBlkNextElm( pStack))) + { + rc = (rc == FERR_BT_END_OF_DATA) ? FERR_OK : rc; + break; + } + } + + pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen; + pStack->uiCurElm = uiPrevElm; + } + +Exit: + + return (rc); +} + +/*************************************************************************** +Desc: Return the last DIN in the current element's reference list +***************************************************************************/ +FLMUINT FSRefLast( + BTSK * pStack, // Small stack to hold btree variables + DIN_STATE * pState, // Holds offset, one run number, etc. + FLMUINT * puiDomainRV) // Returns the elements domain +{ + FLMBYTE * pCurElm = CURRENT_ELM( pStack); + FLMBYTE * pCurRef; + FLMUINT uiRefSize; + + // Point past the domain, ignore return value + + pCurRef = pCurElm; + *puiDomainRV = FSGetDomain( &pCurRef, pStack->uiElmOvhd); + uiRefSize = (FLMUINT) (BBE_GET_RL( pCurElm) - + (pCurRef - BBE_REC_PTR( pCurElm))); + + return (FSGetPrevRef( pCurRef, pState, uiRefSize)); +} + +/*************************************************************************** +Desc: Position and return the previous reference saving the state +***************************************************************************/ +FLMUINT FSGetPrevRef( + FLMBYTE * pCurRef, + DIN_STATE * pState, + FLMUINT uiTarget) +{ + FLMUINT uiDin; + FLMUINT uiOneRuns = 0; + FLMUINT uiDelta = 0; + FLMUINT uiLastOffset = 0; + FLMBYTE byValue; + + RESET_DINSTATE_p( pState); + uiDin = DINNextVal( pCurRef, pState); + + while (pState->uiOffset < uiTarget) + { + + // Get the current byte to see what kind of item it is + + byValue = (FLMBYTE) pCurRef[uiLastOffset = pState->uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + uiDelta = 0; + uiOneRuns = DINOneRunVal( pCurRef, pState); + uiDin -= uiOneRuns; + } + else + { + uiDelta = DINNextVal( pCurRef, pState); + uiDin -= uiDelta; + } + } + + // Hit the end of the reference set for the current element. The + // current din is a correct return value. The pState structure must be + // setup to refer to the last entry using uiLastOffset. + + if ((pState->uiOffset = uiLastOffset) != 0) + { + if (uiDelta == 0) + { + + // One runs was the last entry, setup for one run state * + + uiOneRuns--; + pState->uiOnes = uiOneRuns; + } + } + + return (uiDin); +} + +/*************************************************************************** +Desc: Go to the previous reference given a valid cursor. +***************************************************************************/ +RCODE FSRefPrev( + FDB * pDb, + LFILE * pLFile, + BTSK * pStack, + DIN_STATE * pState, + FLMUINT * puiDinRV) +{ + RCODE rc = FERR_OK; + FLMBYTE * pCurRef; + FLMBYTE * pCurElm; + FLMUINT uiDin = *puiDinRV; + FLMUINT uiDummyDomain; + FLMBYTE byValue; + + // Point to the start of the current reference + + pCurRef = pCurElm = CURRENT_ELM( pStack); + FSGetDomain( &pCurRef, pStack->uiElmOvhd); + + // Was this the first reference + + if (pState->uiOffset == 0) + { + + // Read in the previous element or return FERR_BT_END_OF_DATA if + // first + + if (BBE_IS_FIRST( pCurElm)) + { + return (FERR_BT_END_OF_DATA); + } + + if (RC_BAD( rc = FSBtPrevElm( pDb, pLFile, pStack))) + { + return (rc); + } + + uiDin = FSRefLast( pStack, pState, &uiDummyDomain); + } + else + { + + // Get current byte - could be a 1 run + + byValue = pCurRef[pState->uiOffset]; + + if (DIN_IS_REAL_ONE_RUN( byValue) && pState->uiOnes) + { + uiDin++; + pState->uiOnes--; + } + else + { + uiDin = FSGetPrevRef( pCurRef, pState, pState->uiOffset); + } + } + + *puiDinRV = uiDin; + return (FERR_OK); +} diff --git a/flaim/src/fsrecget.cpp b/flaim/src/fsrecget.cpp index 1ee7426..0f06cb0 100644 --- a/flaim/src/fsrecget.cpp +++ b/flaim/src/fsrecget.cpp @@ -24,24 +24,25 @@ #include "flaimsys.h" +#define NUM_FIELDS_IN_ARRAY 16 + typedef struct Field_State { - // State information to position to the field within the element - FLMBYTE * pElement; // Points to the element within block - FLMUINT uiFieldType; // Storage field type - FLMUINT uiFieldLen; // Length of storage if known - FLMUINT uiPosInElm; // Position within the element - FLMUINT uiTagNum; // Field tag/data dictionary number - FLMUINT uiLevel; // Current level number - FLMUINT uiEncId; // EncDef ID if encrypted - FLMUINT uiEncFieldLen; // Encrypted field length -} FSTATE; + FLMBYTE * pElement; // Points to the element within block + FLMUINT uiFieldType; // Storage field type + FLMUINT uiFieldLen; // Length of storage if known + FLMUINT uiPosInElm; // Position within the element + FLMUINT uiTagNum; // Field tag/data dictionary number + FLMUINT uiLevel; // Current level number + FLMUINT uiEncId; // EncDef ID if encrypted + FLMUINT uiEncFieldLen; // Encrypted field length +} FSTATE; -typedef struct Data_Piece -{ // Data is garbage when uiFieldLen is 0. - FLMBYTE * pData; // Points to data within the block. - FLMUINT uiLength; // Length of this data piece - struct Data_Piece * pNext; // Next data piece or NULL +typedef struct DATAPIECE +{ + FLMBYTE * pData; // Points to data within the block. + FLMUINT uiLength; // Length of this data piece + DATAPIECE * pNext; // Next data piece or NULL } DATAPIECE; typedef struct Temporary_Field @@ -55,177 +56,167 @@ typedef struct Temporary_Field DATAPIECE DataPiece; } TEMPFIELD; -#define NUM_FIELDS_IN_ARRAY 16 - -typedef struct Field_Group +typedef struct FLDGROUP { - TEMPFIELD pFields[ NUM_FIELDS_IN_ARRAY]; // Allocated array of fields - struct Field_Group * pNext; // Next temporary field group + TEMPFIELD pFields[ NUM_FIELDS_IN_ARRAY]; + FLDGROUP * pNext; } FLDGROUP; -typedef struct Locked_Block +typedef struct LOCKED_BLOCK { SCACHE * pSCache; - struct Locked_Block *pNext; + LOCKED_BLOCK * pNext; } LOCKED_BLOCK; - + FSTATIC RCODE FSGetFldOverhead( - FDB_p pDb, - FSTATE * fState); + FDB * pDb, + FSTATE * fState); -/*************************************************************************** -Desc: Retrieves a record given a DRN -*****************************************************************************/ -RCODE FSReadRecord( // Was FSRecordGet - FDB_p pDb, - LFILE * pLFile, +/**************************************************************************** +Desc: Retrieves a record given a DRN +****************************************************************************/ +RCODE FSReadRecord( + FDB * pDb, + LFILE * pLFile, FLMUINT uiDrn, - FlmRecord ** ppRecord, // [out] returned record - FLMUINT * puiRecTransId, // [out] record's transaction ID - FLMBOOL * pbMostCurrent) // [out] true if record is most current + FlmRecord ** ppRecord, + FLMUINT * puiRecTransId, + FLMBOOL * pbMostCurrent) { - RCODE rc; - BTSK stackBuf[ BH_MAX_LEVELS ]; - BTSK_p pStack = NULL; - FLMBYTE pKeyBuf[ DIN_KEY_SIZ ]; - FLMBYTE pDrnBuf[ DIN_KEY_SIZ ]; + RCODE rc = FERR_OK; + BTSK stackBuf[BH_MAX_LEVELS]; + BTSK * pStack = NULL; + FLMBYTE pKeyBuf[DIN_KEY_SIZ]; + FLMBYTE pDrnBuf[DIN_KEY_SIZ]; - FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); + FSInitStackCache( &stackBuf[0], BH_MAX_LEVELS); - pStack = stackBuf; // Initialize the stack + pStack = stackBuf; pStack->pKeyBuf = pKeyBuf; // Search the B-TREE for the record + flmUINT32ToBigEndian( (FLMUINT32)uiDrn, pDrnBuf); - if( RC_OK( rc = FSBtSearch( pDb, pLFile, &pStack, pDrnBuf, 4, 0))) + if (RC_OK( rc = FSBtSearch( pDb, pLFile, &pStack, pDrnBuf, 4, 0))) { rc = RC_SET( FERR_NOT_FOUND); - if( ( pStack->uiCmpStatus == BT_EQ_KEY) && (uiDrn != DRN_LAST_MARKER)) + + if ((pStack->uiCmpStatus == BT_EQ_KEY) && (uiDrn != DRN_LAST_MARKER)) { - rc = FSReadElement( pDb, &pDb->TempPool, pLFile, uiDrn, pStack, - TRUE, ppRecord, puiRecTransId, pbMostCurrent); + rc = FSReadElement( pDb, &pDb->TempPool, pLFile, uiDrn, pStack, TRUE, + ppRecord, puiRecTransId, pbMostCurrent); } } + FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); - return( rc ); + return (rc); } -/************************************************************************** -Desc: Low level routine to retrieve and build an internal tree record. - The caller is responsible for freeing memory that the record - is placed into. This routine is called by FSRecordGet() -Ret: FERR_OK (0) - FERR_NOT_FOUND - field not found - FERR_MEM - ran out of memeory - FERR_DATA_ERROR - the data is somehow corrupt -**************************************************************************/ +/**************************************************************************** +Desc: Low-level routine to retrieve and build an internal tree record. +****************************************************************************/ RCODE FSReadElement( - FDB_p pDb, - POOL * pPool, - LFILE * pLFile, - FLMUINT uiDrn, - BTSK_p pStack, - FLMBOOL bOkToPreallocSpace, - FlmRecord ** ppRecord, // [out] returned record - FLMUINT * puiRecTransId, // [out] record's transaction ID - FLMBOOL * pbMostCurrent) // [out] true if record is most current + FDB * pDb, + POOL * pPool, + LFILE * pLFile, + FLMUINT uiDrn, + BTSK * pStack, + FLMBOOL bOkToPreallocSpace, + FlmRecord ** ppRecord, + FLMUINT * puiRecTransId, + FLMBOOL * pbMostCurrent) { - RCODE rc = FERR_OK; - FlmRecord * pRecord = NULL; - FLMBYTE * pCurElm; // Points to the current element - void * pvPoolMark = GedPoolMark( pPool); - FLMUINT uiElmRecLen; // Length of element's record - FLMUINT uiFieldLen; // Length of the field - FLMUINT uiLowestTransId; // Lowest transaction ID. - FLMUINT uiFieldCount; - FLMUINT uiTrueDataSpace; - FLMUINT uiFieldPos; - FLMBOOL bMostCurrent; - TEMPFIELD * pField; - FLDGROUP * pFldGroup = NULL; - FLDGROUP * pFirstFldGroup = NULL; - DATAPIECE * pDataPiece; - LOCKED_BLOCK * pLockedBlock = NULL; - FSTATE fState; - FLMUINT uiEncFieldLen; -#ifdef FLM_DBG_LOG - char szTmpBuf[ 80]; -#endif - -#ifdef FLM_DBG_LOG - flmAssert( pStack->uiKeyLen == DIN_KEY_SIZ && - flmBigEndianToUINT32( pStack->pKeyBuf) == uiDrn); -#endif + RCODE rc = FERR_OK; + FlmRecord * pRecord = NULL; + FLMBYTE * pCurElm; + void * pvPoolMark = GedPoolMark( pPool); + FLMUINT uiElmRecLen; + FLMUINT uiFieldLen; + FLMUINT uiLowestTransId; + FLMUINT uiFieldCount; + FLMUINT uiTrueDataSpace; + FLMUINT uiFieldPos; + FLMBOOL bMostCurrent; + TEMPFIELD * pField; + FLDGROUP * pFldGroup = NULL; + FLDGROUP* pFirstFldGroup = NULL; + DATAPIECE * pDataPiece; + LOCKED_BLOCK * pLockedBlock = NULL; + FSTATE fState; + FLMUINT uiEncFieldLen; // Initialize variables + fState.uiLevel = 0; uiFieldCount = 0; uiTrueDataSpace = 0; uiFieldPos = NUM_FIELDS_IN_ARRAY; // Check to make sure we are positioned at the first element. - pCurElm = CURRENT_ELM( pStack ); - if( !BBE_IS_FIRST( pCurElm)) + + pCurElm = CURRENT_ELM( pStack); + if (!BBE_IS_FIRST( pCurElm)) { rc = RC_SET( FERR_DATA_ERROR); goto Exit; } - uiLowestTransId = FB2UD( &pStack->pBlk[ BH_TRANS_ID]); - bMostCurrent = (pStack->pSCache->uiHighTransID == 0xFFFFFFFF) ? TRUE : FALSE; - -#ifdef FLM_DBG_LOG - f_sprintf( szTmpBuf, "Rd1:L%X,H%X", - (unsigned)uiLowestTransId, (unsigned)pStack->pSCache->uiHighTransID); - - flmDbgLogWrite( pDb->pFile->uiFFileId, pStack->pSCache->uiBlkAddress, uiDrn, - pDb->LogHdr.uiCurrTransID, szTmpBuf); -#endif + uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]); + bMostCurrent = (pStack->pSCache->uiHighTransID == 0xFFFFFFFF) + ? TRUE + : FALSE; // Loop on each element in the record - for( ;;) + + for (;;) { + // Setup all variables to process the current element - uiElmRecLen = BBE_GET_RL( pCurElm ); - if( uiElmRecLen == 0) + uiElmRecLen = BBE_GET_RL( pCurElm); + if (uiElmRecLen == 0) { rc = RC_SET( FERR_EOF_HIT); break; } - pCurElm += BBE_REC_OFS( pCurElm ); + + pCurElm += BBE_REC_OFS( pCurElm); fState.uiPosInElm = 0; // Loop on each field within this element. - while( fState.uiPosInElm < uiElmRecLen) + + while (fState.uiPosInElm < uiElmRecLen) { fState.pElement = pCurElm; - if( RC_BAD( rc = FSGetFldOverhead( pDb, &fState))) + if (RC_BAD( rc = FSGetFldOverhead( pDb, &fState))) { goto Exit; } + uiFieldLen = fState.uiFieldLen; uiEncFieldLen = fState.uiEncFieldLen; // Old record info data - skip past for now - if( fState.uiTagNum == 0) + + if (fState.uiTagNum == 0) { fState.uiPosInElm += (uiEncFieldLen ? uiEncFieldLen : uiFieldLen); continue; } - if( !pRecord) + if (!pRecord) { + // Create a new data record or use the existing data record. - if( *ppRecord) + if (*ppRecord) { - if( (*ppRecord)->isReadOnly()) + if ((*ppRecord)->isReadOnly()) { (*ppRecord)->Release(); *ppRecord = NULL; - if( (pRecord = f_new FlmRecord) == NULL) + if ((pRecord = f_new FlmRecord) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -233,6 +224,7 @@ RCODE FSReadElement( } else { + // Reuse the existing FlmRecord object. pRecord = *ppRecord; @@ -242,7 +234,7 @@ RCODE FSReadElement( } else { - if( (pRecord = f_new FlmRecord) == NULL) + if ((pRecord = f_new FlmRecord) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -258,13 +250,16 @@ RCODE FSReadElement( } // Check if out of fields in the tempoary field group. - if( uiFieldPos >= NUM_FIELDS_IN_ARRAY) + + if (uiFieldPos >= NUM_FIELDS_IN_ARRAY) { FLDGROUP * pTempFldGroup; uiFieldPos = 0; + // Allocate the first field group from the pool. - if( (pTempFldGroup = (FLDGROUP *) GedPoolAlloc( + + if ((pTempFldGroup = (FLDGROUP *) GedPoolAlloc( pPool, sizeof( FLDGROUP))) == NULL) { rc = RC_SET( FERR_MEM); @@ -272,7 +267,7 @@ RCODE FSReadElement( } pTempFldGroup->pNext = NULL; - if( pFldGroup) + if (pFldGroup) { pFldGroup->pNext = pTempFldGroup; } @@ -280,11 +275,12 @@ RCODE FSReadElement( { pFirstFldGroup = pTempFldGroup; } + pFldGroup = pTempFldGroup; } - + uiFieldCount++; - pField = &pFldGroup->pFields[ uiFieldPos++]; + pField = &pFldGroup->pFields[uiFieldPos++]; pField->uiLevel = fState.uiLevel; pField->uiFieldID = fState.uiTagNum; pField->uiFieldType = fState.uiFieldType; @@ -293,11 +289,11 @@ RCODE FSReadElement( pField->uiEncFieldLen = fState.uiEncFieldLen; pDataPiece = &pField->DataPiece; - if( uiFieldLen || uiEncFieldLen) + if (uiFieldLen || uiEncFieldLen) { - FLMUINT uiDataPos = 0; + FLMUINT uiDataPos = 0; - if( fState.uiEncFieldLen) + if (fState.uiEncFieldLen) { uiTrueDataSpace += FLM_ENC_FLD_OVERHEAD; @@ -305,76 +301,82 @@ RCODE FSReadElement( if (fState.uiFieldType == FLM_BINARY_TYPE) { + // Adjust for the decrypted data. + uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) & - (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); + (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); } uiTrueDataSpace += fState.uiFieldLen + fState.uiEncFieldLen; - // Store the encrypted field length rather than the decrypted field length - // This will allow the gathering of the encrypted or decrypted field data - // to use the same code. - uiFieldLen = uiEncFieldLen; + // Store the encrypted field length rather than the + // decrypted field length This will allow the gathering of + // the encrypted or decrypted field data to use the same + // code. + uiFieldLen = uiEncFieldLen; } - else if( fState.uiFieldLen > 4) + else if (fState.uiFieldLen > 4) { // Binary data needs to account for alignment issues. if (fState.uiFieldType == FLM_BINARY_TYPE) { - if( fState.uiFieldLen >= 0xFF) + if (fState.uiFieldLen >= 0xFF) { + // Align so that the data is aligned - not the length - uiTrueDataSpace += sizeof( FLMUINT16); + uiTrueDataSpace += sizeof(FLMUINT32); uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) & - (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); - uiTrueDataSpace -= sizeof( FLMUINT16); + (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); + uiTrueDataSpace -= sizeof(FLMUINT32); } else { - uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) & - (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); + uiTrueDataSpace = ((uiTrueDataSpace + FLM_ALLOC_ALIGN) & + (~(FLM_ALLOC_ALIGN) & 0x7FFFFFFF)); } } uiTrueDataSpace += fState.uiFieldLen; // Field values with lengths greater than 255 bytes are - // stored length-preceded. A single byte flags field precedes the length. + // stored length-preceded. A single byte flags field + // precedes the length. if (fState.uiFieldLen >= 0xFF) { - uiTrueDataSpace += sizeof( FLMUINT16) + 1; + uiTrueDataSpace += sizeof(FLMUINT32) + 1; } } // Value may start in the next element. - while( uiDataPos < uiFieldLen) + while (uiDataPos < uiFieldLen) { - // Need to read next element for the value portion? - if( fState.uiPosInElm >= uiElmRecLen) + // Need to read next element for the value portion? + + if (fState.uiPosInElm >= uiElmRecLen) { - if( BBE_IS_LAST( CURRENT_ELM( pStack ))) + if (BBE_IS_LAST( CURRENT_ELM( pStack))) { rc = RC_SET( FERR_DATA_ERROR); goto Exit; } - // If we are going to the next block, lock down this block - // beacause data pointers are pointing to it. + // If we are going to the next block, lock down this + // block beacause data pointers are pointing to it. - if( RC_BAD( FSBlkNextElm( pStack))) // Better be FERR_BT_END_OF_DATA + if (RC_BAD( FSBlkNextElm( pStack))) { - LOCKED_BLOCK * pLastLockedBlock = pLockedBlock; - - if( (pLockedBlock = (LOCKED_BLOCK *) GedPoolAlloc( pPool, - sizeof( LOCKED_BLOCK))) == NULL) + LOCKED_BLOCK* pLastLockedBlock = pLockedBlock; + + if ((pLockedBlock = (LOCKED_BLOCK*) GedPoolAlloc( + pPool, sizeof( LOCKED_BLOCK))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -384,34 +386,26 @@ RCODE FSReadElement( pLockedBlock->pSCache = pStack->pSCache; pLockedBlock->pNext = pLastLockedBlock; - if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack))) + if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) { - rc = (rc == FERR_BT_END_OF_DATA) - ? RC_SET( FERR_DATA_ERROR) - : rc; + rc = (rc == FERR_BT_END_OF_DATA) + ? RC_SET( FERR_DATA_ERROR) + : rc; goto Exit; } - if( uiLowestTransId > FB2UD( &pStack->pBlk[ BH_TRANS_ID])) + if (uiLowestTransId > FB2UD( &pStack->pBlk[BH_TRANS_ID])) { - uiLowestTransId = FB2UD( &pStack->pBlk[ BH_TRANS_ID]); + uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]); } - if( !bMostCurrent) + if (!bMostCurrent) { - bMostCurrent = (pStack->pSCache->uiHighTransID == - 0xFFFFFFFF) ? TRUE : FALSE; + bMostCurrent = + (pStack->pSCache->uiHighTransID == 0xFFFFFFFF) + ? TRUE + : FALSE; } - -#ifdef FLM_DBG_LOG - f_sprintf( szTmpBuf, "Rd2:L%X,H%X", - (unsigned)FB2UD( &pStack->pBlk[ BH_TRANS_ID]), - (unsigned)pStack->pSCache->uiHighTransID); - - flmDbgLogWrite( pDb->pFile->uiFFileId, - pStack->pSCache->uiBlkAddress, uiDrn, - pDb->LogHdr.uiCurrTransID, szTmpBuf); -#endif } pCurElm = CURRENT_ELM( pStack); @@ -420,13 +414,14 @@ RCODE FSReadElement( fState.uiPosInElm = 0; } - // Compare number of bytes left if value <= # bytes left in element + // Compare number of bytes left if value <= # bytes left + // in element - if( uiFieldLen - uiDataPos <= uiElmRecLen - fState.uiPosInElm) + if (uiFieldLen - uiDataPos <= uiElmRecLen - fState.uiPosInElm) { - FLMUINT uiDelta = uiFieldLen - uiDataPos; - - pDataPiece->pData = &pCurElm[ fState.uiPosInElm]; + FLMUINT uiDelta = uiFieldLen - uiDataPos; + + pDataPiece->pData = &pCurElm[fState.uiPosInElm]; pDataPiece->uiLength = uiDelta; fState.uiPosInElm += uiDelta; pDataPiece->pNext = NULL; @@ -434,43 +429,47 @@ RCODE FSReadElement( } else { - // Take what is there and get next element to grab some more. - FLMUINT uiBytesToMove = uiElmRecLen - fState.uiPosInElm; - DATAPIECE * pNextDataPiece; - pDataPiece->pData = &pCurElm[ fState.uiPosInElm]; + // Take what is there and get next element to grab some + // more. + + FLMUINT uiBytesToMove = uiElmRecLen - fState.uiPosInElm; + DATAPIECE * pNextDataPiece; + + pDataPiece->pData = &pCurElm[fState.uiPosInElm]; pDataPiece->uiLength = uiBytesToMove; fState.uiPosInElm += uiBytesToMove; uiDataPos += uiBytesToMove; - if( (pNextDataPiece = (DATAPIECE *) - GedPoolAlloc( pPool, sizeof( DATAPIECE))) == NULL) + if ((pNextDataPiece = (DATAPIECE *) GedPoolAlloc( + pPool, sizeof( DATAPIECE))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } + pDataPiece->pNext = pNextDataPiece; pDataPiece = pNextDataPiece; } } - } // End if uiFieldLen - } // End of while( fState.uiPosInElm < uiElmRecLen) + } + } // Done? - if( BBE_IS_LAST( CURRENT_ELM( pStack))) + if (BBE_IS_LAST( CURRENT_ELM( pStack))) { break; } // Position to next element - if( RC_BAD( FSBlkNextElm( pStack))) // Better be FERR_BT_END_OF_DATA + if (RC_BAD( FSBlkNextElm( pStack))) { - LOCKED_BLOCK * pLastLockedBlock = pLockedBlock; - - if( (pLockedBlock = (LOCKED_BLOCK *) GedPoolAlloc( pPool, - sizeof( LOCKED_BLOCK))) == NULL) + LOCKED_BLOCK* pLastLockedBlock = pLockedBlock; + + if ((pLockedBlock = (LOCKED_BLOCK *) GedPoolAlloc( + pPool, sizeof( LOCKED_BLOCK))) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -480,54 +479,47 @@ RCODE FSReadElement( pLockedBlock->pSCache = pStack->pSCache; pLockedBlock->pNext = pLastLockedBlock; - if( RC_BAD(rc = FSBtNextElm( pDb, pLFile, pStack))) + if (RC_BAD( rc = FSBtNextElm( pDb, pLFile, pStack))) { if (rc == FERR_BT_END_OF_DATA) { rc = RC_SET( FERR_DATA_ERROR); } + goto Exit; } - if( uiLowestTransId > FB2UD( &pStack->pBlk[ BH_TRANS_ID])) + if (uiLowestTransId > FB2UD( &pStack->pBlk[BH_TRANS_ID])) { - uiLowestTransId = FB2UD( &pStack->pBlk[ BH_TRANS_ID]); + uiLowestTransId = FB2UD( &pStack->pBlk[BH_TRANS_ID]); } - if( !bMostCurrent) + if (!bMostCurrent) { - bMostCurrent = (pStack->pSCache->uiHighTransID == - 0xFFFFFFFF) ? TRUE : FALSE; + bMostCurrent = (pStack->pSCache->uiHighTransID == 0xFFFFFFFF) + ? TRUE + : FALSE; } - -#ifdef FLM_DBG_LOG - f_sprintf( szTmpBuf, "Rd3:L%X,H%X", - (unsigned)FB2UD( &pStack->pBlk[ BH_TRANS_ID]), - (unsigned)pStack->pSCache->uiHighTransID); - - flmDbgLogWrite( pDb->pFile->uiFFileId, - pStack->pSCache->uiBlkAddress, uiDrn, - pDb->LogHdr.uiCurrTransID, szTmpBuf); -#endif } // Corruption Check. - pCurElm = CURRENT_ELM( pStack ); - if( BBE_IS_FIRST( pCurElm)) + pCurElm = CURRENT_ELM( pStack); + if (BBE_IS_FIRST( pCurElm)) { rc = RC_SET( FERR_DATA_ERROR); goto Exit; } } - if( pRecord) + if (pRecord) { void * pvField; - if( bOkToPreallocSpace) + if (bOkToPreallocSpace) { - if( RC_BAD( rc = pRecord->preallocSpace( uiFieldCount, uiTrueDataSpace))) + if (RC_BAD( rc = pRecord->preallocSpace( + uiFieldCount, uiTrueDataSpace))) { goto Exit; } @@ -535,40 +527,36 @@ RCODE FSReadElement( pFldGroup = pFirstFldGroup; - for( uiFieldPos = 0; uiFieldCount--; uiFieldPos++) + for (uiFieldPos = 0; uiFieldCount--; uiFieldPos++) { - - if( uiFieldPos >= NUM_FIELDS_IN_ARRAY) + if (uiFieldPos >= NUM_FIELDS_IN_ARRAY) { uiFieldPos = 0; - if( (pFldGroup = pFldGroup->pNext) == NULL) + if ((pFldGroup = pFldGroup->pNext) == NULL) + { break; + } } - pField = &pFldGroup->pFields[ uiFieldPos]; - if( RC_BAD( rc = pRecord->insertLast( pField->uiLevel, - pField->uiFieldID, pField->uiFieldType, &pvField))) + pField = &pFldGroup->pFields[uiFieldPos]; + + if (RC_BAD( rc = pRecord->insertLast( pField->uiLevel, + pField->uiFieldID, pField->uiFieldType, &pvField))) { goto Exit; } - if( pField->uiFieldLen) + if (pField->uiFieldLen) { - FLMBYTE * pDataPtr; - FLMBYTE * pEncDataPtr; + FLMBYTE * pDataPtr; + FLMBYTE * pEncDataPtr; pDataPiece = &pField->DataPiece; - if (RC_BAD( rc = pRecord->allocStorageSpace( - pvField, - pField->uiFieldType, - pField->uiFieldLen, - pField->uiEncFieldLen, - pField->uiEncId, - (pField->uiEncId - ? FLD_HAVE_ENCRYPTED_DATA - : 0), - &pDataPtr, - &pEncDataPtr))) + if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, + pField->uiFieldType, pField->uiFieldLen, + pField->uiEncFieldLen, pField->uiEncId, + (pField->uiEncId ? FLD_HAVE_ENCRYPTED_DATA : 0), + &pDataPtr, &pEncDataPtr))) { goto Exit; } @@ -585,17 +573,16 @@ RCODE FSReadElement( f_memcpy( pDataPtr, pDataPiece->pData, pDataPiece->uiLength); pDataPtr += pDataPiece->uiLength; } + pDataPiece = pDataPiece->pNext; - } while( pDataPiece); - + } while (pDataPiece); + // If the field is encrypted, then we must decrypt it here. + if (pField->uiEncId && !pDb->pFile->bInLimitedMode) { - if (RC_BAD( rc = flmDecryptField( pDb->pDict, - pRecord, - pvField, - pField->uiEncId, - &pDb->TempPool))) + if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, pvField, + pField->uiEncId, &pDb->TempPool))) { goto Exit; } @@ -604,20 +591,20 @@ RCODE FSReadElement( } } - if( puiRecTransId) + if (puiRecTransId) { *puiRecTransId = uiLowestTransId; } - if( pbMostCurrent) + if (pbMostCurrent) { *pbMostCurrent = bMostCurrent; } - if( *ppRecord) + if (*ppRecord) { - // We shouldn't hit this case, but in case we do we will deal - // with it. + + // We shouldn't hit this case, but in case we do we will deal with it. flmAssert( 0); (*ppRecord)->Release(); @@ -632,7 +619,7 @@ Exit: // Release all locked down blocks except the current block. - while( pLockedBlock) + while (pLockedBlock) { ScaReleaseCache( pLockedBlock->pSCache, FALSE); pLockedBlock = pLockedBlock->pNext; @@ -640,159 +627,162 @@ Exit: GedPoolReset( pPool, pvPoolMark); - if( pRecord) + if (pRecord) { pRecord->Release(); } // You are now positioned to the last element in the record - return( rc); + return (rc); } -/************************************************************************** -Desc: Read field overhead (level, field drn, and length information. - This isolates the complexity of the storage formats. -Out: fstate updated according to data -Ret: FERR_OK or FERR_NOT_FOUND if the field is not found -Notes:The entire field overhead MUST always be together (not split). - The data may be in another element. -**************************************************************************/ +/**************************************************************************** +Desc: Read field overhead (level, field drn, and length information. This + isolates the complexity of the storage formats. +****************************************************************************/ FSTATIC RCODE FSGetFldOverhead( - FDB_p pDb, + FDB * pDb, FSTATE * fState) { - RCODE rc = FERR_OK; - FLMBYTE * pFieldOvhd = &fState->pElement[ fState->uiPosInElm ]; - FLMBYTE * pElement = fState->pElement; - FLMBOOL bDoesntHaveFieldDef = TRUE; - FLMUINT uiFieldLen; - FLMUINT uiFieldType = 0; - FLMUINT uiTagNum; - FLMBYTE byTemp; - FLMUINT uiEncId = 0; - FLMUINT uiEncFieldLen = 0; + RCODE rc = FERR_OK; + FLMBYTE * pFieldOvhd = &fState->pElement[fState->uiPosInElm]; + FLMBYTE * pElement = fState->pElement; + FLMBYTE * pTmp; + FLMBOOL bDoesntHaveFieldDef = TRUE; + FLMUINT uiFieldLen; + FLMUINT uiFieldType = 0; + FLMUINT uiTagNum; + FLMBYTE ucBaseFlags; + FLMUINT uiEncId = 0; + FLMUINT uiEncFieldLen = 0; - /** - *** See FO_xxx_FLD definitions in FS.H - *** If maintaining, see also FSRecUpd.c to see how codes were written. - **/ - - if( FOP_IS_STANDARD( pFieldOvhd)) + if (FOP_IS_STANDARD( pFieldOvhd)) { - if( FSTA_LEVEL( pFieldOvhd)) + if (FSTA_LEVEL( pFieldOvhd)) { fState->uiLevel++; } - uiFieldLen = FSTA_FLD_LEN( pFieldOvhd ); - uiTagNum = FSTA_FLD_NUM( pFieldOvhd ); - pFieldOvhd += FSTA_OVHD; + uiFieldLen = FSTA_FLD_LEN( pFieldOvhd); + uiTagNum = FSTA_FLD_NUM( pFieldOvhd); + pFieldOvhd += FSTA_OVHD; } - else if( FOP_IS_OPEN( pFieldOvhd)) + else if (FOP_IS_OPEN( pFieldOvhd)) { - if( FOPE_LEVEL( pFieldOvhd)) + if (FOPE_LEVEL( pFieldOvhd)) { fState->uiLevel++; } - byTemp = (FLMBYTE)(FOP_GET_FLD_FLAGS( pFieldOvhd++ )); + ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd++)); + uiTagNum = (FLMUINT) * pFieldOvhd++; - uiTagNum = (FLMUINT) *pFieldOvhd++; - if( FOP_2BYTE_FLDNUM(byTemp)) + if (FOP_2BYTE_FLDNUM( ucBaseFlags)) { - uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8; + uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8; } - uiFieldLen = (FLMUINT) *pFieldOvhd++; - if( FOP_2BYTE_FLDLEN( byTemp )) + uiFieldLen = (FLMUINT) * pFieldOvhd++; + if (FOP_2BYTE_FLDLEN( ucBaseFlags)) { - uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8; + uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8; } } - else if( FOP_IS_NO_VALUE( pFieldOvhd)) + else if (FOP_IS_NO_VALUE( pFieldOvhd)) { - if( FNOV_LEVEL( pFieldOvhd )) + if (FNOV_LEVEL( pFieldOvhd)) { fState->uiLevel++; } - byTemp = (FLMBYTE)(FOP_GET_FLD_FLAGS( pFieldOvhd++ )); - uiTagNum = (FLMUINT) *pFieldOvhd++; - if( FOP_2BYTE_FLDNUM(byTemp)) + ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd++)); + uiTagNum = (FLMUINT) * pFieldOvhd++; + if (FOP_2BYTE_FLDNUM( ucBaseFlags)) { - uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8; + uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8; } - uiFieldLen= uiFieldType = 0; + + uiFieldLen = uiFieldType = 0; } - else if( FOP_IS_SET_LEVEL( pFieldOvhd)) + else if (FOP_IS_SET_LEVEL( pFieldOvhd)) { - // SET THE LEVEL - // - // Must be continuous with the next field + + // SET THE LEVEL Must be continuous with the next field fState->uiLevel -= FSLEV_GET( pFieldOvhd++); - fState->uiPosInElm = (FLMUINT)(pFieldOvhd - pElement); + fState->uiPosInElm = (FLMUINT) (pFieldOvhd - pElement); rc = FSGetFldOverhead( pDb, fState); goto Exit; } - else if( FOP_IS_TAGGED( pFieldOvhd)) + else if (FOP_IS_TAGGED( pFieldOvhd)) { bDoesntHaveFieldDef = FALSE; - if( FTAG_LEVEL( pFieldOvhd)) + if (FTAG_LEVEL( pFieldOvhd)) { fState->uiLevel++; } - byTemp = (FLMBYTE)(FOP_GET_FLD_FLAGS( pFieldOvhd)); - uiFieldType = (FLMUINT)(FTAG_FLD_TYPE( pFieldOvhd )); - pFieldOvhd += FTAG_OVHD; - uiTagNum = (FLMUINT) *pFieldOvhd++; + ucBaseFlags = (FLMBYTE) (FOP_GET_FLD_FLAGS( pFieldOvhd)); + pFieldOvhd++; + uiFieldType = (FLMUINT) (FTAG_GET_FLD_TYPE( *pFieldOvhd)); + pFieldOvhd++; + uiTagNum = (FLMUINT) * pFieldOvhd++; - if( FOP_2BYTE_FLDNUM(byTemp)) + if (FOP_2BYTE_FLDNUM( ucBaseFlags)) { - uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8; + uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8; } - - // When storing the unregistered fields we cleared the high bit - // to save on storage for VER11. The problem is that if a tag that is - // not in the unregistered range (FLAIM TAGS) cannot be represented. - // SO, we will XOR the high bit so 0x0111 is stored as 0x8111 and + + // When storing the unregistered fields we cleared the high bit to + // save on storage for VER11. The problem is that if a tag that is + // not in the unregistered range (FLAIM TAGS) cannot be represented. + // SO, we will XOR the high bit so 0x0111 is stored as 0x8111 and // 0x8222 is stored as 0x0222. uiTagNum ^= 0x8000; - uiFieldLen = (FLMUINT) *pFieldOvhd++; - if( FOP_2BYTE_FLDLEN( byTemp)) + uiFieldLen = (FLMUINT) * pFieldOvhd++; + if (FOP_2BYTE_FLDLEN( ucBaseFlags)) { - uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8; + uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8; } } - else if( FOP_IS_RECORD_INFO( pFieldOvhd)) + else if (FOP_IS_RECORD_INFO( pFieldOvhd)) { bDoesntHaveFieldDef = FALSE; - byTemp = *pFieldOvhd++; + ucBaseFlags = *pFieldOvhd++; uiFieldLen = *pFieldOvhd++; - if( FOP_2BYTE_FLDLEN( byTemp )) - uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8; + + if (FOP_2BYTE_FLDLEN( ucBaseFlags)) + { + uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8; + } + uiTagNum = 0; } else if (FOP_IS_ENCRYPTED( pFieldOvhd)) { - FLMBOOL bTagSz; - FLMBOOL bLenSz; - FLMBOOL bENumSz; - FLMBOOL bELenSz; + FLMBOOL bTagSz; + FLMBOOL bLenSz; + FLMBOOL bENumSz; + FLMBOOL bELenSz; + + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_60) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } bDoesntHaveFieldDef = FALSE; - if( FENC_LEVEL( pFieldOvhd )) + if (FENC_LEVEL( pFieldOvhd)) { fState->uiLevel++; } - uiFieldType = (FLMUINT)(FENC_FLD_TYPE( pFieldOvhd )); + uiFieldType = (FLMUINT) (FENC_FLD_TYPE( pFieldOvhd)); bTagSz = FENC_TAG_SZ( pFieldOvhd); bLenSz = FENC_LEN_SZ( pFieldOvhd); bENumSz = FENC_ETAG_SZ( pFieldOvhd); @@ -800,30 +790,74 @@ FSTATIC RCODE FSGetFldOverhead( pFieldOvhd += 2; - uiTagNum = (FLMUINT) *pFieldOvhd++; - if ( bTagSz) + uiTagNum = (FLMUINT) * pFieldOvhd++; + if (bTagSz) { - uiTagNum += ((FLMUINT) *pFieldOvhd++) << 8; + uiTagNum += ((FLMUINT) * pFieldOvhd++) << 8; } - uiFieldLen = (FLMUINT)*pFieldOvhd++; + uiFieldLen = (FLMUINT) * pFieldOvhd++; if (bLenSz) { - uiFieldLen += ((FLMUINT) *pFieldOvhd++) << 8; + uiFieldLen += ((FLMUINT) * pFieldOvhd++) << 8; } - uiEncId = (FLMUINT) *pFieldOvhd++; + uiEncId = (FLMUINT) * pFieldOvhd++; if (bENumSz) { - uiEncId += ((FLMUINT) *pFieldOvhd++) << 8; + uiEncId += ((FLMUINT) * pFieldOvhd++) << 8; } - uiEncFieldLen = (FLMUINT) *pFieldOvhd++; + uiEncFieldLen = (FLMUINT) * pFieldOvhd++; if (bELenSz) { - uiEncFieldLen += ((FLMUINT) *pFieldOvhd++) << 8; + uiEncFieldLen += ((FLMUINT) * pFieldOvhd++) << 8; } } + else if (FOP_IS_LARGE( pFieldOvhd)) + { + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_61) + { + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + bDoesntHaveFieldDef = FALSE; + pTmp = pFieldOvhd; + + if (FLARGE_LEVEL( pFieldOvhd)) + { + fState->uiLevel++; + } + + pTmp++; + + uiFieldType = FLARGE_FLD_TYPE( pFieldOvhd); + pTmp++; + + uiTagNum = FLARGE_TAG_NUM( pFieldOvhd); + pTmp += 2; + + if ((uiFieldLen = FLARGE_DATA_LEN( pFieldOvhd)) <= 0x0000FFFF) + { + flmAssert( 0); + rc = RC_SET( FERR_DATA_ERROR); + goto Exit; + } + + pTmp += 4; + + if (FLARGE_ENCRYPTED( pFieldOvhd)) + { + uiEncId = FLARGE_ETAG_NUM( pFieldOvhd); + pTmp += 2; + + uiEncFieldLen = FLARGE_EDATA_LEN( pFieldOvhd); + pTmp += 4; + } + + pFieldOvhd = pTmp; + } else { flmAssert( 0); @@ -831,12 +865,13 @@ FSTATIC RCODE FSGetFldOverhead( goto Exit; } - if( bDoesntHaveFieldDef) + if (bDoesntHaveFieldDef) { + // Get the field's storage type. - if( RC_BAD( fdictGetField( pDb->pDict, uiTagNum, &uiFieldType, - NULL, NULL))) + if (RC_BAD( fdictGetField( pDb->pDict, uiTagNum, + &uiFieldType, NULL, NULL))) { rc = RC_SET( FERR_DATA_ERROR); goto Exit; @@ -846,13 +881,13 @@ FSTATIC RCODE FSGetFldOverhead( // Set the fState return values fState->uiFieldType = uiFieldType; - fState->uiFieldLen = uiFieldLen; - fState->uiPosInElm = (FLMUINT) (pFieldOvhd - pElement); - fState->uiTagNum = uiTagNum; - fState->uiEncId = uiEncId; + fState->uiFieldLen = uiFieldLen; + fState->uiPosInElm = (FLMUINT) (pFieldOvhd - pElement); + fState->uiTagNum = uiTagNum; + fState->uiEncId = uiEncId; fState->uiEncFieldLen = uiEncFieldLen; Exit: - return( rc); + return (rc); } diff --git a/flaim/src/fsrecupd.cpp b/flaim/src/fsrecupd.cpp index b28670f..de3f615 100644 --- a/flaim/src/fsrecupd.cpp +++ b/flaim/src/fsrecupd.cpp @@ -43,7 +43,7 @@ RCODE FSRecUpdate( { RCODE rc; BTSK stackBuf[ BH_MAX_LEVELS ]; // Stack to hold b-tree variables - BTSK_p pStack = stackBuf; // Points to a stack element + BTSK * pStack = stackBuf; // Points to a stack element FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4 ];// Key buffer pointed to by stack UCUR updCur; // Update cursor FLMBYTE * pElmBuf; // Points to updCur.buffer @@ -98,7 +98,9 @@ RCODE FSRecUpdate( } } - updCur.uiFlags = (pStack->uiCmpStatus != BT_EQ_KEY) ? UCUR_INSERT : UCUR_REPLACE; + updCur.uiFlags = (pStack->uiCmpStatus != BT_EQ_KEY) + ? UCUR_INSERT + : UCUR_REPLACE; updCur.uiDrn = uiDrn; // Update or Insert the record. @@ -170,198 +172,33 @@ Exit: return( rc); } -/**************************************************************************** -Desc: Sets or verifies the next DRN for the domain supplied. - If the domain has no data blocks then LFH area will be updated. - Must have the stack positioned to the right most tree. -Notes: All checks are very explicit to make clear for maintenance. -****************************************************************************/ -RCODE FSSetNextDrn( - FDB * pDb, // Pointer to operation context struct. - BTSK_p pStack, // Points to a stack element - FLMUINT uiDrn, // (IN) Value to update next counter - FLMBOOL bManditoryChange) // (IN) If true then must be set. -{ - RCODE rc = FERR_OK; - FLMUINT uiNextDrn; - FLMBYTE * ptr; - FLMBYTE * pBlk = GET_CABLKPTR( pStack ); - - // Next DRN marker element in b-tree. By this time, the root - // block will have been initialized. The '11' below is the size - // of the next DRN marker element. - - if( FB2UD( &pBlk[ BH_NEXT_BLK ]) == BT_END && - pStack->uiCurElm + 11 + BBE_LEM_LEN >= pStack->uiBlkEnd) - { - ptr = CURRENT_ELM( pStack); - ptr += BBE_GETR_KL( ptr) + BBE_KEY; - uiNextDrn = FB2UD( ptr); - - // Check if the DRN is 0 or more than the NEXT DRN marker - - if( uiDrn >= uiNextDrn) - { - uiNextDrn = uiDrn + 1; - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - { - goto Exit; - } - - ptr = CURRENT_ELM( pStack); - ptr += BBE_GETR_KL( ptr) + BBE_KEY; - - // Update with the next DRN value and dirty the block - - UD2FBA( uiNextDrn, ptr); - goto Exit; - } - } - - if( bManditoryChange) - { - rc = RC_SET( FERR_BTREE_ERROR); - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Sets or verifies the next DRN for the domain supplied. - If the domain is non-default domain then LFH area will be updated - for FLM_1_1 databases ONLY. FLM_1_2 stores next DRN in last block. -****************************************************************************/ -RCODE FSGetNextDrn( - FDB * pDb, // Pointer to operation context struct. - LFILE * pLFile, // Domain Logical File Definition - FLMBOOL bUpdateNextDrn, // (IN) TRUE then update next drn value - FLMUINT * puiDrnRV) // (IN) 0 or value to check if higher - // (OUT) Returns input value or next value -{ - RCODE rc = FERR_OK; - FLMUINT uiNextDrn = *puiDrnRV; - BTSK stackBuf[ BH_MAX_LEVELS]; - FLMBOOL bUsedStack = FALSE; - - if( uiNextDrn == DRN_LAST_MARKER) - { - rc = RC_SET( FERR_BAD_DRN); - goto Exit; - } - - // All containers have next DRN marker - - if( !uiNextDrn) - { - BTSK_p pStack = stackBuf; - FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4]; - FLMBYTE * ptr; - - // Set up the stack - - bUsedStack = TRUE; - FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); - pStack->pKeyBuf = pKeyBuf; - - // Make sure pLFile is up to date - - if( RC_BAD( rc = FSBtSearchEnd( pDb, pLFile, &pStack, DRN_LAST_MARKER))) - { - goto Exit; - } - - if( pLFile->uiRootBlk == BT_END) - { - *puiDrnRV = pLFile->uiNextDrn; - if( bUpdateNextDrn) - { - pLFile->uiNextDrn++; - if( RC_BAD( rc = flmLFileWrite( pDb, pLFile))) - { - pLFile->uiNextDrn--; - goto Exit; - } - } - } - else - { - if( pStack->uiCmpStatus != BT_EQ_KEY || - pLFile->uiLfNum != FB2UW( &pStack->pBlk[ BH_LOG_FILE_NUM])) - { - rc = RC_SET( FERR_BTREE_ERROR); - goto Exit; - } - - ptr = CURRENT_ELM( pStack); - ptr += BBE_GETR_KL( ptr) + BBE_KEY; - *puiDrnRV = FB2UD( ptr); - - if( bUpdateNextDrn) - { - FLMUINT32 ui32NextDrn = (FLMUINT32)(*puiDrnRV + 1); - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - { - goto Exit; - } - - ptr = CURRENT_ELM( pStack); - ptr += BBE_GETR_KL( ptr) + BBE_KEY; - - // Update with the next DRN value and dirty the block - - UD2FBA( ui32NextDrn, ptr); - } - } - } - - if( *puiDrnRV == DRN_LAST_MARKER) - { - rc = RC_SET( FERR_NO_MORE_DRNS); - goto Exit; - } - -Exit: - - if( bUsedStack) - { - FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); - } - - return( rc ); -} - /*************************************************************************** Desc: Saves a record to the file. The record may overflow & span elements. *****************************************************************************/ FSTATIC RCODE FSBldRecElement( - FDB * pDb, - LFILE * pLFile, - FlmRecord * pRecord, - UCUR * updCur) + FDB * pDb, + LFILE * pLFile, + FlmRecord * pRecord, + UCUR * updCur) { RCODE rc = FERR_OK; - FLMBYTE * pBuf = updCur->pElmBuf; - FLMBYTE * pField; - FLMBYTE * pBufEnd; - const FLMBYTE * pValue = NULL; - FLMBYTE * pOvhd; void * pvField; - FLMUINT uiBufLen = updCur->uiBufLen; - FLMUINT uiValuePos; - FLMUINT uiBytesLeft; - FLMUINT uiValueLen; + FLMBYTE * pBuf = updCur->pElmBuf; // Make pointer for performance + FLMBYTE * pField; // Points to the output field + FLMBYTE * pBufEnd; // Points to the end of the buffer + const FLMBYTE * pValue = NULL; // Points to the value on the line + FLMBYTE * pOvhd; + FLMUINT uiBufLen = updCur->uiBufLen; // Used to optimize + FLMUINT uiValuePos; // Position in the value buffer + FLMUINT uiBytesLeft; // Number of bytes left in element + FLMUINT uiValueLen; // Length of the value FLMUINT uiUsedLen = updCur->uiUsedLen; FLMUINT uiTagNum; FLMUINT uiLevel; FLMUINT uiFldType; FLMINT iLevelCntx; - FLMINT iLastNdLevel = -1; - FLMBYTE byValue; + FLMINT iLastNdLevel = -1; // Last node's level number + FLMBYTE ucBaseFlags; FLMUINT uiEncValueLen; FLMUINT uiEncTagNum; @@ -374,13 +211,16 @@ FSTATIC RCODE FSBldRecElement( FLMUINT uiEncId = 0; // Check for encryption. + bFldEncrypted = pRecord->isEncryptedField( pvField); - if (bFldEncrypted) + if( bFldEncrypted) { // May still proceed if the field is already encrypted. + uiEncFlags = pRecord->getEncFlags( pvField); // Cannot add encrypted field while in limited mode. + if (pDb->pFile->bInLimitedMode && (!(uiEncFlags & FLD_HAVE_ENCRYPTED_DATA))) { @@ -389,16 +229,13 @@ FSTATIC RCODE FSBldRecElement( } // Only encrypt the field if it isn't already encrypted. - if (!(uiEncFlags & FLD_HAVE_ENCRYPTED_DATA)) - { + if( !(uiEncFlags & FLD_HAVE_ENCRYPTED_DATA)) + { uiEncId = pRecord->getEncryptionID( pvField); - if (RC_BAD( rc = flmEncryptField( pDb->pDict, - pRecord, - pvField, - uiEncId, - &pDb->TempPool))) + if (RC_BAD( rc = flmEncryptField( + pDb->pDict, pRecord, pvField, uiEncId, &pDb->TempPool))) { goto Exit; } @@ -406,6 +243,7 @@ FSTATIC RCODE FSBldRecElement( } // First determine if there is enough room for just the tag overhead + uiBytesLeft = (FLMUINT) (uiBufLen - uiUsedLen); // Check for overflow - want all tagged fields with field overhead @@ -427,19 +265,9 @@ FSTATIC RCODE FSBldRecElement( if( bFldEncrypted) { - if (pDb->pFile->bInLimitedMode) - { - rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); - goto Exit; - } - - if (RC_BAD( rc = pRecord->getFieldInfo( pvField, - &uiTagNum, - &uiLevel, - &uiFldType, - &uiValueLen, - &uiEncValueLen, - &uiEncTagNum))) + if( RC_BAD( rc = pRecord->getFieldInfo( pvField, + &uiTagNum, &uiLevel, &uiFldType, &uiValueLen, + &uiEncValueLen, &uiEncTagNum))) { goto Exit; } @@ -448,6 +276,7 @@ FSTATIC RCODE FSBldRecElement( { uiEncValueLen = 0; uiEncTagNum = 0; + if( RC_BAD( rc = pRecord->getFieldInfo( pvField, &uiTagNum, &uiLevel, &uiFldType, &uiValueLen, NULL, NULL))) { @@ -457,13 +286,23 @@ FSTATIC RCODE FSBldRecElement( // Do data sanity checks - if( uiValueLen > 0x0000FFFF || uiEncValueLen > FLM_MAX_FIELD_VAL_SIZE) + if( pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_61) { - rc = RC_SET( FERR_VALUE_TOO_LARGE); + if( uiValueLen > 0x0000FFFF) + { + rc = RC_SET( FERR_VALUE_TOO_LARGE); + goto Exit; + } + } + + if( !uiTagNum) + { + flmAssert( 0); + rc = RC_SET( FERR_BAD_FIELD_NUM); goto Exit; } - if( !bFldEncrypted) + if (!bFldEncrypted) { if( uiFldType == FLM_NUMBER_TYPE) { @@ -505,207 +344,198 @@ FSTATIC RCODE FSBldRecElement( flmAssert( uiTagNum != 0); - if (bFldEncrypted) + if( bFldEncrypted) { flmAssert( uiEncTagNum != 0); } - if( (iLevelCntx = iLastNdLevel) == -1) // Special case to start out// + if( (iLevelCntx = iLastNdLevel) == -1) { iLevelCntx = uiLevel; } - if( (iLevelCntx -= uiLevel) > 0) // If -1 then child, 0 = sibling // + if( (iLevelCntx -= uiLevel) > 0) { do { - *pField++ = (FLMBYTE)(FOP_SET_LEVEL + // Don't forget extra parens below! - ((iLevelCntx >= FOP_LEVEL_MAX) - ? (FLMBYTE)FOP_LEVEL_MAX - : (FLMBYTE)iLevelCntx)); + *pField++ = (FLMBYTE)(FOP_SET_LEVEL + + ((iLevelCntx >= FOP_LEVEL_MAX) + ? (FLMBYTE)FOP_LEVEL_MAX + : (FLMBYTE)iLevelCntx)); iLevelCntx -= FOP_LEVEL_MAX; } while( iLevelCntx > 0 ); - iLevelCntx = 0; // Storage next as sibling + iLevelCntx = 0; } iLastNdLevel = (FLMINT) uiLevel; - /** - *** DATA CONVERSION SECTION - *** - *** No longer performed but could be done in kybuild.c - **/ - /** - *** STORAGE SECTION - *** - *** Tests to see if the field is defined in the dictionary. - *** If not, then field type will be stored with the value & tag - *** as a fully TAGGED field. All flaim tags and unregistered - *** tags are, by definition, NOT defined in the dictionary. - *** Code tries to check most common cases first. - *** - *** NOTE: The record has been verified while indexing so there is - *** no reason to read the dna table again an verify the field type. - **/ + // Get a pointer to the data (if any) if( uiValueLen) { pValue = pRecord->getDataPtr( pvField); } - if (uiEncValueLen) + if( uiEncValueLen) { flmAssert( bFldEncrypted); pValue = pRecord->getEncryptionDataPtr( pvField); flmAssert( pValue); } - // Normal field (not dictionary and not unregistered) - if( uiTagNum < FLM_DICT_FIELD_NUMS) + // Determine the FOP used for storing the field + + if( uiValueLen > 0xFFFF) { - if (!bFldEncrypted) + goto StoreLargeField; + } + else if( uiTagNum < FLM_DICT_FIELD_NUMS) + { + // Normal field (not dictionary and not unregistered) + + if( !bFldEncrypted) { - goto STORE_DEFINED_FIELD; + goto StoreDefinedField; } else { - goto STORE_ENCRYPTED_FIELD; + goto StoreEncryptedField; } } - - // If an unregistered field, store as tagged field else if( uiTagNum >= FLM_UNREGISTERED_TAGS) { - if (!bFldEncrypted) + if( !bFldEncrypted) { - goto STORE_TAGGED_FIELD; + goto StoreTaggedField; } else { - goto STORE_ENCRYPTED_FIELD; + goto StoreEncryptedField; } } - - // dictionary fields else { - if( (uiFldType == FLM_TEXT_TYPE) - || (uiFldType == FLM_CONTEXT_TYPE)) // Slight adjustment of semantics + // Dictionary fields + + if( !bFldEncrypted) { - if (!bFldEncrypted) + if( uiFldType == FLM_TEXT_TYPE || uiFldType == FLM_CONTEXT_TYPE) { - goto STORE_DEFINED_FIELD; // Most dictionary fields are text + goto StoreDefinedField; } else { - goto STORE_ENCRYPTED_FIELD; // Special handling for encrypted fields. + goto StoreTaggedField; } } - - if (!bFldEncrypted) - { - goto STORE_TAGGED_FIELD; // Non text fields in dictionary - } else { - goto STORE_ENCRYPTED_FIELD; + goto StoreEncryptedField; } - } // type in field - we just have to parse it! + } -STORE_DEFINED_FIELD: + // Store the field - if( (uiTagNum <= FSTA_MAX_FLD_NUM ) // If uiTagNum is 8 bits - && (uiValueLen <= FSTA_MAX_FLD_LEN )) // If field length fits +StoreDefinedField: + + flmAssert( uiValueLen <= 0xFFFF); + + if( uiTagNum <= FSTA_MAX_FLD_NUM && uiValueLen <= FSTA_MAX_FLD_LEN) { - /** - *** FOP_STANDARD - *** Most optimal format - **/ + // FOP_STANDARD + *pField++ = (FLMBYTE)((iLevelCntx ? 0x40 : 0) + uiValueLen); *pField++ = (FLMBYTE)uiTagNum; } else { pOvhd = pField++; + if( uiValueLen) { - /** - *** FOP_OPEN - **/ - byValue = iLevelCntx ? (FOP_OPEN + 0x08) : FOP_OPEN; -/* THIS LABEL IS NOT CURRENTLY USED -DO_FOP_OPEN: -*/ - *pField++ = (FLMBYTE) uiTagNum; + // FOP_OPEN + + ucBaseFlags = iLevelCntx ? (FOP_OPEN + 0x08) : FOP_OPEN; + *pField++ = (FLMBYTE)uiTagNum; + if( uiTagNum > 0xFF) { - byValue |= 0x02; - *pField++ = (FLMBYTE) (uiTagNum >> 8); + ucBaseFlags |= 0x02; + *pField++ = (FLMBYTE)(uiTagNum >> 8); } + *pField++ = (FLMBYTE) uiValueLen; - if( uiValueLen > 0xFF) + if( uiValueLen > 0x000000FF) { - byValue |= 0x01; - *pField++ = (FLMBYTE) (uiValueLen >> 8); + ucBaseFlags |= 0x01; + *pField++ = (FLMBYTE)(uiValueLen >> 8); } } else { - /** - *** FOP_NO_VALUE - **/ - byValue = iLevelCntx ? (FOP_NO_VALUE + 0x04) : FOP_NO_VALUE; + // FOP_NO_VALUE + + ucBaseFlags = iLevelCntx ? (FOP_NO_VALUE + 0x04) : FOP_NO_VALUE; *pField++ = (FLMBYTE) uiTagNum; + if( uiTagNum > 0xFF) { - byValue |= 0x02; + ucBaseFlags |= 0x02; *pField++ = (FLMBYTE) (uiTagNum >> 8); } } - *pOvhd = byValue; + + *pOvhd = ucBaseFlags; } - goto WRITE_VALUE_PORTION; + goto WriteValuePortion; + +StoreTaggedField: + + // FOP_TAGGED + // + // Used for data dictionary records, unregistered, and local fields. + // Format similar to FOP_OPEN except the field type is stored with + // the data. + // + // When storing the unregistered fields we cleared + // the high bit to save on storage for VER11. The problem is + // that if a tag that is not in the unregistered range + // (FLAIM TAGS) cannot be represented. SO, we will XOR the + // high bit so 0x0111 is stored as 0x8111 and 0x8222 is stored + // as 0x0222. -STORE_TAGGED_FIELD: - /** - *** FOP_TAGGED - *** Used for data dictionary records, unregistered & local fields. - *** Format similar to FOP_OPEN except the field - *** type is stored with the data. - *** When storing the unregistered fields (WPHOST) we cleared - *** the high bit to save on storage for VER11. The problem is - *** that if a tag that is not in the unregistered range - *** (FLAIM TAGS) cannot be represented. SO, we will XOR the - ** high bit so 0x0111 is stored as 0x8111 and 0x8222 is stored - *** as 0x0222. - **/ pOvhd = pField++; - byValue = iLevelCntx ? (FOP_TAGGED + 0x08) : FOP_TAGGED; - uiTagNum ^= 0x8000; /* Clear high bit if SET (VER11) or set - if it is in the FLM_TAGs range */ + ucBaseFlags = iLevelCntx + ? (FOP_TAGGED + 0x08) + : FOP_TAGGED; + + uiTagNum ^= 0x8000; // Clear high bit if SET (VER11) or set + // if it is in the FLM_TAGs range + *pField++ = (FLMBYTE) uiFldType; *pField++ = (FLMBYTE) uiTagNum; + if( uiTagNum > 0xFF) { - byValue |= 0x02; + ucBaseFlags |= 0x02; *pField++ = (FLMBYTE) (uiTagNum >> 8); } + *pField++ = (FLMBYTE) uiValueLen; if( uiValueLen > 0xFF) { - byValue |= 0x01; - *pField++ = (FLMBYTE) (uiValueLen >> 8); + ucBaseFlags |= 0x01; + *pField++ = (FLMBYTE)(uiValueLen >> 8); } - *pOvhd = byValue; - goto WRITE_VALUE_PORTION; + *pOvhd = ucBaseFlags; + goto WriteValuePortion; + +StoreEncryptedField: + + // FOP_ENCRYPTED -STORE_ENCRYPTED_FIELD: - /** - *** FOP_ENCRYPTED - **/ *pField++ = iLevelCntx ? (FOP_ENCRYPTED + 0x01) : FOP_ENCRYPTED; - *pField = (FLMBYTE)0; *pField = (FLMBYTE)(uiFldType << 4); @@ -758,23 +588,73 @@ STORE_ENCRYPTED_FIELD: // Copy the encrypted value length (uiEncValueLen) into the value length // (uiValueLength). This will be use in the next section so that we can // copy the right amount of data. + uiValueLen = uiEncValueLen; + goto WriteValuePortion; + +StoreLargeField: - goto WRITE_VALUE_PORTION; - -WRITE_VALUE_PORTION: - - /** - *** Write out the data a chunk at a time - **/ - - uiBytesLeft = (FLMUINT) (pBufEnd - pField); - if( uiValueLen <= uiBytesLeft ) + // FOP_LARGE + + // 1101 xxec + // fieldType (1 byte, 0000 ffff) + // tagNum (2 bytes) + // dataLen (4 bytes) + // + // If encrypted, the following are also present: + // + // encryptionId (2 bytes) + // encryptionLength (4 bytes) + + *pField = FOP_LARGE; + + if( iLevelCntx) { - // YES - enough room to copy the node and go on + *pField |= 0x01; + } + + if( bFldEncrypted) + { + *pField |= 0x02; + } + pField++; + + *pField = (FLMBYTE)(uiFldType & 0x0F); + pField++; + + UW2FBA( (FLMUINT16)uiTagNum, pField); + pField += 2; + + UD2FBA( (FLMUINT32)uiValueLen, pField); + pField += 4; + + if( bFldEncrypted) + { + UW2FBA( (FLMUINT16)uiEncTagNum, pField); + pField += 2; + + UD2FBA( (FLMUINT32)uiEncValueLen, pField); + pField += 4; + + // Copy the encrypted value length (uiEncValueLen) into the value length + // (uiValueLength). This will be use in the next section so that we can + // copy the right amount of data. + + uiValueLen = uiEncValueLen; + } + +WriteValuePortion: + + // Write out the data a chunk at a time + + uiBytesLeft = (FLMUINT)(pBufEnd - pField); + if( uiValueLen <= uiBytesLeft) + { + // YES - enough room to copy the node and go on + if( uiValueLen) { - f_memcpy( pField, pValue, uiValueLen ); + f_memcpy( pField, pValue, uiValueLen); pField += uiValueLen; } } @@ -787,9 +667,12 @@ WRITE_VALUE_PORTION: for( ;;) { FLMUINT uiTemp; - f_memcpy( pField, &pValue[ uiValuePos ], uiBytesLeft ); + + f_memcpy( pField, &pValue[ uiValuePos], uiBytesLeft); + pField += uiBytesLeft; uiValuePos += uiBytesLeft; + if( uiValuePos >= uiValueLen) { break; @@ -798,7 +681,7 @@ WRITE_VALUE_PORTION: updCur->uiUsedLen = uiUsedLen = uiBufLen; - if( RC_BAD(rc = FSFlushElement( pDb, pLFile, updCur ))) + if( RC_BAD( rc = FSFlushElement( pDb, pLFile, updCur ))) { goto Exit; } @@ -817,9 +700,9 @@ WRITE_VALUE_PORTION: } } - // Set the used length and get the next node - - updCur->uiUsedLen = uiUsedLen = (FLMUINT) (pField - pBuf); + // Set the used length and get the next node + + updCur->uiUsedLen = uiUsedLen = (FLMUINT)(pField - pBuf); } Exit: @@ -836,7 +719,7 @@ RCODE FSFlushElement( UCUR * updCur) { RCODE rc = FERR_OK; - BTSK_p pStack = updCur->pStack; + BTSK * pStack = updCur->pStack; FLMBYTE * pElmBuf = updCur->pElmBuf; FLMUINT uiFlags = updCur->uiFlags; FLMBOOL bIsLast = FALSE; @@ -969,3 +852,168 @@ Exit: return( rc ); } + +/**************************************************************************** +Desc: Sets or verifies the next DRN for the domain supplied. + If the domain has no data blocks then LFH area will be updated. + Must have the stack positioned to the right most tree. +Notes: All checks are very explicit to make clear for maintenance. +****************************************************************************/ +RCODE FSSetNextDrn( + FDB * pDb, // Pointer to operation context struct. + BTSK * pStack, // Points to a stack element + FLMUINT uiDrn, // (IN) Value to update next counter + FLMBOOL bManditoryChange) // (IN) If true then must be set. +{ + RCODE rc = FERR_OK; + FLMUINT uiNextDrn; + FLMBYTE * ptr; + FLMBYTE * pBlk = GET_CABLKPTR( pStack ); + + // Next DRN marker element in b-tree. By this time, the root + // block will have been initialized. The '11' below is the size + // of the next DRN marker element. + + if( FB2UD( &pBlk[ BH_NEXT_BLK ]) == BT_END && + pStack->uiCurElm + 11 + BBE_LEM_LEN >= pStack->uiBlkEnd) + { + ptr = CURRENT_ELM( pStack); + ptr += BBE_GETR_KL( ptr) + BBE_KEY; + uiNextDrn = FB2UD( ptr); + + // Check if the DRN is 0 or more than the NEXT DRN marker + + if( uiDrn >= uiNextDrn) + { + uiNextDrn = uiDrn + 1; + + if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + ptr = CURRENT_ELM( pStack); + ptr += BBE_GETR_KL( ptr) + BBE_KEY; + + // Update with the next DRN value and dirty the block + + UD2FBA( uiNextDrn, ptr); + goto Exit; + } + } + + if( bManditoryChange) + { + rc = RC_SET( FERR_BTREE_ERROR); + goto Exit; + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Sets or verifies the next DRN for the domain supplied. + If the domain is non-default domain then LFH area will be updated + for FLM_1_1 databases ONLY. FLM_1_2 stores next DRN in last block. +****************************************************************************/ +RCODE FSGetNextDrn( + FDB * pDb, // Pointer to operation context struct. + LFILE * pLFile, // Domain Logical File Definition + FLMBOOL bUpdateNextDrn, // (IN) TRUE then update next drn value + FLMUINT * puiDrnRV) // (IN) 0 or value to check if higher + // (OUT) Returns input value or next value +{ + RCODE rc = FERR_OK; + FLMUINT uiNextDrn = *puiDrnRV; + BTSK stackBuf[ BH_MAX_LEVELS]; + FLMBOOL bUsedStack = FALSE; + + if( uiNextDrn == DRN_LAST_MARKER) + { + rc = RC_SET( FERR_BAD_DRN); + goto Exit; + } + + // All containers have next DRN marker + + if( !uiNextDrn) + { + BTSK * pStack = stackBuf; + FLMBYTE pKeyBuf[ DIN_KEY_SIZ + 4]; + FLMBYTE * ptr; + + // Set up the stack + + bUsedStack = TRUE; + FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); + pStack->pKeyBuf = pKeyBuf; + + // Make sure pLFile is up to date + + if( RC_BAD( rc = FSBtSearchEnd( pDb, pLFile, &pStack, DRN_LAST_MARKER))) + { + goto Exit; + } + + if( pLFile->uiRootBlk == BT_END) + { + *puiDrnRV = pLFile->uiNextDrn; + if( bUpdateNextDrn) + { + pLFile->uiNextDrn++; + if( RC_BAD( rc = flmLFileWrite( pDb, pLFile))) + { + pLFile->uiNextDrn--; + goto Exit; + } + } + } + else + { + if( pStack->uiCmpStatus != BT_EQ_KEY || + pLFile->uiLfNum != FB2UW( &pStack->pBlk[ BH_LOG_FILE_NUM])) + { + rc = RC_SET( FERR_BTREE_ERROR); + goto Exit; + } + + ptr = CURRENT_ELM( pStack); + ptr += BBE_GETR_KL( ptr) + BBE_KEY; + *puiDrnRV = FB2UD( ptr); + + if( bUpdateNextDrn) + { + FLMUINT32 ui32NextDrn = (FLMUINT32)(*puiDrnRV + 1); + + if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + ptr = CURRENT_ELM( pStack); + ptr += BBE_GETR_KL( ptr) + BBE_KEY; + + // Update with the next DRN value and dirty the block + + UD2FBA( ui32NextDrn, ptr); + } + } + } + + if( *puiDrnRV == DRN_LAST_MARKER) + { + rc = RC_SET( FERR_NO_MORE_DRNS); + goto Exit; + } + +Exit: + + if( bUsedStack) + { + FSReleaseStackCache( stackBuf, BH_MAX_LEVELS, FALSE); + } + + return( rc ); +} diff --git a/flaim/src/fsrefspl.cpp b/flaim/src/fsrefspl.cpp index fd7e125..e458465 100644 --- a/flaim/src/fsrefspl.cpp +++ b/flaim/src/fsrefspl.cpp @@ -1,319 +1,363 @@ -//------------------------------------------------------------------------- -// Desc: Index reference splitting routines. -// Tabs: 3 -// -// Copyright (c) 1991-2000,2002-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsrefspl.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC FLMUINT FSSplitRefSet( - FLMBYTE * leftBuf, - FLMUINT * leftLenRV, - FLMBYTE * rightBuf, - FLMUINT * rightLenRV, - FLMBYTE * refPtr, - FLMUINT uiRefLen, - FLMUINT uiSplitFactor); - -/**************************************************************************** -Desc: Try to split a reference set. The size is over the first threshold. - If you split this update the b-tree with the new element and position - to the current element for insert of the din. -Out: The element may be split, or may not. It is not the callers concern. -****************************************************************************/ -RCODE FSRefSplit( - FDB * pDb, - LFILE * pLFile, - BTSK_p * pStackRV, /* Stack area */ - FLMBYTE * pElmBuf, /* Setup with elements key */ - FLMUINT din, /* din to insert */ - FLMUINT uiDeleteFlag, /* Set if you are to delete din */ - FLMUINT uiSplitFactor) /* Set to SPLIT_90_10 | SPLIT_50_50*/ -{ - RCODE rc = FERR_OK; /* Must be set */ - BTSK_p pStack = *pStackRV; /* Stack may change on you! */ - FLMBYTE * pCurElm = CURRENT_ELM( pStack );/* Points to current element*/ - FLMINT iElmLen; /* Length of element in pElmBuf[] */ - - FLMBYTE leftBuf[ MAX_REC_ELM ]; /* Left buffer */ - FLMUINT leftDomain; - FLMUINT leftLen; - - FLMBYTE rightBuf[MAX_REC_ELM ]; /* Right (current) buffer */ - FLMUINT rightDomain; - FLMUINT rightLen; - - FLMBYTE * refPtr; /* Points to the references */ - FLMBYTE * recPtr; - FLMUINT uiRefLen; /* Length of references */ - FLMUINT firstFlag = 0; - - refPtr = pCurElm; - recPtr = BBE_REC_PTR( pCurElm ); - rightDomain = FSGetDomain( &refPtr, (FLMBYTE)pStack->uiElmOvhd ); - uiRefLen = (FLMUINT)(BBE_GET_RL( pCurElm ) - (FLMUINT)(refPtr - recPtr)); -FSRS_try_again: - leftDomain = FSSplitRefSet( leftBuf, &leftLen, rightBuf, &rightLen, - refPtr, uiRefLen, uiSplitFactor ); - - if( leftDomain == 0) /* Split failed, setup to add */ - { - /* Try again using a different split factor - OK to fail above */ - /* In the future, should just handle no splitting and go on */ - if( uiSplitFactor == SPLIT_50_50) - { - uiSplitFactor = SPLIT_90_10; - goto FSRS_try_again; - } -#if 0 - return( RC_SET( FERR_BTREE_ERROR)); /* Can't handle this right now */ -#else - /* Setup for inserting the din into the right buffer and call replace */ - leftDomain = DIN_DOMAIN(din) + 1; - f_memcpy( rightBuf, refPtr, rightLen = uiRefLen ); - leftLen = 0; -#endif - } - /** - *** Write the right element's references. - *** Write the right domain if non-zero and replace element - **/ - - iElmLen = (FLMINT)(BBE_REC_OFS( pElmBuf )); - refPtr = recPtr = &pElmBuf[ iElmLen ]; - if( rightDomain) /* Write the domain if present */ - { - *refPtr++ = SEN_DOMAIN; - SENPutNextVal( &refPtr, rightDomain ); - } - - if( DIN_DOMAIN(din) < leftDomain) /* Remember references DESCEND */ - { - /* Build element inserting the input din */ - if( uiDeleteFlag) - { - if( FSSetDeleteRef( refPtr, rightBuf, din, &rightLen)) - { - /* rightLen should not have changed if error found */ - return ( RC_SET( FERR_KEY_NOT_FOUND) ); -#if 0 - f_memcpy( refPtr, rightBuf, rightLen ); - rc = RC_SET( FERR_KEY_NOT_FOUND); /* Return with this error */ -#endif - } - } - else if( FSSetInsertRef( refPtr, rightBuf, din, &rightLen )) - { - /* Reference there so give up and return success */ - goto Exit; /* rc is set to FERR_OK */ - } - } - else - f_memcpy( refPtr, rightBuf, rightLen ); - - /* The other flags and lengths are been set by the caller */ - iElmLen += BBE_SET_RL( pElmBuf, rightLen + (FLMUINT) (refPtr - recPtr )); - - if( BBE_IS_FIRST( pElmBuf ) && leftLen) - { - firstFlag++; - BBE_CLR_FIRST( pElmBuf ); /* Element will no longer be first */ - - /* Log the block before modifying it. */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - goto Exit; - pCurElm = CURRENT_ELM( pStack );/* Points to current element*/ - - BBE_CLR_FIRST( pCurElm ); /* Clear first flag */ - - /* Call replace below because FIRST flag is now clear */ - } - - /* Can call replace because FIRST flag was NOT set */ - if( RC_BAD( rc = FSBtReplace( pDb, pLFile, &pStack, pElmBuf, iElmLen ))) - goto Exit; - - /** - *** Write the left buffer - *** Should be positioned to the right buffer - *** - **/ - if( leftLen) - { - /** - *** Adjust variables to build and point to the - *** left buffers references. Set the domain - *** and insert into the b-tree. Then go to the next element - **/ - BBE_CLR_LAST( pElmBuf ); /* Element will no longer be last */ - if( firstFlag) - BBE_SET_FIRST( pElmBuf); - iElmLen = (FLMINT)(BBE_REC_OFS( pElmBuf )); - refPtr = recPtr = &pElmBuf[ iElmLen ]; - *refPtr++ = SEN_DOMAIN; - SENPutNextVal( &refPtr, leftDomain ); - - if( DIN_DOMAIN(din) >= leftDomain) - { - /* Build element inserting the input din */ - if( uiDeleteFlag) - { - if( FSSetDeleteRef( refPtr, leftBuf, din, &leftLen)) - return( RC_SET( FERR_KEY_NOT_FOUND )); - } - else - /* If this returned with an error code, is alreay in set */ - if( FSSetInsertRef( refPtr, leftBuf, din, &leftLen )) - f_memcpy( refPtr, leftBuf, leftLen ); - } - else - f_memcpy( refPtr, leftBuf, leftLen ); - - iElmLen += BBE_SET_RL( pElmBuf, leftLen + (FLMUINT) (refPtr - recPtr)); - - /* Setup the pStack and bsKeyBuf[] for the insert */ - - if( RC_BAD(rc = FSBtScanTo( pStack, &pElmBuf[ BBE_KEY ], - (FLMUINT)(BBE_GET_KL(pElmBuf)), 0))) - goto Exit; - - rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuf, iElmLen ); - } -Exit: - return( rc ); -} - -/**************************************************************************** -Desc: Split a reference set within a domain value. If buffer cannot be - split then will return a leftDomain value of ZERO. - Must have a minimum of 2 references in left and right buffers. -Out: References split to the left or right buffers. -Return: 0 if the split failed, else the leftDomain value -Notes: Two references are needed in each side because one reference may - be deleted leaving the left buffer with a domain & maybe should not. -****************************************************************************/ -FSTATIC FLMUINT FSSplitRefSet( - FLMBYTE * leftBuf, - FLMUINT * leftLenRV, - FLMBYTE * rightBuf, - FLMUINT * rightLenRV, - FLMBYTE * refPtr, - FLMUINT uiRefLen, - FLMUINT uiSplitFactor) /* Set to SPLIT_90_10 | SPLIT_50_50*/ -{ - FLMUINT leftDomain = 0; - FLMUINT din = 0; - FLMUINT oneRuns = 0; - FLMUINT delta; - FLMUINT rightLen; - FLMUINT offsetTarget = (uiSplitFactor == SPLIT_90_10) - ? REF_SPLIT_90_10 : REF_SPLIT_50_50; - DIN_STATE leftState, rightState, refState; - FLMBYTE byValue; - FLMUINT uiLeftCnt; - - RESET_DINSTATE( leftState ); - RESET_DINSTATE( rightState); - RESET_DINSTATE( refState ); - - /* Read the first din value */ - din = DINNextVal( refPtr, &refState ); - DINPutNextVal( leftBuf, &leftState, din ); - uiLeftCnt = 1; - - // Must have at least 2 in the left buffer. - - while( refState.uiOffset < offsetTarget || uiLeftCnt < 2) - { - byValue = refPtr[ refState.uiOffset ]; - if( DIN_IS_REAL_ONE_RUN( byValue )) - { - oneRuns = DINOneRunVal( refPtr, &refState ); - DINPutOneRunVal( leftBuf, &leftState, oneRuns ); - din -= oneRuns; - } - else - { - delta = DINNextVal( refPtr, &refState ); - DINPutNextVal( leftBuf, &leftState, delta ); - din -= delta; - } - uiLeftCnt++; - } - - /* Made it past the target point - find where domain changes */ - leftDomain = DIN_DOMAIN( din ); - - /* Don't parse past the end */ - while( refState.uiOffset < uiRefLen) - { - byValue = refPtr[ refState.uiOffset ]; - if( DIN_IS_REAL_ONE_RUN( byValue )) - { - oneRuns = DINOneRunVal( refPtr, &refState ); - if( DIN_DOMAIN(din-oneRuns) != leftDomain) - { - /* This is tricky, write only correct number of one runs */ - delta = din & 0xFF; - if( delta) - DINPutOneRunVal( leftBuf, &leftState, delta ); - - /* Increment delta because setting up for next element */ - delta++; - oneRuns -= delta; - /* Write din and one runs below */ - din -= delta; - break; - } - DINPutOneRunVal( leftBuf, &leftState, oneRuns ); - din -= oneRuns; - } - else - { - delta = DINNextVal( refPtr, &refState ); - din -= delta; - if( DIN_DOMAIN(din) != leftDomain) - { - oneRuns = 0; - break; - } - DINPutNextVal( leftBuf, &leftState, delta ); - } - } - if( refState.uiOffset == uiRefLen) - return( 0 ); /* Cannot split, caller take care of*/ - - /* Start writing to the right side, compare /w uiRefLen proves > 2 refs */ - DINPutNextVal( rightBuf, &rightState, din ); - if( oneRuns) - DINPutOneRunVal( rightBuf, &rightState, oneRuns ); - - *leftLenRV = leftState.uiOffset; - rightLen = (FLMUINT)(uiRefLen - refState.uiOffset); - - f_memcpy( &rightBuf[ rightState.uiOffset ], - &refPtr[ refState.uiOffset ], - rightLen ); - - *rightLenRV = rightLen + rightState.uiOffset; - - return( leftDomain ); -} +//------------------------------------------------------------------------- +// Desc: Index reference splitting routines. +// Tabs: 3 +// +// Copyright (c) 1991-2000,2002-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fsrefspl.cpp 12286 2006-01-19 14:55:18 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC FLMUINT FSSplitRefSet( + FLMBYTE * leftBuf, + FLMUINT * leftLenRV, + FLMBYTE * rightBuf, + FLMUINT * rightLenRV, + FLMBYTE * refPtr, + FLMUINT uiRefLen, + FLMUINT uiSplitFactor); + +/*************************************************************************** +Desc: Try to split a reference set. The size is over the first threshold. + If you split this update the b-tree with the new element and position + to the current element for insert of the din. +***************************************************************************/ +RCODE FSRefSplit( + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMBYTE * pElmBuf, + FLMUINT din, + FLMUINT uiDeleteFlag, + FLMUINT uiSplitFactor) +{ + RCODE rc = FERR_OK; + BTSK * pStack = *pStackRV; + FLMBYTE * pCurElm = CURRENT_ELM( pStack); + FLMINT iElmLen; + FLMBYTE leftBuf[MAX_REC_ELM]; + FLMUINT leftDomain; + FLMUINT leftLen; + FLMBYTE rightBuf[MAX_REC_ELM]; + FLMUINT rightDomain; + FLMUINT rightLen; + FLMBYTE * refPtr; + FLMBYTE * recPtr; + FLMUINT uiRefLen; + FLMUINT firstFlag = 0; + + refPtr = pCurElm; + recPtr = BBE_REC_PTR( pCurElm); + rightDomain = FSGetDomain( &refPtr, (FLMBYTE) pStack->uiElmOvhd); + uiRefLen = (FLMUINT) (BBE_GET_RL( pCurElm) - (FLMUINT) (refPtr - recPtr)); + +FSRS_try_again: + + leftDomain = FSSplitRefSet( leftBuf, &leftLen, rightBuf, &rightLen, refPtr, + uiRefLen, uiSplitFactor); + + if (leftDomain == 0) + { + // Split failed, setup to add + // + // Try again using a different split factor - OK to fail above; + // In the future, should just handle no splitting and go on + + if (uiSplitFactor == SPLIT_50_50) + { + uiSplitFactor = SPLIT_90_10; + goto FSRS_try_again; + } + + // Setup for inserting the din into the right buffer and call + // replace + + leftDomain = DIN_DOMAIN( din) + 1; + f_memcpy( rightBuf, refPtr, rightLen = uiRefLen); + leftLen = 0; + } + + // Write the right element's references. Write the right domain if + // non-zero and replace element + + iElmLen = (FLMINT) (BBE_REC_OFS( pElmBuf)); + refPtr = recPtr = &pElmBuf[iElmLen]; + + if (rightDomain) + { + *refPtr++ = SEN_DOMAIN; + SENPutNextVal( &refPtr, rightDomain); + } + + if (DIN_DOMAIN( din) < leftDomain) + { + + // Build element inserting the input din + + if (uiDeleteFlag) + { + if (FSSetDeleteRef( refPtr, rightBuf, din, &rightLen)) + { + + // rightLen should not have changed if error found + + return (RC_SET( FERR_KEY_NOT_FOUND)); + } + } + else if (FSSetInsertRef( refPtr, rightBuf, din, &rightLen)) + { + + // Reference there so give up and return success + + goto Exit; + } + } + else + { + f_memcpy( refPtr, rightBuf, rightLen); + } + + // The other flags and lengths are been set by the caller + + iElmLen += BBE_SET_RL( pElmBuf, rightLen + (FLMUINT) (refPtr - recPtr)); + + if (BBE_IS_FIRST( pElmBuf) && leftLen) + { + firstFlag++; + BBE_CLR_FIRST( pElmBuf); + + // Log the block before modifying it. + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + pCurElm = CURRENT_ELM( pStack); + BBE_CLR_FIRST( pCurElm); + + // Call replace below because FIRST flag is now clear + } + + // Can call replace because FIRST flag was NOT set + + if (RC_BAD( rc = FSBtReplace( pDb, pLFile, &pStack, pElmBuf, iElmLen))) + { + goto Exit; + } + + // Write the left buffer Should be positioned to the right buffer + + if (leftLen) + { + + // Adjust variables to build and point to the left buffers + // references. Set the domain and insert into the b-tree. Then go to + // the next element + + BBE_CLR_LAST( pElmBuf); + if (firstFlag) + { + BBE_SET_FIRST( pElmBuf); + } + + iElmLen = (FLMINT) (BBE_REC_OFS( pElmBuf)); + refPtr = recPtr = &pElmBuf[iElmLen]; + *refPtr++ = SEN_DOMAIN; + SENPutNextVal( &refPtr, leftDomain); + + if (DIN_DOMAIN( din) >= leftDomain) + { + + // Build element inserting the input din + + if (uiDeleteFlag) + { + if (FSSetDeleteRef( refPtr, leftBuf, din, &leftLen)) + { + return (RC_SET( FERR_KEY_NOT_FOUND)); + } + } + else + { + if (FSSetInsertRef( refPtr, leftBuf, din, &leftLen)) + { + f_memcpy( refPtr, leftBuf, leftLen); + } + } + } + else + { + f_memcpy( refPtr, leftBuf, leftLen); + } + + iElmLen += BBE_SET_RL( pElmBuf, leftLen + (FLMUINT) (refPtr - recPtr)); + + // Setup the pStack and bsKeyBuf[] for the insert + + if (RC_BAD( rc = FSBtScanTo( pStack, &pElmBuf[BBE_KEY], + (FLMUINT) (BBE_GET_KL( pElmBuf)), 0))) + { + goto Exit; + } + + rc = FSBtInsert( pDb, pLFile, &pStack, pElmBuf, iElmLen); + } + +Exit: + + return (rc); +} + +/*************************************************************************** +Desc: Split a reference set within a domain value. If buffer cannot be + split then will return a leftDomain value of ZERO. Must have a + minimum of 2 references in left and right buffers. +***************************************************************************/ +FSTATIC FLMUINT FSSplitRefSet( + FLMBYTE * leftBuf, + FLMUINT * leftLenRV, + FLMBYTE * rightBuf, + FLMUINT * rightLenRV, + FLMBYTE * refPtr, + FLMUINT uiRefLen, + FLMUINT uiSplitFactor) +{ + FLMUINT leftDomain = 0; + FLMUINT din = 0; + FLMUINT oneRuns = 0; + FLMUINT delta; + FLMUINT rightLen; + FLMUINT offsetTarget; + DIN_STATE leftState; + DIN_STATE rightState; + DIN_STATE refState; + FLMBYTE byValue; + FLMUINT uiLeftCnt; + + RESET_DINSTATE( leftState); + RESET_DINSTATE( rightState); + RESET_DINSTATE( refState); + + offsetTarget = (uiSplitFactor == SPLIT_90_10) + ? REF_SPLIT_90_10 + : REF_SPLIT_50_50; + + // Read the first din value + + din = DINNextVal( refPtr, &refState); + DINPutNextVal( leftBuf, &leftState, din); + uiLeftCnt = 1; + + // Must have at least 2 in the left buffer. + + while (refState.uiOffset < offsetTarget || uiLeftCnt < 2) + { + byValue = refPtr[refState.uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + oneRuns = DINOneRunVal( refPtr, &refState); + DINPutOneRunVal( leftBuf, &leftState, oneRuns); + din -= oneRuns; + } + else + { + delta = DINNextVal( refPtr, &refState); + DINPutNextVal( leftBuf, &leftState, delta); + din -= delta; + } + + uiLeftCnt++; + } + + // Made it past the target point - find where domain changes + + leftDomain = DIN_DOMAIN( din); + + // Don't parse past the end + + while (refState.uiOffset < uiRefLen) + { + byValue = refPtr[refState.uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + oneRuns = DINOneRunVal( refPtr, &refState); + if (DIN_DOMAIN( din - oneRuns) != leftDomain) + { + + // This is tricky, write only correct number of one runs + + delta = din & 0xFF; + if (delta) + { + DINPutOneRunVal( leftBuf, &leftState, delta); + } + + // Increment delta because setting up for next element + + delta++; + oneRuns -= delta; + + // Write din and one runs below + + din -= delta; + break; + } + + DINPutOneRunVal( leftBuf, &leftState, oneRuns); + din -= oneRuns; + } + else + { + delta = DINNextVal( refPtr, &refState); + din -= delta; + if (DIN_DOMAIN( din) != leftDomain) + { + oneRuns = 0; + break; + } + + DINPutNextVal( leftBuf, &leftState, delta); + } + } + + if (refState.uiOffset == uiRefLen) + { + // Cannot split, caller take care of + + return (0); + } + + // Start writing to the right side, compare /w uiRefLen proves > 2 refs + + DINPutNextVal( rightBuf, &rightState, din); + if (oneRuns) + { + DINPutOneRunVal( rightBuf, &rightState, oneRuns); + } + + *leftLenRV = leftState.uiOffset; + rightLen = (FLMUINT) (uiRefLen - refState.uiOffset); + + f_memcpy( &rightBuf[rightState.uiOffset], &refPtr[refState.uiOffset], + rightLen); + + *rightLenRV = rightLen + rightState.uiOffset; + return (leftDomain); +} diff --git a/flaim/src/fsrefupd.cpp b/flaim/src/fsrefupd.cpp index 823ebdb..e20e0da 100644 --- a/flaim/src/fsrefupd.cpp +++ b/flaim/src/fsrefupd.cpp @@ -24,106 +24,95 @@ #include "flaimsys.h" -/* #define REF_TESTING - set for quick testing */ +extern FLMBYTE SENLenArray[]; -#define INSERT_REF 0 -#define DELETE_REF 1 -#define SPLIT_90_10 0 -#define SPLIT_50_50 1 - -/**-------------------- -*** Static routines -***-------------------*/ +#define INSERT_REF 0 +#define DELETE_REF 1 +#define SPLIT_90_10 0 +#define SPLIT_50_50 1 FSTATIC RCODE FSUpdateIxCounts( - FDB * pDb, - IXD * pIxd, - FLMBYTE byFlags, - FLMBOOL bSingleRef); + FDB * pDb, + IXD * pIxd, + FLMBYTE byFlags, + FLMBOOL bSingleRef); FSTATIC RCODE FSOutputIxCounts( - FDB * pDb, - IX_STATS * pIxStats); + FDB * pDb, + IX_STATS * pIxStats); FSTATIC RCODE FSRefCreateRec( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack); + KREF_ENTRY * pKrefEntry, + BTSK * pStack); FSTATIC RCODE FSRefInsert( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack); + KREF_ENTRY * pKrefEntry, + BTSK * pStack); FSTATIC RCODE FSRefDelete( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack, + KREF_ENTRY * pKrefEntry, + BTSK * pStack, FLMBOOL * pbSingleRef); - -// Defined in fsnext.cpp -extern FLMBYTE SENLenArray[]; - -/*************************************************************************** -Desc: Update (add or delete) a single reference -TODO: Index by the logical file attribute to determine the compression - method of the index. Try multipling by index compression type. -*****************************************************************************/ +/**************************************************************************** +Desc: Update (add or delete) a single reference +****************************************************************************/ RCODE FSRefUpdate( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry - ) + KREF_ENTRY * pKrefEntry) { - RCODE rc; - BTSK stackBuf[ BH_MAX_LEVELS ]; // Stack to hold b-tree variables - BTSK_p pStack = stackBuf; // Points to proper stack frame - FLMUINT uiDinDomain = DIN_DOMAIN( pKrefEntry->uiDrn) + 1; // Lower bounds - FLMBYTE byFlags = (FLMBYTE)pKrefEntry->uiFlags; + RCODE rc = FERR_OK; + BTSK stackBuf[BH_MAX_LEVELS]; + BTSK * pStack = stackBuf; + FLMUINT uiDinDomain = DIN_DOMAIN( pKrefEntry->uiDrn) + 1; + FLMBYTE byFlags = (FLMBYTE) pKrefEntry->uiFlags; FLMBOOL bSingleRef = FALSE; FLMBOOL bAddReference = (byFlags & KREF_DELETE_FLAG) ? FALSE : TRUE; - FLMBYTE pKeyBuf[ MAX_KEY_SIZ ]; // Key buffer pointed to by stack + FLMBYTE pKeyBuf[MAX_KEY_SIZ]; FSRU_try_again: - + if (pKrefEntry->uiFlags & KREF_ENCRYPTED_KEY) { + // Can't allow updates whit these keys. + flmAssert( pDb->pFile->bInLimitedMode); rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); goto Exit; } - - FSInitStackCache( &stackBuf [0], BH_MAX_LEVELS); + + FSInitStackCache( &stackBuf[0], BH_MAX_LEVELS); pStack = stackBuf; pStack->pKeyBuf = pKeyBuf; - if( RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, - (FLMBYTE *) &pKrefEntry[1], pKrefEntry->ui16KeyLen, uiDinDomain))) + if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, (FLMBYTE*) &pKrefEntry[1], + pKrefEntry->ui16KeyLen, uiDinDomain))) { - // GWBUG 57352: July 17, 1998. Had a return() here that would - // keep block use count on block. goto Exit; } - // If pStack->bsStatus == REC_NOT_FOUND create a new element - // if found then add the reference into the found element. + // If pStack->bsStatus == REC_NOT_FOUND create a new element if found + // then add the reference into the found element. - if( pStack->uiCmpStatus == BT_EQ_KEY) + if (pStack->uiCmpStatus == BT_EQ_KEY) { - if( (byFlags & KREF_UNIQUE_KEY) && !(byFlags & KREF_DELETE_FLAG)) + if ((byFlags & KREF_UNIQUE_KEY) && !(byFlags & KREF_DELETE_FLAG)) { rc = RC_SET( FERR_NOT_UNIQUE); goto Exit; } - if( pLFile->pIxd->uiFlags & IXD_POSITIONING) + if (pLFile->pIxd->uiFlags & IXD_POSITIONING) { - if ( RC_BAD( rc = FSChangeCount( pDb, pStack, bAddReference))) + if (RC_BAD( rc = FSChangeCount( pDb, pStack, bAddReference))) { goto Exit; } @@ -131,15 +120,17 @@ FSRU_try_again: bSingleRef = FALSE; - if( bAddReference) + if (bAddReference) { - if( RC_BAD( rc = FSRefInsert( pDb, pLFile, pKrefEntry, pStack))) + if (RC_BAD( rc = FSRefInsert( pDb, pLFile, pKrefEntry, pStack))) + { goto Exit; + } } else { - if( RC_BAD( rc = FSRefDelete( pDb, pLFile, - pKrefEntry, pStack, &bSingleRef))) + if (RC_BAD( rc = FSRefDelete( pDb, pLFile, pKrefEntry, pStack, + &bSingleRef))) { goto Exit; } @@ -147,9 +138,11 @@ FSRU_try_again: } else { - if( !bAddReference) + if (!bAddReference) { + // Already been deleted, ignore the error condition and go on. + flmAssert( 0); rc = FERR_OK; goto Exit; @@ -157,9 +150,9 @@ FSRU_try_again: // The B-Tree may be empty - if( pLFile->uiRootBlk == BT_END) + if (pLFile->uiRootBlk == BT_END) { - if( RC_BAD( rc = flmLFileInit( pDb, pLFile))) + if (RC_BAD( rc = flmLFileInit( pDb, pLFile))) { goto Exit; } @@ -168,18 +161,18 @@ FSRU_try_again: goto FSRU_try_again; } - if( pLFile->pIxd->uiFlags & IXD_POSITIONING) + if (pLFile->pIxd->uiFlags & IXD_POSITIONING) { - if ( RC_BAD( rc = FSChangeCount( pDb, pStack, TRUE))) + if (RC_BAD( rc = FSChangeCount( pDb, pStack, TRUE))) { goto Exit; } } // Add new key|reference element. - + bSingleRef = TRUE; - if( RC_BAD( rc = FSRefCreateRec( pDb, pLFile, pKrefEntry, pStack ))) + if (RC_BAD( rc = FSRefCreateRec( pDb, pLFile, pKrefEntry, pStack))) { goto Exit; } @@ -192,19 +185,19 @@ Exit: { rc = FSUpdateIxCounts( pDb, pLFile->pIxd, byFlags, bSingleRef); } - return( rc ); + + return (rc); } -/*************************************************************************** -Desc: Update the index reference and/or key counts in memory only. Counts +/**************************************************************************** +Desc: Update the index reference and/or key counts in memory only. Counts are not written to the database until transaction commit time. -*****************************************************************************/ +****************************************************************************/ FSTATIC RCODE FSUpdateIxCounts( - FDB * pDb, - IXD * pIxd, - FLMBYTE byFlags, - FLMBOOL bSingleRef - ) + FDB * pDb, + IXD * pIxd, + FLMBYTE byFlags, + FLMBOOL bSingleRef) { RCODE rc = FERR_OK; IX_STATS * pIxStat; @@ -221,10 +214,11 @@ FSTATIC RCODE FSUpdateIxCounts( if (!pIxStat) { - if (RC_BAD( rc = f_calloc( sizeof( IX_STATS), &pIxStat))) + if (RC_BAD( rc = f_calloc( sizeof(IX_STATS), &pIxStat))) { goto Exit; } + pIxStat->uiIndexNum = pIxd->uiIndexNum; pIxStat->pNext = pDb->pIxStats; pDb->pIxStats = pIxStat; @@ -238,6 +232,7 @@ FSTATIC RCODE FSUpdateIxCounts( { pIxStat->iDeltaKeys--; } + pIxStat->iDeltaRefs--; } else @@ -246,28 +241,30 @@ FSTATIC RCODE FSUpdateIxCounts( { pIxStat->iDeltaKeys++; } + pIxStat->iDeltaRefs++; } + Exit: - return( rc); + + return (rc); } -/*************************************************************************** -Desc: Output the index reference and/or key counts by writing them to - the tracker record. -*****************************************************************************/ +/**************************************************************************** +Desc: Output the index reference and/or key counts by writing them to the + tracker record. +****************************************************************************/ FSTATIC RCODE FSOutputIxCounts( FDB * pDb, - IX_STATS * pIxStats - ) + IX_STATS * pIxStats) { - RCODE rc = FERR_OK; - FLMBOOL bCreateRec; - FlmRecord * pRecord = NULL; - FlmRecord * pTmpRec = NULL; - void * pvField; - FLMUINT uiCount; - LFILE * pLFile; + RCODE rc = FERR_OK; + FLMBOOL bCreateRec; + FlmRecord * pRecord = NULL; + FlmRecord * pTmpRec = NULL; + void * pvField; + FLMUINT uiCount; + LFILE * pLFile; // If no counts changed, do nothing @@ -276,8 +273,8 @@ FSTATIC RCODE FSOutputIxCounts( goto Exit; } - if (RC_BAD( rc = fdictGetContainer( pDb->pDict, - FLM_TRACKER_CONTAINER, &pLFile))) + if (RC_BAD( rc = fdictGetContainer( pDb->pDict, FLM_TRACKER_CONTAINER, + &pLFile))) { goto Exit; } @@ -285,12 +282,13 @@ FSTATIC RCODE FSOutputIxCounts( // Retrieve the tracker record from record cache. if (RC_BAD( rc = flmRcaRetrieveRec( pDb, NULL, FLM_TRACKER_CONTAINER, - pIxStats->uiIndexNum, TRUE, NULL, NULL, &pRecord))) + pIxStats->uiIndexNum, TRUE, NULL, NULL, &pRecord))) { if (rc != FERR_NOT_FOUND) { goto Exit; } + bCreateRec = TRUE; rc = FERR_OK; } @@ -299,11 +297,11 @@ FSTATIC RCODE FSOutputIxCounts( bCreateRec = FALSE; } - // If there was no record, create one. Otherwise, copy the record + // If there was no record, create one. Otherwise, copy the record if (bCreateRec) { - if( (pTmpRec = f_new FlmRecord) == NULL) + if ((pTmpRec = f_new FlmRecord) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; @@ -311,8 +309,8 @@ FSTATIC RCODE FSOutputIxCounts( // Create at least the root node. - if (RC_BAD( rc = pTmpRec->insertLast( 0, FLM_INDEX_TAG, - FLM_CONTEXT_TYPE, &pvField))) + if (RC_BAD( rc = pTmpRec->insertLast( 0, FLM_INDEX_TAG, FLM_CONTEXT_TYPE, + &pvField))) { goto Exit; } @@ -340,12 +338,14 @@ FSTATIC RCODE FSOutputIxCounts( flmAssert( 0); pIxStats->iDeltaKeys = 0; } + if (RC_BAD( rc = pTmpRec->insert( pTmpRec->root(), INSERT_LAST_CHILD, - FLM_KEY_TAG, FLM_NUMBER_TYPE, &pvField))) + FLM_KEY_TAG, FLM_NUMBER_TYPE, &pvField))) { goto Exit; } - uiCount = (FLMUINT)pIxStats->iDeltaKeys; + + uiCount = (FLMUINT) pIxStats->iDeltaKeys; } else { @@ -358,9 +358,9 @@ FSTATIC RCODE FSOutputIxCounts( { pIxStats->iDeltaKeys = -pIxStats->iDeltaKeys; - if ((FLMUINT)pIxStats->iDeltaKeys <= uiCount) + if ((FLMUINT) pIxStats->iDeltaKeys <= uiCount) { - uiCount -= (FLMUINT)pIxStats->iDeltaKeys; + uiCount -= (FLMUINT) pIxStats->iDeltaKeys; } else { @@ -373,9 +373,10 @@ FSTATIC RCODE FSOutputIxCounts( } else { - uiCount += (FLMUINT)pIxStats->iDeltaKeys; + uiCount += (FLMUINT) pIxStats->iDeltaKeys; } } + if (RC_BAD( rc = pTmpRec->setUINT( pvField, uiCount))) { goto Exit; @@ -396,12 +397,14 @@ FSTATIC RCODE FSOutputIxCounts( flmAssert( 0); pIxStats->iDeltaRefs = 0; } + if (RC_BAD( rc = pTmpRec->insert( pTmpRec->root(), INSERT_LAST_CHILD, - FLM_REFS_TAG, FLM_NUMBER_TYPE, &pvField))) + FLM_REFS_TAG, FLM_NUMBER_TYPE, &pvField))) { goto Exit; } - uiCount = (FLMUINT)pIxStats->iDeltaRefs; + + uiCount = (FLMUINT) pIxStats->iDeltaRefs; } else { @@ -414,9 +417,9 @@ FSTATIC RCODE FSOutputIxCounts( { pIxStats->iDeltaRefs = -pIxStats->iDeltaRefs; - if ((FLMUINT)pIxStats->iDeltaRefs <= uiCount) + if ((FLMUINT) pIxStats->iDeltaRefs <= uiCount) { - uiCount -= (FLMUINT)pIxStats->iDeltaRefs; + uiCount -= (FLMUINT) pIxStats->iDeltaRefs; } else { @@ -429,9 +432,10 @@ FSTATIC RCODE FSOutputIxCounts( } else { - uiCount += (FLMUINT)pIxStats->iDeltaRefs; + uiCount += (FLMUINT) pIxStats->iDeltaRefs; } } + if (RC_BAD( rc = pTmpRec->setUINT( pvField, uiCount))) { goto Exit; @@ -445,22 +449,22 @@ FSTATIC RCODE FSOutputIxCounts( if (bCreateRec) { - if (RC_BAD( rc = FSRecUpdate( pDb, pLFile, pTmpRec, - pIxStats->uiIndexNum, REC_UPD_ADD))) + if (RC_BAD( rc = FSRecUpdate( pDb, pLFile, pTmpRec, pIxStats->uiIndexNum, + REC_UPD_ADD))) { goto Exit; } // Put the record into record cache. - if( RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, pIxStats->uiIndexNum, - pTmpRec))) + if (RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, + pIxStats->uiIndexNum, pTmpRec))) { // Remove the record that was added. - (void)FSRecUpdate( pDb, pLFile, NULL, pIxStats->uiIndexNum, - REC_UPD_DELETE); + (void) FSRecUpdate( pDb, pLFile, NULL, pIxStats->uiIndexNum, + REC_UPD_DELETE); goto Exit; } } @@ -469,8 +473,8 @@ FSTATIC RCODE FSOutputIxCounts( // Modify the record. - if (RC_BAD( rc = FSRecUpdate( pDb, pLFile, pTmpRec, - pIxStats->uiIndexNum, REC_UPD_MODIFY))) + if (RC_BAD( rc = FSRecUpdate( pDb, pLFile, pTmpRec, pIxStats->uiIndexNum, + REC_UPD_MODIFY))) { goto Exit; } @@ -478,13 +482,14 @@ FSTATIC RCODE FSOutputIxCounts( // Put the modified record into record cache. if (RC_BAD( rc = flmRcaInsertRec( pDb, pLFile, - pIxStats->uiIndexNum, pTmpRec))) + pIxStats->uiIndexNum, pTmpRec))) { - // Undo the record that was modified - replace with original record. + // Undo the record that was modified - replace with original + // record. - (void)FSRecUpdate( pDb, pLFile, pRecord, - pIxStats->uiIndexNum, REC_UPD_MODIFY); + (void) FSRecUpdate( pDb, pLFile, pRecord, pIxStats->uiIndexNum, + REC_UPD_MODIFY); goto Exit; } } @@ -500,15 +505,15 @@ Exit: { pTmpRec->Release(); } - return( rc ); + + return (rc); } -/*************************************************************************** +/**************************************************************************** Desc: Free the index stats structures for an FDB. -*****************************************************************************/ +****************************************************************************/ void FSFreeIxCounts( - FDB * pDb - ) + FDB * pDb) { IX_STATS * pNextIxStat; @@ -520,12 +525,12 @@ void FSFreeIxCounts( } } -/*************************************************************************** -Desc: Commit the index reference and/or key counts for a database. This +/**************************************************************************** +Desc: Commit the index reference and/or key counts for a database. This routine is only called at commit time. -*****************************************************************************/ +****************************************************************************/ RCODE FSCommitIxCounts( - FDB * pDb) + FDB * pDb) { RCODE rc = FERR_OK; IX_STATS * pNextIxStat; @@ -537,9 +542,11 @@ RCODE FSCommitIxCounts( { goto Exit; } + f_free( &pDb->pIxStats); pDb->pIxStats = pNextIxStat; } + Exit: if (RC_BAD( rc)) @@ -547,111 +554,110 @@ Exit: FSFreeIxCounts( pDb); } - return( rc); + return (rc); } -/*************************************************************************** -Desc: Create a new record and add the reference to it. -Notes: The record size is the size of the only SEN value - There is no overhead for references for the entry compression -*****************************************************************************/ +/**************************************************************************** +Desc: Create a new record and add the reference to it. +Note: The record size is the size of the only SEN value. There is no + overhead for references for the entry compression +****************************************************************************/ FSTATIC RCODE FSRefCreateRec( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack) + KREF_ENTRY * pKrefEntry, + BTSK * pStack) { - RCODE rc; - FLMUINT uiElmSize; // Element size for insert - FLMUINT uiKeyLen = pKrefEntry->ui16KeyLen; - FLMUINT uiRecLen; - FLMBYTE * pSen; - FLMBYTE byElmBuf[ MAX_KEY_SIZ + BBE_KEY + SEN_MAX_SIZ ]; + RCODE rc = FERR_OK; + FLMUINT uiElmSize; + FLMUINT uiKeyLen = pKrefEntry->ui16KeyLen; + FLMUINT uiRecLen; + FLMBYTE * pSen; + FLMBYTE byElmBuf[MAX_KEY_SIZ + BBE_KEY + SEN_MAX_SIZ]; - // Create the element overhead + // Create the element overhead - byElmBuf[ BBE_PKC ] = BBE_FIRST_FLAG | BBE_LAST_FLAG; - BBE_SET_KL( byElmBuf, uiKeyLen ); + byElmBuf[BBE_PKC] = BBE_FIRST_FLAG | BBE_LAST_FLAG; + BBE_SET_KL( byElmBuf, uiKeyLen); // Copy in the key - f_memcpy( &byElmBuf[ BBE_KEY ], (FLMBYTE *) &pKrefEntry[1], uiKeyLen ); + f_memcpy( &byElmBuf[BBE_KEY], (FLMBYTE*) &pKrefEntry[1], uiKeyLen); uiElmSize = (BBE_KEY + uiKeyLen); - pSen = &byElmBuf[ uiElmSize ]; - uiRecLen = SENPutNextVal( &pSen, pKrefEntry->uiDrn ); - uiElmSize += BBE_SET_RL( byElmBuf, uiRecLen ); + pSen = &byElmBuf[uiElmSize]; + uiRecLen = SENPutNextVal( &pSen, pKrefEntry->uiDrn); + uiElmSize += BBE_SET_RL( byElmBuf, uiRecLen); // Save the element - if( RC_BAD( rc = FSBtInsert( pDb, pLFile, &pStack, byElmBuf, uiElmSize))) + if (RC_BAD( rc = FSBtInsert( pDb, pLFile, &pStack, byElmBuf, uiElmSize))) { goto Exit; } Exit: - return( rc); + return (rc); } -/*************************************************************************** -Desc: Insert a reference into a key|reference list -Notes: The algorithm positions for an insert and inserts the reference - while altering the block. If a reference split is required - refSplit() is called and FSRefInsert() could be recursively called. -*****************************************************************************/ +/**************************************************************************** +Desc: Insert a reference into a key|reference list +Note: The algorithm positions for an insert and inserts the reference while + altering the block. If a reference split is required refSplit() is + called and FSRefInsert() could be recursively called. +****************************************************************************/ FSTATIC RCODE FSRefInsert( - FDB * pDb, - LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack) + FDB * pDb, + LFILE * pLFile, + KREF_ENTRY * pKrefEntry, + BTSK * pStack) { - RCODE rc; - FLMBYTE * pElement = CURRENT_ELM( pStack ); // Points to element - FLMUINT uiElmLen = (FLMUINT) BBE_GET_RL( pElement );// Length of the element - FLMUINT uiElmSize; // Element size for insert - FLMBYTE byElmBuf[ MAX_KEY_SIZ + BBE_KEY+REF_SET_MAX_SIZ ]; // 796! + RCODE rc; + FLMBYTE * pElement = CURRENT_ELM( pStack); + FLMUINT uiElmLen = (FLMUINT) BBE_GET_RL( pElement); + FLMUINT uiElmSize; + FLMBYTE byElmBuf[MAX_KEY_SIZ + BBE_KEY + REF_SET_MAX_SIZ]; // Build the element in byElmBuf[] - FSSetElmOvhd( byElmBuf, BBE_KEY, 0, pStack->uiKeyLen, pElement ); - f_memcpy( &byElmBuf[ BBE_KEY ], pStack->pKeyBuf, pStack->uiKeyLen); + FSSetElmOvhd( byElmBuf, BBE_KEY, 0, pStack->uiKeyLen, pElement); + f_memcpy( &byElmBuf[BBE_KEY], pStack->pKeyBuf, pStack->uiKeyLen); - if( uiElmLen > REF_SET_MAX_SIZ ) + if (uiElmLen > REF_SET_MAX_SIZ) { + // May or may not split the reference set, but will always insert DRN - rc = FSRefSplit( pDb, pLFile, &pStack, - byElmBuf, - pKrefEntry->uiDrn, - INSERT_REF, - (FLMBYTE)(BBE_IS_FIRST(pElement) ? SPLIT_50_50 : SPLIT_90_10) ); + + rc = FSRefSplit( pDb, pLFile, &pStack, byElmBuf, pKrefEntry->uiDrn, + INSERT_REF, (FLMBYTE) (BBE_IS_FIRST( pElement) + ? SPLIT_50_50 + : SPLIT_90_10)); } else { uiElmSize = BBE_KEY + pStack->uiKeyLen; - if( FSSetInsertRef( &byElmBuf[ uiElmSize ], - BBE_REC_PTR( pElement ), // Points to references - pKrefEntry->uiDrn, - &uiElmLen )) + if (FSSetInsertRef( &byElmBuf[uiElmSize], BBE_REC_PTR( pElement), + pKrefEntry->uiDrn, &uiElmLen)) { - rc = RC_SET( FERR_BTREE_ERROR); // Entry is already there + rc = RC_SET( FERR_BTREE_ERROR); // Entry is already there goto Exit; } - BBE_SET_RL( byElmBuf, uiElmLen ); + + BBE_SET_RL( byElmBuf, uiElmLen); rc = FSBtReplace( pDb, pLFile, &pStack, byElmBuf, uiElmSize + uiElmLen); } Exit: - return( rc ); + + return (rc); } - /**************************************************************************** -Desc: Insert a single reference into a reference set. This is the code - that supports the new DIN (Dual Integer Numbers) format for reference - set compression. -Notes: This code is optimized for adding references to the front. +Desc: Insert a single reference into a reference set. This is the code + that supports the new DIN (Dual Integer Numbers) format for reference + set compression. ****************************************************************************/ RCODE FSSetInsertRef( FLMBYTE * pDestRef, @@ -659,684 +665,687 @@ RCODE FSSetInsertRef( FLMUINT drn, FLMUINT * puiSetLength) { - DIN_STATE destState, srcState; // State info for destination & source - FLMUINT uiSetLength= *puiSetLength;// Source set length - FLMUINT uiLastDrn; // Last drn before one tobe inserted - FLMUINT uiOldDelta; // If inserting at front value=0 - FLMUINT uiDelta; // Current uiDelta value - FLMUINT uiNewDelta; // Computes as uiOldDelta - uiDelta - FLMUINT uiOneRun; // Value of one runs - FLMUINT uiPrevOneRun; // Previous one runs value + DIN_STATE destState; + DIN_STATE srcState; + FLMUINT uiSetLength = *puiSetLength; + FLMUINT uiLastDrn; + FLMUINT uiOldDelta; + FLMUINT uiDelta; + FLMUINT uiNewDelta; + FLMUINT uiOneRun; + FLMUINT uiPrevOneRun; + FLMUINT uiLastSrcOfs; + FLMUINT uiPrevLastSrcOfs = 0; + FLMUINT uiMoveLen; + FLMBYTE byValue; - FLMUINT uiLastSrcOfs; // Last source offset - FLMUINT uiPrevLastSrcOfs = 0; // Previous last source offset - FLMUINT uiMoveLen; // Number of bytes to move - FLMBYTE byValue; // Temporary byte value - register + // Initialization Section - /** - *** Initialization Section - **/ uiPrevOneRun = uiOldDelta = 0; uiLastSrcOfs = 0; - RESET_DINSTATE( destState ); - RESET_DINSTATE( srcState ); + + RESET_DINSTATE( destState); + RESET_DINSTATE( srcState); // Take care of the domain value. - if( *pSrcRef == SEN_DOMAIN) + + if (*pSrcRef == SEN_DOMAIN) { srcState.uiOffset = 1; - DINNextVal( pSrcRef, &srcState ); + DINNextVal( pSrcRef, &srcState); uiLastSrcOfs = srcState.uiOffset; } - uiLastDrn = DINNextVal( pSrcRef, &srcState ); // Get highest value + uiLastDrn = DINNextVal( pSrcRef, &srcState); - if( drn > uiLastDrn) + if (drn > uiLastDrn) { - // ADD TO THE FRONT. Set uiDelta and uiNewDelta - + + // ADD TO THE FRONT. Set uiDelta and uiNewDelta + uiNewDelta = (uiDelta = drn) - uiLastDrn; - goto FSSIR_add_delta; // Move domain if there & add values. + goto FSSIR_add_delta; } uiOldDelta = uiLastDrn; uiOneRun = 0; // Search through the set finding where the "drn" fits in. - while( drn < uiLastDrn) + + while (drn < uiLastDrn) { - /** - *** Save previous last source offset & previous one runs - **/ + + // Save previous last source offset & previous one runs + uiPrevLastSrcOfs = uiLastSrcOfs; uiLastSrcOfs = srcState.uiOffset; uiPrevOneRun = uiOneRun; - uiOneRun = 0; // Reset each loop + uiOneRun = 0; - if( srcState.uiOffset >= uiSetLength) // Check if at end + if (srcState.uiOffset >= uiSetLength) { - /**------------------------*** - *** APPEND TO THE END *** - ***------------------------**/ - uiDelta = uiLastDrn - drn; // Compute new delta value + + // APPEND TO THE END + + uiDelta = uiLastDrn - drn; uiNewDelta = 0; goto FSSIR_add_delta; } - /** - *** Check for a run of ONE's - **/ - byValue = pSrcRef[ srcState.uiOffset]; - if( DIN_IS_ONE_RUN( byValue )) /* uiOneRun must be set if a 1 */ + + // Check for a run of ONE's + + byValue = pSrcRef[srcState.uiOffset]; + if (DIN_IS_ONE_RUN( byValue)) { - /* Read the number of one runs */ - uiOneRun = DINOneRunVal( pSrcRef, &srcState ); + + // Read the number of one runs + + uiOneRun = DINOneRunVal( pSrcRef, &srcState); uiLastDrn -= uiOneRun; - if( drn > uiLastDrn) - uiLastDrn = drn; // DRN inside of one-run - duplicate! + if (drn > uiLastDrn) + { + uiLastDrn = drn; + } } else { - uiOldDelta = DINNextVal( pSrcRef, &srcState ); + uiOldDelta = DINNextVal( pSrcRef, &srcState); uiLastDrn -= uiOldDelta; } - } /* End while( drn < uiLastDrn) */ - - /* Check for duplicates */ - if( drn == uiLastDrn) - return( RC_SET( FERR_BTREE_ERROR) ); // Duplicate found or inside of one run + } + + // Check for duplicates + + if (drn == uiLastDrn) + { + // Duplicate found or inside of one run + + return (RC_SET( FERR_BTREE_ERROR)); + } + + uiDelta = uiLastDrn + uiOldDelta - drn; + uiNewDelta = drn - uiLastDrn; - uiDelta = uiLastDrn + uiOldDelta - drn; // Compute the first delta value - uiNewDelta = drn - uiLastDrn; // or (uiOldDelta - uiDelta); - FSSIR_add_delta: - /**-----------------------------------------------------------------*** - *** COMPRESS MULTIPLE ONE RUNS *** - *** *** - *** Special case if delta is 1. Check the previous destinaion DIN *** - *** for a 1 or a run of ones and combine to the left. *** - *** Also check to combine a one run on the right by jumping within *** - *** add_new_delta. *** - ***-----------------------------------------------------------------**/ + // COMPRESS MULTIPLE ONE RUNS Special case if delta is 1. Check the + // previous destinaion DIN for a 1 or a run of ones and combine to the + // left. Also check to combine a one run on the right by jumping within + // add_new_delta. - if( uiDelta == 1 ) + if (uiDelta == 1) { uiOneRun = 1; - if( uiPrevOneRun ) + if (uiPrevOneRun) { f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiPrevLastSrcOfs); - uiOneRun += uiPrevOneRun; // Combine uiDelta and prev. one runs + uiOneRun += uiPrevOneRun; } else { - f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs ); + f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs); } - if( uiNewDelta == 1) + + if (uiNewDelta == 1) { - uiOneRun++; // Combine the uiNewDelta one run + uiOneRun++; goto FSSIR_combine_right_one_runs; } - /* uiNewDelta is not 1 so write to destination and go on */ - DINPutOneRunVal( pDestRef, &destState, uiOneRun ); + + // uiNewDelta is not 1 so write to destination and go on + + DINPutOneRunVal( pDestRef, &destState, uiOneRun); } else { - f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs ); - // No one runs found so write the delta value - DINPutNextVal( pDestRef, &destState, uiDelta ); + f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs); + + // No one runs found so write the delta value + + DINPutNextVal( pDestRef, &destState, uiDelta); } -/*FSSIR_add_new_delta:*/ - /** - *** Add new delta value (uiOldDelta - uiDelta) - *** If the new delta value is == 1 then - *** check next DIN for a 1 run and combine with the uiNewDelta run. - *** uiNewDelta only has a value when NOT appending to the end. - **/ - if( uiNewDelta) + // Add new delta value (uiOldDelta - uiDelta). If the new delta value is + // 1 then check next DIN for a 1 run and combine with the uiNewDelta + // run. uiNewDelta only has a value when NOT appending to the end. + + if (uiNewDelta) { - if( uiNewDelta != 1) - DINPutNextVal( pDestRef, &destState, uiNewDelta ); + if (uiNewDelta != 1) + { + DINPutNextVal( pDestRef, &destState, uiNewDelta); + } else { uiOneRun = 1; - + FSSIR_combine_right_one_runs: - - if( srcState.uiOffset < uiSetLength ) /* Done parsing?*/ + + if (srcState.uiOffset < uiSetLength) { - /** - *** CONNECT ONE RUNS - *** Check on the right side of the source for another 1 run. - **/ - byValue = pSrcRef[ srcState.uiOffset]; - if( DIN_IS_ONE_RUN( byValue )) + + // CONNECT ONE RUNS Check on the right side of the source for + // another 1 run. + + byValue = pSrcRef[srcState.uiOffset]; + if (DIN_IS_ONE_RUN( byValue)) { - uiOneRun += DINOneRunVal( pSrcRef, &srcState ); + uiOneRun += DINOneRunVal( pSrcRef, &srcState); } } - DINPutOneRunVal( pDestRef, &destState, uiOneRun ); + + DINPutOneRunVal( pDestRef, &destState, uiOneRun); } } -/*FSSIR_move_rest_of_dins:*/ + // FSSIR_move_rest_of_dins: - if( (uiMoveLen = (FLMUINT)(uiSetLength - srcState.uiOffset)) != 0) + if ((uiMoveLen = (FLMUINT) (uiSetLength - srcState.uiOffset)) != 0) { - f_memcpy( &pDestRef[ destState.uiOffset ], - &pSrcRef[ srcState.uiOffset ], uiMoveLen ); + f_memcpy( &pDestRef[destState.uiOffset], &pSrcRef[srcState.uiOffset], + uiMoveLen); destState.uiOffset += uiMoveLen; } + *puiSetLength = destState.uiOffset; - return( FERR_OK ); + return (FERR_OK); } - -/*************************************************************************** -Desc: Delete a matching reference into a key|reference list. If this - was the last continuation element then remove the SEN_DOMAIN value - from the previous element. -*****************************************************************************/ -FSTATIC RCODE FSRefDelete( +/**************************************************************************** +Desc: Delete a matching reference into a key|reference list. If this was + the last continuation element then remove the SEN_DOMAIN value from the + previous element. +****************************************************************************/ +FSTATIC RCODE FSRefDelete( FDB * pDb, LFILE * pLFile, - KREF_ENTRY_p pKrefEntry, - BTSK_p pStack, - FLMBOOL * pbSingleRef) /* [out] return TRUE if last ref */ + KREF_ENTRY * pKrefEntry, + BTSK * pStack, + FLMBOOL * pbSingleRef) { RCODE rc = FERR_OK; - FLMBYTE * pElement = CURRENT_ELM( pStack ); /* Points to element */ - FLMBYTE * pReference; /* Points to the references */ + FLMBYTE * pElement = CURRENT_ELM( pStack); + FLMBYTE * pReference; FLMBYTE * pDestRefPtr; - FLMUINT uiElmLen = BBE_GET_RL( pElement ); /* Length of the element */ - FLMUINT uiElmSize; /* Element size for insert */ - FLMUINT uiSetLength; /* Length of the new set */ + FLMUINT uiElmLen = BBE_GET_RL( pElement); + FLMUINT uiElmSize; + FLMUINT uiSetLength; FLMUINT uiKeyLen; FLMUINT uiSenLen; - FLMBYTE byElmBuf[ MAX_KEY_SIZ + BBE_KEY + REF_SET_MAX_SIZ ]; + FLMBYTE byElmBuf[MAX_KEY_SIZ + BBE_KEY + REF_SET_MAX_SIZ]; - /* Build the element in byElmBuf[] */ - FSSetElmOvhd( byElmBuf, BBE_KEY, 0, pStack->uiKeyLen, pElement ); + // Build the element in byElmBuf[] - f_memcpy( &byElmBuf[ BBE_KEY], pStack->pKeyBuf, pStack->uiKeyLen); - pDestRefPtr = &byElmBuf[ BBE_KEY + pStack->uiKeyLen ]; + FSSetElmOvhd( byElmBuf, BBE_KEY, 0, pStack->uiKeyLen, pElement); + + f_memcpy( &byElmBuf[BBE_KEY], pStack->pKeyBuf, pStack->uiKeyLen); + pDestRefPtr = &byElmBuf[BBE_KEY + pStack->uiKeyLen]; uiElmSize = (BBE_KEY + pStack->uiKeyLen); - if( uiElmLen > REF_SET_MAX_SIZ ) /* Deletion may EXPAND element! */ + if (uiElmLen > REF_SET_MAX_SIZ) { - /* Straight deletions MAY overflow the record portion ! ! */ + + // Straight deletions MAY overflow the record portion + rc = FSRefSplit( pDb, pLFile, &pStack, byElmBuf, pKrefEntry->uiDrn, - DELETE_REF, SPLIT_50_50 ); - return( rc ); + DELETE_REF, SPLIT_50_50); + return (rc); } - pReference = BBE_REC_PTR( pElement ); + pReference = BBE_REC_PTR( pElement); uiSetLength = uiElmLen; - if( FSSetDeleteRef( pDestRefPtr, pReference, pKrefEntry->uiDrn, &uiSetLength )) + if (FSSetDeleteRef( pDestRefPtr, pReference, pKrefEntry->uiDrn, &uiSetLength)) { - // 22Feb99 - before this time we returned FERR_KEY_NOT_FOUND. goto Exit; } - BBE_SET_RL( byElmBuf, uiSetLength ); - /* hasDomainFlag = 0; */ - uiElmSize += uiSetLength; /* Add to wElmSize for FSBtReplace()*/ + BBE_SET_RL( byElmBuf, uiSetLength); + uiElmSize += uiSetLength; - /* Get the reference length and hasDomainFlag */ - if( uiSetLength ) + // Get the reference length and hasDomainFlag + + if (uiSetLength) { - if( *pReference == SEN_DOMAIN ) + if (*pReference == SEN_DOMAIN) { - /* hasDomainFlag = 1; */ uiSetLength--; - uiSetLength -= SENValLen( pReference + 1 ); + uiSetLength -= SENValLen( pReference + 1); } } - if( uiSetLength == 0 ) + + if (uiSetLength == 0) { - FLMBOOL bLastElm = BBE_IS_LAST( pElement ); - FLMBOOL bFirstElm = BBE_IS_FIRST( pElement ); + FLMBOOL bLastElm = BBE_IS_LAST( pElement); + FLMBOOL bFirstElm = BBE_IS_FIRST( pElement); - /* Delete the element */ - if( RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack ))) - return( rc ); + // Delete the element - /**-------------------------------------------------------------------- - *** Remove the LAST (only) reference in an element. - *** - *** There are 4 cases to consider that deal with continuation elements - *** 1. ONLY element - no list - ALL DONE - *** 2. FIRST of many in a list- Set BBE_FIRST_FLAG in the next element - *** 3. MIDDLE of a list - ALL DONE - *** 4. LAST in a list - - *** Remove the domain from the previous element and - *** set the BBE_LAST_FLAG in the new last element. - ***-------------------------------------------------------------------*/ + if (RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack))) + { + return (rc); + } - if( bFirstElm && bLastElm) /* Case 1 - ONLY element */ + // Remove the LAST (only) reference in an element. There are 4 cases + // to consider that deal with continuation elements: + // 1. ONLY element - no list - ALL DONE + // 2. FIRST of many in a list - Set BBE_FIRST_FLAG in the + // next element + // 3. MIDDLE of a list - ALL DONE + // 4. LAST in a list Remove the domain from the previous element and + // set the BBE_LAST_FLAG in the new last element. + + if (bFirstElm && bLastElm) // Case 1 - ONLY element { *pbSingleRef = TRUE; } - else if( bFirstElm && (! bLastElm )) /* Case 2 - first of many */ + else if (bFirstElm && (!bLastElm)) // Case 2 - first of many { - /* Log the block before modifying it. */ - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - return( rc); - pElement = CURRENT_ELM( pStack ); - BBE_SET_FIRST( pElement ); + // Log the block before modifying it. + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + return (rc); + } + + pElement = CURRENT_ELM( pStack); + BBE_SET_FIRST( pElement); } - - else if( !bFirstElm && bLastElm ) /* Case 4 - Last in a list */ + else if (!bFirstElm && bLastElm) // Case 4 - Last in a list { - /**--------------------------------------------------- - *** Element was either the ONLY or LAST in a list. - ***--------------------------------------------------*/ - FSBtPrevElm( pDb, pLFile, pStack ); /* Goto the previous element */ + // Element was either the ONLY or LAST in a list. - pElement = CURRENT_ELM( pStack ); + FSBtPrevElm( pDb, pLFile, pStack); // Goto the previous element - pReference = BBE_REC_PTR( pElement ); - uiSetLength = BBE_GET_RL( pElement ); + pElement = CURRENT_ELM( pStack); + + pReference = BBE_REC_PTR( pElement); + uiSetLength = BBE_GET_RL( pElement); uiKeyLen = pStack->uiKeyLen; - /* Build the element in byElmBuf[] - sets BBE_FIRST_FLAG if set */ - FSSetElmOvhd( byElmBuf, BBE_KEY, 0, uiKeyLen, pElement ); - BBE_SET_LAST( byElmBuf ); /* Set last element flag */ + // Build the element in byElmBuf[] - sets BBE_FIRST_FLAG if set - f_memcpy( &byElmBuf[ BBE_KEY ], pStack->pKeyBuf, uiKeyLen); - pDestRefPtr = &byElmBuf[ BBE_KEY + uiKeyLen ]; - /* Parse past the element information and delete the domain data*/ - - if( *pReference != SEN_DOMAIN) - return( RC_SET( FERR_BTREE_ERROR) ); + FSSetElmOvhd( byElmBuf, BBE_KEY, 0, uiKeyLen, pElement); + BBE_SET_LAST( byElmBuf); // Set last element flag - uiSenLen = (SENValLen( pReference + 1) + 1); + f_memcpy( &byElmBuf[BBE_KEY], pStack->pKeyBuf, uiKeyLen); + pDestRefPtr = &byElmBuf[BBE_KEY + uiKeyLen]; + + // Parse past the element information and delete the domain data + + if (*pReference != SEN_DOMAIN) + { + return (RC_SET( FERR_BTREE_ERROR)); + } + + uiSenLen = (SENValLen( pReference + 1) + 1); pReference += uiSenLen; uiSetLength -= uiSenLen; - f_memcpy( pDestRefPtr, pReference, uiSetLength ); - BBE_SET_RL( byElmBuf, uiSetLength ); + f_memcpy( pDestRefPtr, pReference, uiSetLength); + BBE_SET_RL( byElmBuf, uiSetLength); - uiElmSize = (BBE_KEY + uiKeyLen + uiSetLength); /* Recompute wElmSize */ + uiElmSize = (BBE_KEY + uiKeyLen + uiSetLength); - /** - *** We could call FSBtReplace() except that if the element - *** is the last element in the block, the parent element - *** will still contain the 3 byte non-leaf DOMAIN number which - *** should no longer exist. In addition, the BBE_LAST_FLAG - *** flag should be set in the current element and replace doesn't - *** do that. - **/ - if( RC_BAD(rc = FSBtDelete( pDb, pLFile, &pStack ))) - return( rc ); + // We could call FSBtReplace() except that if the element is the + // last element in the block, the parent element will still + // contain the 3 byte non-leaf DOMAIN number which should no + // longer exist. In addition, the BBE_LAST_FLAG flag should be + // set in the current element and replace doesn't do that. - /**----------------------------------------------------------------- - *** POSSIBLE CHECK YOU MAY FORGET... - *** You could have deleted the ONLY element in the tree. - *** Check and if so init a new root block and position for insert. - ***----------------------------------------------------------------*/ - if( pLFile->uiRootBlk == BT_END ) + if (RC_BAD( rc = FSBtDelete( pDb, pLFile, &pStack))) { - if( RC_BAD( rc = flmLFileInit( pDb, pLFile))) + return (rc); + } + + // POSSIBLE CHECK YOU MAY FORGET... You could have deleted the + // ONLY element in the tree. Check and if so init a new root + // block and position for insert. + + if (pLFile->uiRootBlk == BT_END) + { + if (RC_BAD( rc = flmLFileInit( pDb, pLFile))) { - return( rc); + return (rc); } - /* Call FSBtSearch to setup the pStack, would rather do a goto top; */ - if( RC_BAD(rc = FSBtSearch( pDb, pLFile, &pStack, - (FLMBYTE *) &byElmBuf[BBE_KEY], - uiKeyLen, 0 ))) + // Call FSBtSearch to setup the pStack, would rather do a goto top; + + if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, + (FLMBYTE*) &byElmBuf[BBE_KEY], uiKeyLen, 0))) { - return( rc); + return (rc); } } else { - /* BUG #18811 8/14/96 - had == in the code. - Added the rc checking in June. - The DIN_DOMAIN for this new element is 0 because scanto() - will go to wCurElm. - */ - /* Setup the pStack and bsKeyBuf[] for the insert */ - if( RC_BAD(rc = FSBtScanTo( pStack, &byElmBuf[ BBE_KEY ], - uiKeyLen, 0))) + + if (RC_BAD( rc = FSBtScanTo( pStack, + &byElmBuf[BBE_KEY], uiKeyLen, 0))) { goto Exit; } } - rc = FSBtInsert( pDb, pLFile, &pStack, byElmBuf, uiElmSize ); + rc = FSBtInsert( pDb, pLFile, &pStack, byElmBuf, uiElmSize); } } else { - /* Replace the current element - wElmSize has had uiSetLength added to it */ - rc = FSBtReplace( pDb, pLFile, &pStack, byElmBuf, uiElmSize ); + + // Replace the current element - wElmSize has had uiSetLength added + // to it + + rc = FSBtReplace( pDb, pLFile, &pStack, byElmBuf, uiElmSize); } - if( RC_BAD( rc)) + if (RC_BAD( rc)) { goto Exit; } - + Exit: - return( rc ); + return (rc); } /**************************************************************************** -Desc: Delete a single reference into a reference set. This is the code - that supports the new DIN (Dual Integer Numbers) format for reference - set compression. -Notes: This code is optimized for adding references to the front. -****************************************************************************/ +Desc: Delete a single reference into a reference set. This is the code + that supports the new DIN (Dual Integer Numbers) format for reference + set compression. +****************************************************************************/ RCODE FSSetDeleteRef( FLMBYTE * pDestRef, FLMBYTE * pSrcRef, FLMUINT drn, - FLMUINT * puiSetLength) /* returns the current length of the set */ + FLMUINT * puiSetLength) { - DIN_STATE destState, srcState; /* State destination & source info */ - FLMUINT uiSetLength = *puiSetLength; /* Source set length */ + DIN_STATE destState; + DIN_STATE srcState; + FLMUINT uiSetLength = *puiSetLength; FLMUINT uiMoveLen; - FLMUINT uiLastSrcOfs; /* Last accessed source offset value */ - FLMUINT uiLastDrn; /* Last din before one tobe Deleted */ - FLMUINT uiOldDelta; /* If deleting at front value=0 */ - FLMUINT uiOneRun; /* Value of one runs */ + FLMUINT uiLastSrcOfs; + FLMUINT uiLastDrn; + FLMUINT uiOldDelta; + FLMUINT uiOneRun; FLMUINT uiTemp; - FLMBYTE byValue; /* Temporary byte value - register */ + FLMBYTE byValue; - /* Initialization Section */ - RESET_DINSTATE( destState ); - RESET_DINSTATE( srcState ); + RESET_DINSTATE( destState); + RESET_DINSTATE( srcState); uiLastSrcOfs = 0; - /* Take care of the domain value */ - if( *pSrcRef == SEN_DOMAIN) + // Take care of the domain value + + if (*pSrcRef == SEN_DOMAIN) { srcState.uiOffset = 1; - uiLastDrn = DINNextVal( pSrcRef, &srcState ); + uiLastDrn = DINNextVal( pSrcRef, &srcState); uiLastSrcOfs = srcState.uiOffset; } - uiLastDrn = DINNextVal( pSrcRef, &srcState ); + uiLastDrn = DINNextVal( pSrcRef, &srcState); - if( drn > uiLastDrn) /* Greater than the first reference */ + if (drn > uiLastDrn) { - return( RC_SET( FERR_KEY_NOT_FOUND) ); + // Greater than the first reference + + return (RC_SET( FERR_KEY_NOT_FOUND)); } - if( drn == uiLastDrn) + + if (drn == uiLastDrn) { - /** - *** MATCHED THE FIRST REFERENCE - *** Write the replacement starting DRN and fix 1 run if there. - **/ - if( uiLastSrcOfs) /* If domain - copy it */ - f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs); - if( srcState.uiOffset >= uiSetLength) /* Only 1 reference */ - goto FSSDR_done; + // MATCHED THE FIRST REFERENCE Write the replacement starting DRN + // and fix 1 run if there. - byValue = pSrcRef[ srcState.uiOffset ]; - if( DIN_IS_REAL_ONE_RUN( byValue )) /* Run of 2 or above */ + if (uiLastSrcOfs) { - DINPutNextVal( pDestRef, &destState, uiLastDrn - 1 ); - DINPutOneRunVal( pDestRef, &destState, - DINOneRunVal( pSrcRef,&srcState)-1); + // If domain - copy it + + f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs); + } + + if (srcState.uiOffset >= uiSetLength) + { + // Only 1 reference + + goto FSSDR_done; + } + + byValue = pSrcRef[srcState.uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + // Run of 2 or above + + DINPutNextVal( pDestRef, &destState, uiLastDrn - 1); + DINPutOneRunVal( pDestRef, &destState, + DINOneRunVal( pSrcRef, &srcState) - 1); } else { - uiLastDrn -= DINNextVal( pSrcRef, &srcState ); - DINPutNextVal( pDestRef, &destState, uiLastDrn ); + uiLastDrn -= DINNextVal( pSrcRef, &srcState); + DINPutNextVal( pDestRef, &destState, uiLastDrn); } + goto FSSDR_move_rest_of_dins; } uiOldDelta = uiLastDrn; uiOneRun = 0; - /** - *** Search through the set finding where the "din" fits in. - *** Similar while loop as the while loop in FSSetInsertRef() above. - **/ - while( drn < uiLastDrn) + + // Search through the set finding where the "din" fits in. Similar + // while loop as the while loop in FSSetInsertRef() above. + + while (drn < uiLastDrn) { uiLastSrcOfs = srcState.uiOffset; - uiOneRun = 0; - if( srcState.uiOffset >= uiSetLength) /* Check if at end */ + if (srcState.uiOffset >= uiSetLength) { - return( RC_SET( FERR_KEY_NOT_FOUND) ); + return (RC_SET( FERR_KEY_NOT_FOUND)); } - /** - *** Check for a run of ONE's - **/ - byValue = pSrcRef[ srcState.uiOffset ]; - if( DIN_IS_REAL_ONE_RUN( byValue )) /* Only consider one runs >= 2 */ + // Check for a run of ONE's + + byValue = pSrcRef[srcState.uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) { - /* Read the number of one runs */ - uiOneRun = DINOneRunVal( pSrcRef, &srcState ); - uiLastDrn -= uiOneRun; /* This could make uiLastDrn < drn */ + + // Read the number of one runs + + uiOneRun = DINOneRunVal( pSrcRef, &srcState); + uiLastDrn -= uiOneRun; } else { - uiOldDelta = DINNextVal( pSrcRef, &srcState ); + uiOldDelta = DINNextVal( pSrcRef, &srcState); uiLastDrn -= uiOldDelta; } - } /* End while( drn < uiLastDrn) */ - + } + f_memcpy( pDestRef, pSrcRef, destState.uiOffset = uiLastSrcOfs); - if( uiOneRun ) + if (uiOneRun) { - /**-------------------------------------------------*** - *** Divide out a one run. drn may match the *** - *** first, middle or last value of a one run. *** - *** Copy up to the last source value to dest. *** - ***-------------------------------------------------**/ - - uiLastDrn += uiOneRun; /* Reset uiLastDrn back to > drn */ - if( drn == uiLastDrn - 1 ) /* Delete FIRST one run */ + // Divide out a one run. drn may match the first, middle or last + // value of a one run. Copy up to the last source value to dest. + + uiLastDrn += uiOneRun; + if (drn == uiLastDrn - 1) { - /* Remove the first value from the run - run is >= 2 */ - DINPutNextVal( pDestRef, &destState, 2 ); - if( uiOneRun > 2 ) + + // Remove the first value from the run - run is >= 2 + + DINPutNextVal( pDestRef, &destState, 2); + if (uiOneRun > 2) { DINPutOneRunVal( pDestRef, &destState, uiOneRun - 2); } + goto FSSDR_move_rest_of_dins; } - else + else { - DINPutOneRunVal( pDestRef, &destState, (uiLastDrn - drn) - 1 ); - - if( drn > uiLastDrn - uiOneRun ) /* Delete from the MIDDLE of one run*/ + DINPutOneRunVal( pDestRef, &destState, (uiLastDrn - drn) - 1); + + if (drn > uiLastDrn - uiOneRun) { - FLMUINT oneRun2ndHalf = uiOneRun - (uiLastDrn - drn) - 1; - + FLMUINT oneRun2ndHalf = uiOneRun - (uiLastDrn - drn) - 1; + DINPutNextVal( pDestRef, &destState, 2); - if( oneRun2ndHalf) - DINPutOneRunVal( pDestRef, &destState, oneRun2ndHalf ); + if (oneRun2ndHalf) + { + DINPutOneRunVal( pDestRef, &destState, oneRun2ndHalf); + } + goto FSSDR_move_rest_of_dins; } else { - /* Delete from the END of a one run */ + + // Delete from the END of a one run + uiOldDelta = 1; goto FSSDR_combine_2_deltas; } - } - /* Should never reach here! */ + } + + // Should never reach here! } - /* Check for duplicates */ - else if( drn != uiLastDrn) - return( RC_SET( FERR_KEY_NOT_FOUND) ); - /* implied else */ - - /** - *** Hit a non-one run where drn == uiLastDrn - *** Check the next DIN value and add uiOldDelta to it - *** UNLESS it is a one run, then write uiOldDelta+1 and - *** if uiOneRun-1 is non-zero then write uiOneRun-1 - **/ - /* Check for a run of ONE's */ - if( srcState.uiOffset < uiSetLength ) + // Check for duplicates + + else if (drn != uiLastDrn) { - byValue = pSrcRef[ srcState.uiOffset ]; - if( DIN_IS_REAL_ONE_RUN( byValue )) - { - DINPutNextVal( pDestRef, &destState, uiOldDelta + 1 ); - uiOneRun = DINOneRunVal( pSrcRef, &srcState ) - 1; - DINPutOneRunVal( pDestRef, &destState, uiOneRun ); - } - else /* else combine the next delta with the preceeding delta */ - { + return (RC_SET( FERR_KEY_NOT_FOUND)); + } + // Hit a non-one run where drn == uiLastDrn Check the next DIN value + // and add uiOldDelta to it UNLESS it is a one run, then write + // uiOldDelta+1 and if uiOneRun-1 is non-zero then write uiOneRun-1 + + if (srcState.uiOffset < uiSetLength) + { + byValue = pSrcRef[srcState.uiOffset]; + if (DIN_IS_REAL_ONE_RUN( byValue)) + { + DINPutNextVal( pDestRef, &destState, uiOldDelta + 1); + uiOneRun = DINOneRunVal( pSrcRef, &srcState) - 1; + DINPutOneRunVal( pDestRef, &destState, uiOneRun); + } + else + { FSSDR_combine_2_deltas: - if( srcState.uiOffset >= uiSetLength) - goto FSSDR_done; - uiTemp = DINNextVal(pSrcRef, &srcState); /* 2 lines for debugging */ - DINPutNextVal( pDestRef, &destState, uiOldDelta + uiTemp ); + if (srcState.uiOffset >= uiSetLength) + { + goto FSSDR_done; + } + + uiTemp = DINNextVal( pSrcRef, &srcState); + DINPutNextVal( pDestRef, &destState, uiOldDelta + uiTemp); } - } + } FSSDR_move_rest_of_dins: - if( (uiMoveLen = (FLMUINT)(uiSetLength - srcState.uiOffset) ) != 0) + + if ((uiMoveLen = (FLMUINT) (uiSetLength - srcState.uiOffset)) != 0) { - f_memcpy( &pDestRef[ destState.uiOffset ], - &pSrcRef[ srcState.uiOffset ], uiMoveLen ); + f_memcpy( &pDestRef[destState.uiOffset], &pSrcRef[srcState.uiOffset], + uiMoveLen); destState.uiOffset += uiMoveLen; } FSSDR_done: - *puiSetLength = destState.uiOffset; - -#ifdef REF_TESTING - uiSetLength = destState.uiOffset; - if( uiSetLength && drn < 512) - { - int colPos = 1; - printf("%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% Deleting %ld\n", drn); - uiLastDrn = 0; - RESET_DINSTATE( destState ); - if( *pDestRef == SEN_DOMAIN) - printf("DOMAIN: %ld\n", DINNextVal( pDestRef, &destState )); - uiLastDrn = DINNextVal( pDestRef, &destState ); - printf(" %4ld ", uiLastDrn ); - while( destState.uiOffset < uiSetLength) - { - byValue = pDestRef[ destState.uiOffset ]; - if( DIN_IS_ONE_RUN( byValue )) /* uiOneRun must be set if a 1 */ - { - /* Read the number of one runs */ - printf("R%4ldR", uiOneRun = DINOneRunVal( pDestRef, &destState )); - uiLastDrn -= uiOneRun; - } - else - { - uiOldDelta = DINNextVal( pDestRef, &destState ); - uiLastDrn -= uiOldDelta; - printf(" %4ld ", uiLastDrn ); - } - if( colPos++ > 9) - { - printf("\n"); - colPos = 0; - } - } - printf("\n"); - } -#endif - return( FERR_OK ); + *puiSetLength = destState.uiOffset; + return (FERR_OK); } -/*************************************************************************** -Desc: Put a SEN value into a buffer - return the length of storage used -Notes: goto's used to save code space and maybe speed up code! -*****************************************************************************/ +/**************************************************************************** +Desc: Put a SEN value into a buffer - return the length of storage used +****************************************************************************/ FLMUINT SENPutNextVal( - FLMBYTE ** pSenRV, /* Points to a SEN buffer */ - FLMUINT senValue /* SEN value */ - ) + FLMBYTE ** pSenRV, + FLMUINT senValue) { FLMBYTE * pSen = *pSenRV; FLMUINT uiSenLen; - - if( senValue <= SEN_1B_VAL) + + if (senValue <= SEN_1B_VAL) { *pSen++ = (FLMBYTE) senValue; } - else if( senValue <= SEN_2B_VAL) + else if (senValue <= SEN_2B_VAL) { - *pSen++ = (FLMBYTE)(SEN_2B_CODE + (FLMBYTE) ((senValue >> 8) & SEN_2B_MASK )); + *pSen++ = (FLMBYTE) (SEN_2B_CODE + + (FLMBYTE) ((senValue >> 8) & SEN_2B_MASK)); *pSen++ = (FLMBYTE) senValue; - /* Don't bother with goto */ } - else if( senValue <= SEN_3B_VAL) + else if (senValue <= SEN_3B_VAL) { - *pSen++ = (FLMBYTE)(SEN_3B_CODE + (FLMBYTE) ((senValue >> 16) & SEN_3B_MASK )); + *pSen++ = (FLMBYTE) (SEN_3B_CODE + + (FLMBYTE) ((senValue >> 16) & SEN_3B_MASK)); goto SENPV_2_bytes; } - else if( senValue <= SEN_4B_VAL) + else if (senValue <= SEN_4B_VAL) { - *pSen++ = (FLMBYTE)(SEN_4B_CODE + (FLMBYTE) ((senValue >> 24) & SEN_4B_MASK )); + *pSen++ = (FLMBYTE) (SEN_4B_CODE + + (FLMBYTE) ((senValue >> 24) & SEN_4B_MASK)); goto SENPV_3_bytes; } else { - *pSen++ = SEN_5B_CODE; /* 0 value in left 4 bits ALWAYS */ + *pSen++ = SEN_5B_CODE; *pSen++ = (FLMBYTE) (senValue >> 24); + SENPV_3_bytes: + *pSen++ = (FLMBYTE) (senValue >> 16); + SENPV_2_bytes: + *pSen++ = (FLMBYTE) (senValue >> 8); -/*SENPV_1_byte:*/ *pSen++ = (FLMBYTE) senValue; } - - uiSenLen = (FLMUINT) (pSen - *pSenRV); - /* wSenLen = SENLenArray[ **pSenRV >> 4 ]; this could be faster??? */ + uiSenLen = (FLMUINT) (pSen -*pSenRV); *pSenRV = pSen; - return( uiSenLen ); + return (uiSenLen); } /**************************************************************************** -Desc: Put the next one run value - high level +Desc: Put the next one run value - high level ****************************************************************************/ -FLMUINT DINPutOneRunVal( +FLMUINT DINPutOneRunVal( FLMBYTE * dinPtr, - DIN_STATE_p state, + DIN_STATE * state, FLMUINT uiValue) { - FLMUINT uiLength = 1; /* Default */ + FLMUINT uiLength = 1; FLMUINT uiOffset = state->uiOffset; FLMBYTE * pOneRun; - if( uiValue == 1) + if (uiValue == 1) { - dinPtr[ uiOffset ] = 1; + dinPtr[uiOffset] = 1; } - else if( uiValue <= DIN_MAX_1B_ONE_RUN) + else if (uiValue <= DIN_MAX_1B_ONE_RUN) { - dinPtr[ uiOffset ] = (FLMBYTE)(DIN_ONE_RUN_LV | (((FLMBYTE) uiValue) - 2)); + dinPtr[uiOffset] = (FLMBYTE) (DIN_ONE_RUN_LV | (((FLMBYTE) uiValue) - 2)); } else { - dinPtr[ uiOffset ] = DIN_ONE_RUN_HV; - pOneRun = &dinPtr[ uiOffset + 1 ]; - - uiLength += SENPutNextVal( &pOneRun, uiValue ); - } - state->uiOffset += uiLength; - /* See if faster to set state->uiOffset = uiLength + uiOffset */ - return( uiLength ); -} + dinPtr[uiOffset] = DIN_ONE_RUN_HV; + pOneRun = &dinPtr[uiOffset + 1]; + uiLength += SENPutNextVal( &pOneRun, uiValue); + } + + state->uiOffset += uiLength; + return (uiLength); +} diff --git a/flaim/src/fsrvlock.cpp b/flaim/src/fsrvlock.cpp index 17f664e..e9b4600 100644 --- a/flaim/src/fsrvlock.cpp +++ b/flaim/src/fsrvlock.cpp @@ -192,7 +192,7 @@ void ServerLockManager::CheckLockTimeouts( FLMBOOL bTimeoutAll) { FLMUINT uiCurrTime; - LOCK_WAITER_p pLockWaiter; + LOCK_WAITER * pLockWaiter; pMutexRef->Lock(); uiCurrTime = (FLMUINT)FLM_GET_TIMER(); @@ -232,8 +232,8 @@ void ServerLockManager::SignalLockWaiter( FLMUINT uiThreadId) { FLMUINT uiCurrTime; - LOCK_WAITER_p pLockWaiter; - LOCK_WAITER_p pNextWaiter; + LOCK_WAITER * pLockWaiter; + LOCK_WAITER * pNextWaiter; F_MutexRef MutexRef( m_phMutex); @@ -272,9 +272,9 @@ Desc: Inserts a waiter into the global list of waiters, sorted by is already locked. ****************************************************************************/ void ServerLockManager::InsertWaiter( - LOCK_WAITER_p pLockWaiter) + LOCK_WAITER * pLockWaiter) { - LOCK_WAITER_p pPrevLockWaiter; + LOCK_WAITER * pPrevLockWaiter; // Determine where in the list this lock waiter should go. @@ -644,7 +644,7 @@ Desc: Removes a waiter from the list of waiters on this object. is already locked. ****************************************************************************/ void ServerLockObject::RemoveWaiter( - LOCK_WAITER_p pLockWaiter) + LOCK_WAITER * pLockWaiter) { if (pLockWaiter->pNext) pLockWaiter->pNext->pPrev = pLockWaiter->pPrev; @@ -753,7 +753,7 @@ RCODE ServerLockObject::Lock( // Do the event callback, if any registered. if (bLogEvent && - gv_FlmSysData.EventHdrs [F_EVENT_LOCKS].pEventCBList) + gv_FlmSysData.LockEvents.pEventCBList) { flmDoEventCallback( F_EVENT_LOCKS, (FEventType)((bSendSuspendEvent) @@ -793,7 +793,7 @@ RCODE ServerLockObject::Lock( // Do the event callback, if any registered. if (bLogEvent && - gv_FlmSysData.EventHdrs [F_EVENT_LOCKS].pEventCBList) + gv_FlmSysData.LockEvents.pEventCBList) { if (RC_BAD( rc)) { @@ -864,7 +864,7 @@ RCODE ServerLockObject::Lock( if (bLogEvent && !bSendSuspendEvent && - gv_FlmSysData.EventHdrs [F_EVENT_LOCKS].pEventCBList) + gv_FlmSysData.LockEvents.pEventCBList) { MutexRef.Unlock(); bSemLocked = FALSE; @@ -892,14 +892,14 @@ Desc: Unlock this object. If there is a pending lock request, give ****************************************************************************/ RCODE ServerLockObject::Unlock( FLMBOOL bLogEvent, - FDB_p pDb, + FDB * pDb, FLMBOOL bRelease, DB_STATS * pDbStats ) { RCODE rc = FERR_OK; F_SEM hESem; - LOCK_WAITER_p pLockWaiter; + LOCK_WAITER * pLockWaiter; F_MutexRef MutexRef( m_pServerLockMgr->GetSemPtr()); MutexRef.Lock(); @@ -932,7 +932,7 @@ RCODE ServerLockObject::Unlock( // us to end up in here again! if (bLogEvent && - gv_FlmSysData.EventHdrs [F_EVENT_LOCKS].pEventCBList) + gv_FlmSysData.LockEvents.pEventCBList) { flmDoEventCallback( F_EVENT_LOCKS, F_EVENT_LOCK_RELEASED, @@ -1064,7 +1064,7 @@ void ServerLockObject::GetLockInfo( FLOCK_INFO * pLockInfo ) { - LOCK_WAITER_p pLockWaiter; + LOCK_WAITER * pLockWaiter; F_MutexRef MutexRef( m_pServerLockMgr->GetSemPtr()); f_memset( pLockInfo, 0, sizeof( FLOCK_INFO)); @@ -1258,7 +1258,7 @@ Desc: Returns TRUE if there are lock waiters with a priority > iPriority FLMBOOL ServerLockObject::haveHigherPriorityWaiter( FLMINT iPriority) { - LOCK_WAITER_p pLockWaiter; + LOCK_WAITER * pLockWaiter; F_MutexRef MutexRef( m_pServerLockMgr->GetSemPtr()); FLMBOOL bWaiters = FALSE; diff --git a/flaim/src/fsrvlock.h b/flaim/src/fsrvlock.h index 82ac102..9f98df0 100644 --- a/flaim/src/fsrvlock.h +++ b/flaim/src/fsrvlock.h @@ -46,10 +46,9 @@ typedef RFileItemId * RFileItemId_p; Desc: This structure is used to keep track of threads waiting for a lock. **************************************************************************/ -typedef struct Lock_Waiter * LOCK_WAITER_p; -typedef struct Lock_Waiter +typedef struct LOCK_WAITER { - ServerLockObject_p pLockObject; // Pointer to lock object. + ServerLockObject * pLockObject; // Pointer to lock object. FLMUINT uiThreadId; // Thread of waiter F_SEM hESem; // Semaphore to signal when lock is // granted (or denied). @@ -65,12 +64,12 @@ typedef struct Lock_Waiter FLMINT iPriority; // Priority of waiter. F_TMSTAMP StartTime; // Time we started waiting (for stats) DB_STATS * pDbStats; // Statistics to update. - LOCK_WAITER_p pNext; // Next lock waiter in list. - LOCK_WAITER_p pPrev; // Previous lock waiter in list. - LOCK_WAITER_p pNextGlobal; // Next lock waiter in global list + LOCK_WAITER * pNext; // Next lock waiter in list. + LOCK_WAITER * pPrev; // Previous lock waiter in list. + LOCK_WAITER * pNextGlobal; // Next lock waiter in global list // that is ordered according to // udWaitEndTime. - LOCK_WAITER_p pPrevGlobal; // Previous lock waiter in global list + LOCK_WAITER * pPrevGlobal; // Previous lock waiter in global list } LOCK_WAITER; /**************************************************************************** @@ -112,7 +111,7 @@ public: LOCK_WAITER * pLockWaiter); FINLINE void RemoveWaiter( - LOCK_WAITER_p pLockWaiter) + LOCK_WAITER * pLockWaiter) { if (pLockWaiter->pNextGlobal) { @@ -157,7 +156,7 @@ public: private: F_MUTEX * m_phMutex; - FBUCKET_p m_pHashTbl; + FBUCKET * m_pHashTbl; LOCK_WAITER * m_pFirstLockWaiter; FLMUINT m_uiNumAvail; ServerLockObject * m_pAvailLockList; @@ -189,7 +188,7 @@ public: F_ItemId * pItemId) = 0; virtual FLMUINT GetHashBucket( - FBUCKET_p pHashTbl, + FBUCKET * pHashTbl, FLMUINT uiHashTblSize) = 0; FINLINE FLMUINT GetItemType( void) @@ -215,7 +214,7 @@ class FFileItemId : public F_ItemId public: FINLINE FFileItemId( - FFILE_p pFile, + FFILE * pFile, FLMBOOL bTrans) { m_pFile = pFile; @@ -232,7 +231,7 @@ public: F_ItemId * pItemId); FINLINE FLMUINT GetHashBucket( - FBUCKET_p pHashTbl, + FBUCKET * pHashTbl, FLMUINT uiHashTblSize) { char szFileName[ F_PATH_MAX_SIZE]; @@ -256,7 +255,7 @@ public: private: - FFILE_p m_pFile; + FFILE * m_pFile; }; /**************************************************************************** @@ -277,7 +276,7 @@ public: F_ItemId * pItemId); FINLINE FLMUINT GetHashBucket( - FBUCKET_p pHashTbl, + FBUCKET * pHashTbl, FLMUINT uiHashTblSize) { return( flmStrHashBucket( m_szFileName, pHashTbl, uiHashTblSize)); @@ -319,7 +318,7 @@ public: RCODE Lock( FLMBOOL bLogEvent, - FDB_p pDb, + FDB * pDb, FLMBOOL bSendSuspendEvent, FLMBOOL bExclLock, FLMUINT uiMaxWaitSecs, @@ -328,7 +327,7 @@ public: RCODE Unlock( FLMBOOL bLogEvent, - FDB_p pDb, + FDB * pDb, FLMBOOL bRelease = FALSE, DB_STATS * pDbStats = NULL); diff --git a/flaim/src/fssearch.cpp b/flaim/src/fssearch.cpp index e1e3261..4af3995 100644 --- a/flaim/src/fssearch.cpp +++ b/flaim/src/fssearch.cpp @@ -24,156 +24,142 @@ #include "flaimsys.h" -FSTATIC FLMUINT FSKeyCmp( - BTSK_p pStack, - FLMBYTE * key, - FLMUINT uiKeyLen, - FLMUINT drnDomain); +FSTATIC FLMUINT FSKeyCmp( + BTSK * pStack, + FLMBYTE * key, + FLMUINT uiKeyLen, + FLMUINT drnDomain); - -/*************************************************************************** -Desc: Search the b-tree for a matching key. Set up stack for updates. - If index search using dinDomain. dinDomain MUST be 0 for data recs. - dinDomain is ONE more than the expected target for index ref sets. - This is because of the compare routine must have dinDomain contain - a value in order to test the domain. - -In: stackRV - points to 'n' level stack, returns leaf stack level - key - points to key requested to search for - keylen - length of the key - dinDomain - domain of index key requested - -Out: Stack set up for each level & stack[level].bsStatus set to... - BT_EQ_KEY (0) if equal key was found - BT_GT_KEY (1) if greater than key was found - BT_END_OF_DATA (0xFFFF) if marker was hit before eq or gt key found - -Return: RCODE - FERR_OK,FERR_OLD_VIEW or other error -Notes: All buffers for the stack (pKeyBuf and BlkBuf must have been - allocated before the call. -Notes: btSearch responsible for bsLevel & bsBlock in stack structure. -*****************************************************************************/ +/**************************************************************************** +Desc: Search the b-tree for a matching key. +****************************************************************************/ RCODE FSBtSearch( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p * pStackRV, /* Stack of variables for each level */ - FLMBYTE * key, /* The input key to search for */ - FLMUINT keyLen, /* Length of the key (not null term) */ - FLMUINT dinDomain /* INDEXES ONLY - lower bounds of din */ - ) + FDB * pDb, + LFILE * pLFile, + BTSK ** pStackRV, + FLMBYTE * key, + FLMUINT keyLen, + FLMUINT dinDomain) { - RCODE rc = FERR_OK; // Technically, don't need to set, but we - BTSK_p pStack = *pStackRV; - FLMBYTE * pKeyBuf = pStack->pKeyBuf;// Used to set key buf on each btsk. + RCODE rc = FERR_OK; + BTSK * pStack = *pStackRV; + FLMBYTE * pKeyBuf = pStack->pKeyBuf; FLMUINT uiBlkAddr; FLMUINT uiKeyBufSize; LFILE TmpLFile; - // don't want a maintenance problem. uiKeyBufSize = (pLFile->uiLfType == LF_INDEX) ? MAX_KEY_SIZ : DIN_KEY_SIZ; - - /* Get the correct root block specified in the LFILE. */ - if( RC_BAD( rc = FSGetRootBlock( pDb, &pLFile, &TmpLFile, pStack))) + // Get the correct root block specified in the LFILE. + + if (RC_BAD( rc = FSGetRootBlock( pDb, &pLFile, &TmpLFile, pStack))) { if (rc == FERR_NO_ROOT_BLOCK) { flmAssert( pLFile->uiRootBlk == BT_END); rc = FERR_OK; } + goto Exit; } - /**---------------------------------------------- - *** MAIN LOOP - *** Read each block going down the b-tree. - *** Save state information in the pStack[]. - ***---------------------------------------------*/ - - for(;;) + // MAIN LOOP Read each block going down the b-tree. Save state + // information in the pStack[]. + + for (;;) { pStack->uiFlags = FULL_STACK; pStack->uiKeyBufSize = uiKeyBufSize; - if( pStack->uiBlkType != BHT_NON_LEAF_DATA) + + if (pStack->uiBlkType != BHT_NON_LEAF_DATA) { rc = FSBtScan( pStack, key, keyLen, dinDomain); } else { - rc = FSBtScanNonLeafData( pStack, keyLen == 1 - ? *key - : flmBigEndianToUINT32( key)); + rc = FSBtScanNonLeafData( pStack, + keyLen == 1 + ? (FLMUINT) *key + : (FLMUINT) flmBigEndianToUINT32( key)); } - if( RC_BAD( rc)) + + if (RC_BAD( rc)) { goto Exit; } - // VISIT: Verify byLevel for cyclic loops. - - if( !pStack->uiLevel) // Leaf level? - break; // Done + // VISIT: Verify byLevel for cyclic loops. - uiBlkAddr = FSChildBlkAddr( pStack ); + if (!pStack->uiLevel) + { + // Leaf level - we are done. + + break; + } - pStack++; // Next btree pStack level. - pStack->pKeyBuf = pKeyBuf; // need to set for each pStack. + uiBlkAddr = FSChildBlkAddr( pStack); - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack ))) + pStack++; + pStack->pKeyBuf = pKeyBuf; + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + { goto Exit; + } } - *pStackRV = pStack; // Set the stack return value. + + *pStackRV = pStack; Exit: - return( rc); + + return (rc); } - -/*************************************************************************** -Desc: Search the right-most end of the b-tree. Set up stack for updates. -Out: Stack set up for each level & stack[level].bsStatus set to... - BT_EQ_KEY (0) if equal key was found - BT_GT_KEY (1) if greater than key was found - BT_END_OF_DATA (0xFFFF) if marker was hit before eq or gt key found -*****************************************************************************/ + +/**************************************************************************** +Desc: Search the right-most end of the b-tree. +****************************************************************************/ RCODE FSBtSearchEnd( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p * pStackRV, /* Stack of variables for each level */ - FLMUINT uiDrn) /* Used to position and setup for update */ + FDB * pDb, + LFILE * pLFile, // Logical file definition + BTSK ** pStackRV, // Stack of variables for each level + FLMUINT uiDrn) // Used to position and setup for update { - RCODE rc = FERR_OK; // Technically, don't need to set, but we - BTSK_p pStack = *pStackRV; - FLMBYTE * pKeyBuf = pStack->pKeyBuf;// Used to set key buf on each btsk. - FLMBYTE key[ DIN_KEY_SIZ + 4 ];/* Key buffer pointed to by stack */ + RCODE rc = FERR_OK; + BTSK * pStack = *pStackRV; + FLMBYTE * pKeyBuf = pStack->pKeyBuf; + FLMBYTE key[ DIN_KEY_SIZ + 4]; FLMUINT uiBlkAddr; LFILE TmpLFile; - /* Get the correct root block specified in the LFILE. */ - if( RC_BAD( rc = FSGetRootBlock( pDb, &pLFile, &TmpLFile, pStack))) + // Get the correct root block specified in the LFILE. + + if (RC_BAD( rc = FSGetRootBlock( pDb, &pLFile, &TmpLFile, pStack))) { if (rc == FERR_NO_ROOT_BLOCK) { flmAssert( pLFile->uiRootBlk == BT_END); rc = FERR_OK; } + goto Exit; } flmUINT32ToBigEndian( (FLMUINT32)uiDrn, key); - for(;;) + for (;;) { pStack->uiFlags = FULL_STACK; pStack->uiKeyBufSize = DIN_KEY_SIZ; // Remove all scanning from non-leaf data blocks (both formats). - if( pStack->uiLevel) + + if (pStack->uiLevel) { - pStack->uiCurElm = pStack->uiBlkEnd; // Position past last element - FSBtPrevElm( pDb, pLFile, pStack ); // Build full key in pKeyBuf[] + pStack->uiCurElm = pStack->uiBlkEnd; // Position past last element + FSBtPrevElm( pDb, pLFile, pStack); // Build full key in pKeyBuf[] } else { - if( pStack->uiBlkType != BHT_NON_LEAF_DATA) + if (pStack->uiBlkType != BHT_NON_LEAF_DATA) { rc = FSBtScan( pStack, key, DIN_KEY_SIZ, 0); } @@ -181,57 +167,67 @@ RCODE FSBtSearchEnd( { rc = FSBtScanNonLeafData( pStack, uiDrn); } - if( RC_BAD( rc)) + + if (RC_BAD( rc)) + { goto Exit; + } } - if( !pStack->uiLevel) // Leaf level? - break; // Done - uiBlkAddr = FSChildBlkAddr( pStack ); - pStack++; // Next btree pStack level. - pStack->pKeyBuf = pKeyBuf; // need to set for each pStack. + if (!pStack->uiLevel) + { + // Leaf level - we are done. + + break; + } - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack ))) + uiBlkAddr = FSChildBlkAddr( pStack); + pStack++; + pStack->pKeyBuf = pKeyBuf; + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + { goto Exit; + } } - *pStackRV = pStack; // Set the stack return value. + + *pStackRV = pStack; Exit: - return( rc); + + return (rc); } /**************************************************************************** -Desc: Returns the root block of a passed-in LFILE +Desc: Returns the root block of a passed-in LFILE ****************************************************************************/ RCODE FSGetRootBlock( - FDB_p pDb, - LFILE ** ppLFile, /* Logical file definition */ - LFILE * pTmpLFile, - BTSK_p pStack) /* Stack of variables for each level */ + FDB * pDb, + LFILE ** ppLFile, + LFILE * pTmpLFile, + BTSK * pStack) { - RCODE rc = FERR_OK; - LFILE * pLFile = *ppLFile; - FLMUINT uiBlkAddr; - FLMBOOL bRereadLFH = FALSE; + RCODE rc = FERR_OK; + LFILE * pLFile = *ppLFile; + FLMUINT uiBlkAddr; + FLMBOOL bRereadLFH = FALSE; - /* - Make Sure this is the correct root block in the LFILE area. - If not then read in the LFH structure and try again. - It would be nice to have a routine that reads only root blocks. - DSS: Added check for uiBlkAddr >= pDb->Loghdr.uiLogicalEOF - because the pLFile could have a root block address of an aborted - update transaction where the root block has not yet been fixed up by - the aborting transaction (in a shared environment). - */ - - if( ((uiBlkAddr = pLFile->uiRootBlk) == BT_END) || + // Make Sure this is the correct root block in the LFILE area. If not + // then read in the LFH structure and try again. It would be nice to + // have a routine that reads only root blocks. DSS: Added check for + // uiBlkAddr >= pDb->Loghdr.uiLogicalEOF because the pLFile could have + // a root block address of an aborted update transaction where the root + // block has not yet been fixed up by the aborting transaction (in a + // shared environment). + + if (((uiBlkAddr = pLFile->uiRootBlk) == BT_END) || (uiBlkAddr >= pDb->LogHdr.uiLogicalEOF)) { bRereadLFH = TRUE; } - else if( RC_BAD(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + else if (RC_BAD( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) { - if( rc == FERR_DATA_ERROR || (rc == FERR_OLD_VIEW && !pDb->uiKilledTime)) + if (rc == FERR_DATA_ERROR || (rc == FERR_OLD_VIEW && !pDb->uiKilledTime)) { bRereadLFH = TRUE; pStack->uiBlkAddr = BT_END; @@ -241,145 +237,139 @@ RCODE FSGetRootBlock( goto Exit; } } - else /* Check for valid root block - Root Flag and Logical file number */ + else { + // Check for valid root block - Root Flag and Logical file number + FLMBYTE * pBlk = pStack->pBlk; - if( !(BH_IS_ROOT_BLK( pBlk)) - || (pLFile->uiLfNum != FB2UW( &pBlk[ BH_LOG_FILE_NUM ]))) - { + if (!(BH_IS_ROOT_BLK( pBlk)) || + (pLFile->uiLfNum != FB2UW( &pBlk[BH_LOG_FILE_NUM]))) + { bRereadLFH = TRUE; FSReleaseBlock( pStack, FALSE); pStack->uiBlkAddr = BT_END; } } - /* Reread the LFH from disk if we do not have the root block */ - if( bRereadLFH) - { - /* - If we are in a read transaction and we are using an HFSHARE - structure that is shared among multiple threads, copy the LFILE - structure so that we don't mess up a thread that may be doing - an update. The only members of the LFILE that might be - different after the FSLFileRead are as follows: + // Reread the LFH from disk if we do not have the root block - uiRootBlk and VER11 elements are: byLevel, uiNextDrn, and uiLastBlk. - - None of these members are needed outside this routine during a - read transaction, so it is OK to use a temporary LFILE inside - this routine. - */ - - if( flmGetDbTransType( pDb) == FLM_READ_TRANS) + if (bRereadLFH) + { + + // If we are in a read transaction, copy the LFILE structure so + // that we don't mess up a thread that may be doing an update. + + if (flmGetDbTransType( pDb) == FLM_READ_TRANS) { - f_memcpy( pTmpLFile, pLFile, sizeof( LFILE)); + f_memcpy( pTmpLFile, pLFile, sizeof(LFILE)); pLFile = pTmpLFile; } - if( RC_BAD( rc = flmLFileRead( pDb, pLFile))) + if (RC_BAD( rc = flmLFileRead( pDb, pLFile))) { goto Exit; } - /* If there is no root block, return right away */ + // If there is no root block, return right away - if( (uiBlkAddr = pLFile->uiRootBlk) == BT_END) + if ((uiBlkAddr = pLFile->uiRootBlk) == BT_END) { - /* - The caller of FSGetRootBlock is expected to check for and - handle FERR_NO_ROOT_BLOCK. It should NEVER be returned - to the application. - NOTE: Checking for BT_END_OF_DATA will not work in every - case to check for no root block because it is not always - initialized before calling FSGetRootBlock, so it could - have garbage in it if we don't end up going through this - code path. - */ + // The caller of FSGetRootBlock is expected to check for and + // handle FERR_NO_ROOT_BLOCK. It should NEVER be returned to the + // application. NOTE: Checking for BT_END_OF_DATA will not work + // in every case to check for no root block because it is not + // always initialized before calling FSGetRootBlock, so it could + // have garbage in it if we don't end up going through this code + // path. rc = RC_SET( FERR_NO_ROOT_BLOCK); pStack->uiCmpStatus = BT_END_OF_DATA; pStack->uiBlkAddr = BT_END; goto Exit; } - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) - goto Exit; /* Usually returns OLD_VIEW or BLOCK_MODIFIED */ + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, uiBlkAddr, pStack))) + { + goto Exit; + } } Exit: + *ppLFile = pLFile; - return( rc); + return (rc); } -/*************************************************************************** -Desc: Scan a b-tree block for a matching key at any b-tree block level. -Notes: This routine has been optimized for speed. Routine calls - have been taken out in order to improve the performance. -*****************************************************************************/ +/**************************************************************************** +Desc: Scan a b-tree block for a matching key at any b-tree block level. +****************************************************************************/ RCODE FSBtScan( - BTSK_p pStack, // [in/out] Stack of variables for each level - FLMBYTE * pSearchKey, // The input key to search for - FLMUINT uiSearchKeyLen, // Length of the key (not null terminated) - FLMUINT dinDomain) // INDEXES ONLY - lower bounds of din + BTSK * pStack, // [in/out] Stack of variables for each level + FLMBYTE * pSearchKey, // The input key to search for + FLMUINT uiSearchKeyLen, // Length of the key (not null terminated) + FLMUINT dinDomain) // INDEXES ONLY - lower bounds of din { - RCODE rc = FERR_OK;// MUST initialize. - FLMBYTE * pCurElm; // Points to the current element. - FLMBYTE * pBlk; // Points to the cache block. - FLMBYTE * pKeyBuf; // Points to pStack->pKeyBuf (optimization). - FLMBYTE * pElmKey; // Points to the key within the element. - FLMUINT uiRecLen = 0; // Length of the record portion. - FLMUINT uiPrevKeyCnt; // Number left end bytes compressed - FLMUINT uiElmKeyLen; // Length of the current element's key portion - FLMUINT uiBlkType; // B-tree block type - Leaf or non-leaf. - FLMUINT uiElmOvhd; // Number bytes overhead for element. - FLMUINT uiBytesMatched; // Number of bytes matched with pSearchKey - // and cur element. Related to uiPrevKeyCnt. + RCODE rc = FERR_OK; + FLMBYTE * pCurElm; // Points to the current element. + FLMBYTE * pBlk; // Points to the cache block. + FLMBYTE * pKeyBuf; // Points to pStack->pKeyBuf (optimization). + FLMBYTE * pElmKey; // Points to the key within the element. + FLMUINT uiRecLen = 0; // Length of the record portion. + FLMUINT uiPrevKeyCnt; // Number left end bytes compressed + FLMUINT uiElmKeyLen; // Length of the current element's key portion + FLMUINT uiBlkType; // B-tree block type - Leaf or non-leaf. + FLMUINT uiElmOvhd; // Number bytes overhead for element. + FLMUINT uiBytesMatched; // Number of bytes matched with pSearchKey + uiBlkType = pStack->uiBlkType; flmAssert( uiBlkType != BHT_NON_LEAF_DATA); - // Initialize stack variables for possibly better performance. + // Initialize stack variables for possibly better performance. + pKeyBuf = pStack->pKeyBuf; - pBlk = pStack->pBlk; + pBlk = pStack->pBlk; uiElmOvhd = pStack->uiElmOvhd; pStack->uiCurElm = BH_OVHD; pStack->uiKeyLen = pStack->uiPKC = pStack->uiPrevElmPKC = 0; uiBytesMatched = 0; - for( ;;) // while bsCurElm < bsBlkEnd + for (;;) { - pCurElm = &pBlk[ pStack->uiCurElm]; - uiElmKeyLen = BBE_GETR_KL( pCurElm ); + pCurElm = &pBlk[pStack->uiCurElm]; + uiElmKeyLen = BBE_GETR_KL( pCurElm); - // Read in RAW mode - doesn't do all bit checking - - if( (uiPrevKeyCnt = (BBE_GETR_PKC( pCurElm ))) > BBE_PKC_MAX) + // Read in RAW mode - doesn't do all bit checking + + if ((uiPrevKeyCnt = (BBE_GETR_PKC( pCurElm))) > BBE_PKC_MAX) { uiElmKeyLen += (uiPrevKeyCnt & BBE_KL_HBITS) << BBE_KL_SHIFT_BITS; uiPrevKeyCnt &= BBE_PKC_MAX; } - // Should not have a non-zero PKC if we are on the first element - // of a block + // Should not have a non-zero PKC if we are on the first element of + // a block - if( uiPrevKeyCnt && pStack->uiCurElm == BH_OVHD) + if (uiPrevKeyCnt && pStack->uiCurElm == BH_OVHD) { rc = RC_SET( FERR_DATA_ERROR); goto Exit; } // Get the record portion length when on the leaf blocks. - - if( uiBlkType == BHT_LEAF) + + if (uiBlkType == BHT_LEAF) { - uiRecLen = BBE_GET_RL( pCurElm ); + uiRecLen = BBE_GET_RL( pCurElm); } pStack->uiPrevElmPKC = pStack->uiPKC; - - // The zero length key is the terminating element in a right-most block. - if( (pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen) == 0) + // The zero length key is the terminating element in a right-most + // block. + + if ((pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen) == 0) { pStack->uiPrevElmPKC = f_min( uiBytesMatched, BBE_PKC_MAX); pStack->uiPKC = 0; @@ -388,623 +378,701 @@ RCODE FSBtScan( } // Handle special case of left-end compression maxing out. - if( uiPrevKeyCnt == BBE_PKC_MAX && BBE_PKC_MAX < uiBytesMatched) + + if (uiPrevKeyCnt == BBE_PKC_MAX && BBE_PKC_MAX < uiBytesMatched) { uiBytesMatched = BBE_PKC_MAX; } // Check out this element to see if the key matches. - if( uiPrevKeyCnt == uiBytesMatched) + + if (uiPrevKeyCnt == uiBytesMatched) { - pElmKey = &pCurElm[ uiElmOvhd ]; - for(;;) + pElmKey = &pCurElm[uiElmOvhd]; + for (;;) { + // All bytes of the search key are matched? - if( uiBytesMatched == uiSearchKeyLen) + + if (uiBytesMatched == uiSearchKeyLen) { pStack->uiPKC = f_min( uiBytesMatched, BBE_PKC_MAX); + // Build pKeyBuf with the search key because it matches. // Current key is either equal or greater than search key. - if( uiSearchKeyLen < pStack->uiKeyLen) + if (uiSearchKeyLen < pStack->uiKeyLen) { - f_memcpy( &pKeyBuf[ uiSearchKeyLen], pElmKey, - pStack->uiKeyLen - uiSearchKeyLen); + f_memcpy( &pKeyBuf[uiSearchKeyLen], pElmKey, + pStack->uiKeyLen - uiSearchKeyLen); pStack->uiCmpStatus = BT_GT_KEY; } else { - if( dinDomain) + if (dinDomain) { - FLMBYTE * pCurRef = pCurElm; - if( (dinDomain - 1) < - FSGetDomain( &pCurRef, (FLMBYTE)uiElmOvhd)) + FLMBYTE* pCurRef = pCurElm; + if ((dinDomain - 1) < + FSGetDomain( &pCurRef, (FLMBYTE) uiElmOvhd)) { + // Keep going... + goto Next_Element; } } + pStack->uiCmpStatus = BT_EQ_KEY; } + f_memcpy( pKeyBuf, pSearchKey, uiSearchKeyLen); goto Exit; } + // .. else matches all the bytes in the element key. - if( uiBytesMatched == pStack->uiKeyLen) + + if (uiBytesMatched == pStack->uiKeyLen) { pStack->uiPKC = f_min( uiBytesMatched, BBE_PKC_MAX); + // Need an outer break call here - forced to do a goto. + goto Next_Element; } // Compare the next byte in the search key and element - if( pSearchKey[ uiBytesMatched] != *pElmKey) + + if (pSearchKey[uiBytesMatched] != *pElmKey) + { break; + } + uiBytesMatched++; pElmKey++; } + pStack->uiPKC = f_min( uiBytesMatched, BBE_PKC_MAX); // Check if we are done comparing, if so build pKeyBuf[]. - if( pSearchKey[ uiBytesMatched] < *pElmKey) + + if (pSearchKey[uiBytesMatched] < *pElmKey) { - if( uiBytesMatched) + if (uiBytesMatched) { f_memcpy( pKeyBuf, pSearchKey, uiBytesMatched); } - f_memcpy( &pKeyBuf[ uiBytesMatched], pElmKey, - pStack->uiKeyLen - uiBytesMatched); + + f_memcpy( &pKeyBuf[uiBytesMatched], pElmKey, + pStack->uiKeyLen - uiBytesMatched); pStack->uiCmpStatus = BT_GT_KEY; goto Exit; } } - else if( uiPrevKeyCnt < uiBytesMatched) + else if (uiPrevKeyCnt < uiBytesMatched) { - // Current key > search key. Set pKeyBuf and break out. + + // Current key > search key. Set pKeyBuf and break out. + pStack->uiPKC = uiPrevKeyCnt; - if( uiPrevKeyCnt) + if (uiPrevKeyCnt) { - // VISIT: Call a small memcpy here. f_memcpy( pKeyBuf, pSearchKey, uiPrevKeyCnt); } - f_memcpy( &pKeyBuf[ uiPrevKeyCnt], &pCurElm[ uiElmOvhd], uiElmKeyLen); + + f_memcpy( &pKeyBuf[uiPrevKeyCnt], &pCurElm[uiElmOvhd], uiElmKeyLen); pStack->uiCmpStatus = BT_GT_KEY; goto Exit; } - // else the key is less than the search key (uiPrevKeyCnt > uiBytesMatched). + + // else the key is less than the search key (uiPrevKeyCnt > + // uiBytesMatched). Next_Element: - /* Position to the next element */ - pStack->uiCurElm += uiElmKeyLen + ((uiBlkType == BHT_LEAF ) - ? (BBE_KEY + uiRecLen) - : (BNE_IS_DOMAIN(pCurElm) ? (BNE_DOMAIN_LEN + uiElmOvhd) - : uiElmOvhd)); - - // Most common check first. - if( pStack->uiCurElm < pStack->uiBlkEnd) - continue; + // Position to the next element - if( pStack->uiCurElm == pStack->uiBlkEnd) + pStack->uiCurElm += uiElmKeyLen + + ((uiBlkType == BHT_LEAF) + ? (BBE_KEY + uiRecLen) + : (BNE_IS_DOMAIN( pCurElm) + ? (BNE_DOMAIN_LEN + uiElmOvhd) + : uiElmOvhd)); + + // Most common check first. + + if (pStack->uiCurElm < pStack->uiBlkEnd) { - // On the equals conditition it may be OK in some very special cases. + continue; + } + + if (pStack->uiCurElm == pStack->uiBlkEnd) + { + + // On the equals conditition it may be OK in some very special + // cases. + pStack->uiCmpStatus = BT_END_OF_DATA; goto Exit; } + // Marched off the end of the block - something is corrupt. + rc = RC_SET( FERR_CACHE_ERROR); goto Exit; } Exit: - return( rc); + + return (rc); } -/*************************************************************************** -Desc: Binary search into a non-leaf data record block. -In: Stack, key, keyLen, dinDomain (value for indexes only else 0) -Out: Stack set up - bsStatus set to following... - BT_EQ_KEY (0) if equal key was found - BT_GT_KEY (1) if greater than key was found - BT_END_OF_DATA (0xFFFF) if marker was hit before eq or gt key found -Return: RCODE - FERR_OK -*****************************************************************************/ +/**************************************************************************** +Desc: Binary search into a non-leaf data record block. +****************************************************************************/ RCODE FSBtScanNonLeafData( - BTSK_p pStack, - FLMUINT uiDrn) + BTSK * pStack, + FLMUINT uiDrn) { RCODE rc = FERR_OK; - FLMBYTE * pBlk = pStack->pBlk; // Points to the cache block. - FLMUINT uiLow = 0, - uiMid, - uiHigh = ((pStack->uiBlkEnd - BH_OVHD) >> 3) - 1; + FLMBYTE * pBlk = pStack->pBlk; + FLMUINT uiLow = 0; + FLMUINT uiMid; + FLMUINT uiHigh = ((pStack->uiBlkEnd - BH_OVHD) >> 3) - 1; FLMUINT uiTblSize = uiHigh; FLMUINT uiCurDrn; pStack->uiCmpStatus = BT_GT_KEY; - for(;;) + for (;;) { - uiMid = (uiLow + uiHigh) >> 1; // (uiLow + uiHigh) / 2 - + uiMid = (uiLow + uiHigh) >> 1; + uiCurDrn = flmBigEndianToUINT32( &pBlk[ BH_OVHD + (uiMid << 3)]); - if( uiCurDrn == 0) + if (uiCurDrn == 0) { + // Special case - at the end of a rightmost block. - pStack->uiCmpStatus = BT_EQ_KEY; //BT_END_OF_DATA; + + pStack->uiCmpStatus = BT_EQ_KEY; break; } - if( uiDrn == uiCurDrn) + + if (uiDrn == uiCurDrn) { + // Remember a data record can span multiple blocks (same DRN). - while( uiMid) + + while (uiMid) { uiCurDrn = flmBigEndianToUINT32( &pBlk[ BH_OVHD + ((uiMid - 1) << 3)]); - if( uiDrn != uiCurDrn) + if (uiDrn != uiCurDrn) { break; } - + uiMid--; } + pStack->uiCmpStatus = BT_EQ_KEY; break; } // Down to one item if too high then position to next item. - if( uiLow >= uiHigh) + + if (uiLow >= uiHigh) { - if( (uiDrn > uiCurDrn) && uiMid < uiTblSize) + if ((uiDrn > uiCurDrn) && uiMid < uiTblSize) + { uiMid++; + } break; } // If too high then try lower section - if( uiDrn < uiCurDrn) + + if (uiDrn < uiCurDrn) { + // First item too high? - if( uiMid == 0) + + if (uiMid == 0) + { break; + } + uiHigh = uiMid - 1; } - else // try upper section because mid value is too low. + else { - if( uiMid == uiTblSize) + // Try upper section because mid value is too low. + + if (uiMid == uiTblSize) { uiMid++; pStack->uiCmpStatus = BT_END_OF_DATA; - break; // Done - Hit the top + break; } - uiLow = uiMid + 1; /* Too low */ + + uiLow = uiMid + 1; } } // Set curElm and the key buffer. + pStack->uiCurElm = BH_OVHD + (uiMid << 3); flmUINT32ToBigEndian( (FLMUINT32)uiCurDrn, pStack->pKeyBuf); - -//Exit: - return( rc); + return (rc); } /**************************************************************************** -Desc: Read the block information and initialize all needed pStack elements. - Assumes that bsBlock is correct. Normalizes BH_TYPE to[ 0,1] values. - Note that byElmOvhd cannot be set for non-leaf blocks unless - the version number is passed in. -Out: stack updated with needed block contents. -Notes: Same code is in FSGetBlock(). +Desc: Read the block information and initialize all needed pStack + elements. ****************************************************************************/ void FSBlkToStack( - BTSK_p pStack) + BTSK * pStack) { - FLMBYTE * pBlk = pStack->pBlk; - FLMUINT uiBlkType; + FLMBYTE * pBlk = pStack->pBlk; + FLMUINT uiBlkType; - pStack->uiBlkType = uiBlkType = (FLMUINT)(BH_GET_TYPE( pBlk )); + pStack->uiBlkType = uiBlkType = (FLMUINT) (BH_GET_TYPE( pBlk)); - /** - *** The standard overhead is used in the pStack - *** Compares are made to determine if the element is extended. - **/ - if( uiBlkType == BHT_LEAF) + // The standard overhead is used in the pStack Compares are made to + // determine if the element is extended. + + if (uiBlkType == BHT_LEAF) { pStack->uiElmOvhd = BBE_KEY; } - else if( uiBlkType == BHT_NON_LEAF_DATA) + else if (uiBlkType == BHT_NON_LEAF_DATA) { pStack->uiElmOvhd = BNE_DATA_OVHD; } - else if( uiBlkType == BHT_NON_LEAF) + else if (uiBlkType == BHT_NON_LEAF) { pStack->uiElmOvhd = BNE_KEY_START; } - else if( uiBlkType == BHT_NON_LEAF_COUNTS) + else if (uiBlkType == BHT_NON_LEAF_COUNTS) { pStack->uiElmOvhd = BNE_KEY_COUNTS_START; } else { - flmAssert(0); + flmAssert( 0); pStack->uiElmOvhd = BNE_KEY_START; } pStack->uiKeyLen = pStack->uiPKC = pStack->uiPrevElmPKC = 0; pStack->uiCurElm = BH_OVHD; - pStack->uiBlkEnd = (FLMUINT)FB2UW( &pBlk[ BH_ELM_END ] ); - pStack->uiLevel = (FLMUINT)pBlk[ BH_LEVEL ]; + pStack->uiBlkEnd = (FLMUINT) FB2UW( &pBlk[BH_ELM_END]); + pStack->uiLevel = (FLMUINT) pBlk[BH_LEVEL]; } -/*************************************************************************** -Desc: Scan to a specific element (pStack->uiCurElm) in a b-tree block. - Builds the current key in pStack->pKeyBuf and sets up the stack - for an insert of an element. - The block must exist and never contain a lone LEM (last elm marker). -Notes: This may be called at ANY b-tree level. -*****************************************************************************/ +/**************************************************************************** +Desc: Scan to a specific element (pStack->uiCurElm) in a b-tree block. +****************************************************************************/ RCODE FSBtScanTo( - BTSK_p pStack, // Stack of variables for each level - FLMBYTE * pSearchKey, // The input key to search for - FLMUINT uiSearchKeyLen, // Length of the key (not null term) - FLMUINT dinDomain // INDEXES ONLY - lower bounds of din - ) + BTSK * pStack, + FLMBYTE * pSearchKey, + FLMUINT uiSearchKeyLen, + FLMUINT dinDomain) { - FLMBYTE * pCurElm; // Points to the current element. - FLMBYTE * pBlk; // Points to block - optimization - FLMBYTE * pKeyBuf = pStack->pKeyBuf; // Key buffer to fill - FLMBYTE * pPrevElm; // Points to previous element. RCODE rc = FERR_OK; - FLMUINT uiPrevKeyCnt = 0; // Current elements previous key count. - FLMUINT uiElmKeyLen = 0; // Current element key length. - FLMUINT uiTargetCurElm = pStack->uiCurElm;// Target value to scan to. - FLMUINT uiElmOvhd; // Number bytes overhead for element. - FLMUINT uiKeyBufLen; // Length of key in pKeyBuf. + FLMBYTE * pCurElm; + FLMBYTE * pBlk; + FLMBYTE * pKeyBuf = pStack->pKeyBuf; + FLMBYTE * pPrevElm; + FLMUINT uiPrevKeyCnt = 0; + FLMUINT uiElmKeyLen = 0; + FLMUINT uiTargetCurElm = pStack->uiCurElm; + FLMUINT uiElmOvhd; + FLMUINT uiKeyBufLen; - // Initialize section - FSBlkToStack( pStack ); // Read information & put to stack. - pBlk = pStack->pBlk; + FSBlkToStack( pStack); + pBlk = pStack->pBlk; uiElmOvhd = pStack->uiElmOvhd; - if( uiTargetCurElm > pStack->uiBlkEnd) + if (uiTargetCurElm > pStack->uiBlkEnd) { uiTargetCurElm = pStack->uiBlkEnd; } // The code is easy for non-leaf data blocks. - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) + + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) { - // target may be any byte offset in the block. - while( pStack->uiCurElm < uiTargetCurElm ) + + // Target may be any byte offset in the block. + + while (pStack->uiCurElm < uiTargetCurElm) { pStack->uiCurElm += BNE_DATA_OVHD; } - if( uiTargetCurElm < pStack->uiBlkEnd) + + if (uiTargetCurElm < pStack->uiBlkEnd) { - flmCopyDrnKey( pKeyBuf, &pBlk[ pStack->uiCurElm ]); + flmCopyDrnKey( pKeyBuf, &pBlk[pStack->uiCurElm]); pStack->uiCmpStatus = BT_EQ_KEY; } else { pStack->uiCmpStatus = BT_END_OF_DATA; } + goto Exit; } - + // Note: There is no way pPrevElm can be accessed and point to NULL // unless the block is corrupt and starts with a PKC value. + pCurElm = NULL; uiKeyBufLen = 0; - while( pStack->uiCurElm < uiTargetCurElm) + while (pStack->uiCurElm < uiTargetCurElm) { pPrevElm = pCurElm; - pCurElm = &pBlk[ pStack->uiCurElm ]; - uiPrevKeyCnt = BBE_GET_PKC( pCurElm ); - uiElmKeyLen = BBE_GET_KL( pCurElm ); - if( (pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen) > pStack->uiKeyBufSize) + pCurElm = &pBlk[pStack->uiCurElm]; + uiPrevKeyCnt = BBE_GET_PKC( pCurElm); + uiElmKeyLen = BBE_GET_KL( pCurElm); + if ((pStack->uiKeyLen = uiPrevKeyCnt + uiElmKeyLen) > pStack->uiKeyBufSize) { rc = RC_SET( FERR_CACHE_ERROR); goto Exit; } // Copy the minimum number of bytes from the previous element. - // A memcpy may be slower because this shouldn't copy very many bytes. - if( uiPrevKeyCnt > uiKeyBufLen) + + if (uiPrevKeyCnt > uiKeyBufLen) { FLMUINT uiCopyLength = uiPrevKeyCnt - uiKeyBufLen; - FLMBYTE * pSrcPtr = &pPrevElm[ uiElmOvhd]; + FLMBYTE * pSrcPtr = &pPrevElm[uiElmOvhd]; flmAssert( pCurElm != NULL); - // VISIT: Replace with an inline memcpy. - while( uiCopyLength--) + + while (uiCopyLength--) { - pKeyBuf[ uiKeyBufLen++] = *pSrcPtr++; + pKeyBuf[uiKeyBufLen++] = *pSrcPtr++; } } else { uiKeyBufLen = uiPrevKeyCnt; } - + // Position to the next element - if( pStack->uiBlkType == BHT_LEAF) - { - pStack->uiCurElm += (FLMUINT)(BBE_LEN( pCurElm )); - if( pStack->uiCurElm + BBE_LEM_LEN >= pStack->uiBlkEnd) + if (pStack->uiBlkType == BHT_LEAF) + { + pStack->uiCurElm += (FLMUINT) (BBE_LEN( pCurElm)); + if (pStack->uiCurElm + BBE_LEM_LEN >= pStack->uiBlkEnd) { - f_memcpy( &pKeyBuf[ uiKeyBufLen], &pCurElm[ uiElmOvhd], uiElmKeyLen); + f_memcpy( &pKeyBuf[uiKeyBufLen], &pCurElm[uiElmOvhd], uiElmKeyLen); - if( uiSearchKeyLen && (pStack->uiCurElm < pStack->uiBlkEnd)) + if (uiSearchKeyLen && (pStack->uiCurElm < pStack->uiBlkEnd)) { - // This is a rare and unsure case where caller needs to have - // pStack->uiPrevElmPKC set correctly. + + // This is a rare and unsure case where caller needs to + // have pStack->uiPrevElmPKC set correctly. + FSKeyCmp( pStack, pSearchKey, uiSearchKeyLen, dinDomain); } + goto Hit_End; } } else { - pStack->uiCurElm += (FLMUINT)(BNE_LEN( pStack, pCurElm)); /* Adds in DOMAIN */ - - if( pStack->uiCurElm >= pStack->uiBlkEnd) + pStack->uiCurElm += (FLMUINT) (BNE_LEN( pStack, pCurElm)); + + if (pStack->uiCurElm >= pStack->uiBlkEnd) { + // Make sure that pKeyBuf has the last element's key. - f_memcpy( &pKeyBuf[ uiKeyBufLen], &pCurElm[ uiElmOvhd], uiElmKeyLen); + + f_memcpy( &pKeyBuf[uiKeyBufLen], &pCurElm[uiElmOvhd], uiElmKeyLen); Hit_End: + pStack->uiKeyLen = 0; - pStack->uiPrevElmPKC = pStack->uiPKC; /* Change previous element */ + pStack->uiPrevElmPKC = pStack->uiPKC; pStack->uiPKC = 0; pStack->uiCmpStatus = BT_END_OF_DATA; goto Exit; } } } - // Check to see if the scan hit where you wanted, if so setup stack & pKeyBuf. - if( pStack->uiCurElm == uiTargetCurElm) + // Check to see if the scan hit where you wanted, if so setup stack & + // pKeyBuf. + + if (pStack->uiCurElm == uiTargetCurElm) { - // BE CAREFUL. Names with "target" point to this element. All other + + // BE CAREFUL. Names with "target" point to this element. All other // references include pCurElm point to the previous element. + FLMBYTE * pTargetCurElm = CURRENT_ELM( pStack); FLMUINT uiTargetPrevKeyCnt = BBE_GET_PKC( pTargetCurElm); FLMUINT uiTargetElmKeyLen = BBE_GET_KL( pTargetCurElm); // Compare the current key so that prevPKC and PKC are set. - pStack->uiCmpStatus = BT_EQ_KEY; - if( pCurElm) - { - if( uiSearchKeyLen) - { - // Copy the entire key into keyBuf to compare - output is ->uiPKC - f_memcpy( &pKeyBuf[ uiPrevKeyCnt], &pCurElm[ uiElmOvhd], uiElmKeyLen); - pStack->uiCmpStatus = FSKeyCmp( pStack, pSearchKey, - uiSearchKeyLen, dinDomain); - } - else if( uiTargetPrevKeyCnt > uiKeyBufLen) + pStack->uiCmpStatus = BT_EQ_KEY; + if (pCurElm) + { + if (uiSearchKeyLen) { - // Copy what is necessary. uiPrevKeyCnt is equal to uiKeyBufLen. + + // Copy the entire key into keyBuf to compare + + f_memcpy( &pKeyBuf[uiPrevKeyCnt], &pCurElm[uiElmOvhd], uiElmKeyLen); + pStack->uiCmpStatus = FSKeyCmp( pStack, pSearchKey, uiSearchKeyLen, + dinDomain); + } + else if (uiTargetPrevKeyCnt > uiKeyBufLen) + { + + // Copy what is necessary. uiPrevKeyCnt is equal to + // uiKeyBufLen. FLMUINT uiCopyLength = uiTargetPrevKeyCnt - uiKeyBufLen; - FLMBYTE * pSrcPtr = &pCurElm[ uiElmOvhd]; + FLMBYTE * pSrcPtr = &pCurElm[uiElmOvhd]; - // VISIT: Replace with an inline memcpy. - while( uiCopyLength--) + while (uiCopyLength--) { - pKeyBuf[ uiKeyBufLen++] = *pSrcPtr++; + pKeyBuf[uiKeyBufLen++] = *pSrcPtr++; } } } - if( (pStack->uiKeyLen = - uiTargetPrevKeyCnt + uiTargetElmKeyLen) > pStack->uiKeyBufSize) + if ((pStack->uiKeyLen = uiTargetPrevKeyCnt + uiTargetElmKeyLen) > + pStack->uiKeyBufSize) { rc = RC_SET( FERR_CACHE_ERROR); goto Exit; } - if( uiTargetElmKeyLen) + if (uiTargetElmKeyLen) { - f_memcpy( &pKeyBuf[ uiTargetPrevKeyCnt], - &pTargetCurElm[ uiElmOvhd], uiTargetElmKeyLen); + f_memcpy( &pKeyBuf[uiTargetPrevKeyCnt], &pTargetCurElm[uiElmOvhd], + uiTargetElmKeyLen); - if( uiSearchKeyLen) + if (uiSearchKeyLen) { - pStack->uiCmpStatus = FSKeyCmp( pStack, pSearchKey, uiSearchKeyLen, dinDomain ); + pStack->uiCmpStatus = FSKeyCmp( pStack, pSearchKey, uiSearchKeyLen, + dinDomain); } } - else { - /* - This will be hit on a condition where we want to insert "ABCD (10)" into - ABCD (15) - ABCD (5) - between the two keys. (10) is the DIN value. Because the keys are equal - we don't have to call compare again. The uiPKC is the uiPrevKeyCnt value. - */ + + // This will be hit on a condition where we want to insert "ABCD + // (10)" into ABCD (15) ABCD (5) between the two keys. (10) is + // the DIN value. Because the keys are equal we don't have to + // call compare again. The uiPKC is the uiPrevKeyCnt value. + pStack->uiPrevElmPKC = pStack->uiPKC; pStack->uiPKC = uiTargetPrevKeyCnt; } } else { + // Copy the remaining bytes of the current key into the buffer. - if( pCurElm) + + if (pCurElm) { - f_memcpy( &pKeyBuf[ uiPrevKeyCnt], &pCurElm[ uiElmOvhd], uiElmKeyLen); + f_memcpy( &pKeyBuf[uiPrevKeyCnt], &pCurElm[uiElmOvhd], uiElmKeyLen); } + pStack->uiCmpStatus = BT_GT_KEY; - // Not necessary to compare because we just wanted a rough position & keyBuf. } Exit: - return( rc ); + + return (rc); } -/*************************************************************************** -Desc: Standard key compare routine for a key and a b-tree element -Return: BT_EQ_KEY (0) if equal key was found - BT_GT_KEY (1) if greater than key was found - BT_LT_KEY (2) if less than (keep going) -*****************************************************************************/ +/**************************************************************************** +Desc: Standard key compare routine for a key and a b-tree element +****************************************************************************/ FSTATIC FLMUINT FSKeyCmp( - BTSK_p pStack, /* Stack of variables for each level */ - FLMBYTE * key, /* The input key to search for */ - FLMUINT uiKeyLen, /* Length of the key (not null term) */ - FLMUINT dinDomain) /* INDEXES ONLY - lower bounds of din*/ + BTSK * pStack, + FLMBYTE * key, + FLMUINT uiKeyLen, + FLMUINT dinDomain) { FLMBYTE * pCurElm; - FLMBYTE * pKeyBuf; /* Current element's key */ - FLMUINT uiCmp; /* Return value */ - FLMUINT uiCompareLen; /* Length to compare */ - FLMUINT uiOrigCompareLen; /* Original compare length */ - FLMUINT uiCurElmKeyLen; /* Current element's length */ + FLMBYTE * pKeyBuf; // Current element's key + FLMUINT uiCmp; // Return value + FLMUINT uiCompareLen; // Length to compare + FLMUINT uiOrigCompareLen; // Original compare length + FLMUINT uiCurElmKeyLen; // Current element's length FLMUINT uiPKCTemp; - /* Get again the current element's key length & compute compare length */ + // Get again the current element's key length & compute compare length + uiCurElmKeyLen = pStack->uiKeyLen; - uiOrigCompareLen = uiCompareLen = f_min( uiKeyLen, uiCurElmKeyLen ); - pKeyBuf = pStack->pKeyBuf; /* Point to the local key buffer */ - pStack->uiPrevElmPKC = pStack->uiPKC; /* Change previous element */ + uiOrigCompareLen = uiCompareLen = f_min( uiKeyLen, uiCurElmKeyLen); + pKeyBuf = pStack->pKeyBuf; // Point to the local key buffer + pStack->uiPrevElmPKC = pStack->uiPKC; // Change previous element pStack->uiPKC = 0; - while( uiCompareLen--) + while (uiCompareLen--) { - if( *key++ == *pKeyBuf++) /* Just do a left-right compare */ + if (*key++ == *pKeyBuf++) + { continue; + } uiPKCTemp = uiOrigCompareLen - (uiCompareLen + 1); pStack->uiPKC = (uiPKCTemp > BBE_PKC_MAX) ? BBE_PKC_MAX : uiPKCTemp; - /* Not equal so return */ - return( (*(--key) < *(--pKeyBuf)) ? BT_GT_KEY : BT_LT_KEY ); + + // Not equal so return + + return ((*(--key) < *(--pKeyBuf)) ? BT_GT_KEY : BT_LT_KEY); } - /* Set the prev key count value */ - pStack->uiPKC = (uiOrigCompareLen <= BBE_PKC_MAX) - ? uiOrigCompareLen - : BBE_PKC_MAX; - + // Set the prev key count value - /** Set return status, If equal then compare the dinDomain if needed. **/ - uiCmp = uiKeyLen > uiCurElmKeyLen ? BT_LT_KEY : - (uiKeyLen < uiCurElmKeyLen ? BT_GT_KEY : BT_EQ_KEY) ; + pStack->uiPKC = (uiOrigCompareLen <= BBE_PKC_MAX) + ? uiOrigCompareLen + : BBE_PKC_MAX; - if( (uiCmp == BT_EQ_KEY) && dinDomain) + // Set return status, If equal then compare the dinDomain if needed. + + uiCmp = uiKeyLen > uiCurElmKeyLen + ? BT_LT_KEY + : (uiKeyLen < uiCurElmKeyLen + ? BT_GT_KEY + : BT_EQ_KEY); + + if ((uiCmp == BT_EQ_KEY) && dinDomain) { - pCurElm = CURRENT_ELM( pStack ); - if( (dinDomain - 1) < FSGetDomain( &pCurElm, (FLMBYTE)pStack->uiElmOvhd )) + pCurElm = CURRENT_ELM( pStack); + if ((dinDomain - 1) < FSGetDomain( &pCurElm, (FLMBYTE) pStack->uiElmOvhd)) { - uiCmp = BT_LT_KEY; /* Keep going */ + uiCmp = BT_LT_KEY; } } - return( uiCmp ); + + return (uiCmp); } - /**************************************************************************** -Desc: Goto the next element within the block -Notes: The key is NOT moved into the byKeyBuf[] - LEAF: Returns FERR_BT_END_OF_DATA if positioned on the last-element-marker - (LEM) or is NOW positioned on the LEM. +Desc: Go to the next element within the block ****************************************************************************/ RCODE FSBlkNextElm( - BTSK_p pStack) /* Stack of variables for each level */ + BTSK * pStack) { - FLMBYTE * elmPtr; - FLMUINT uiElmSize; - RCODE rc = FERR_BT_END_OF_DATA; /* Code assumes at the end */ + RCODE rc = FERR_BT_END_OF_DATA; + FLMBYTE * elmPtr; + FLMUINT uiElmSize; - elmPtr = &pStack->pBlk[ pStack->uiCurElm ]; + elmPtr = &pStack->pBlk[pStack->uiCurElm]; - if( pStack->uiBlkType == BHT_LEAF) - { - uiElmSize = BBE_LEN( elmPtr ); - if( pStack->uiCurElm + BBE_LEM_LEN < pStack->uiBlkEnd ) + if (pStack->uiBlkType == BHT_LEAF) + { + uiElmSize = BBE_LEN( elmPtr); + if (pStack->uiCurElm + BBE_LEM_LEN < pStack->uiBlkEnd) { - if( (pStack->uiCurElm += uiElmSize) + BBE_LEM_LEN < pStack->uiBlkEnd) + if ((pStack->uiCurElm += uiElmSize) + BBE_LEM_LEN < pStack->uiBlkEnd) + { rc = FERR_OK; + } } } else { - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) - uiElmSize = BNE_DATA_OVHD; - else - uiElmSize = (FLMUINT) BNE_LEN( pStack, elmPtr); /* Adds in DOMAIN if present */ - - if( pStack->uiCurElm < pStack->uiBlkEnd) + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) { - /* Check if this is not the last element within the block */ - if( (pStack->uiCurElm += uiElmSize) < pStack->uiBlkEnd) + uiElmSize = BNE_DATA_OVHD; + } + else + { + uiElmSize = (FLMUINT) BNE_LEN( pStack, elmPtr); + } + + if (pStack->uiCurElm < pStack->uiBlkEnd) + { + + // Check if this is not the last element within the block + + if ((pStack->uiCurElm += uiElmSize) < pStack->uiBlkEnd) + { rc = FERR_OK; + } } } - return( rc ); + + return (rc); } -/*************************************************************************** -Desc: Go to the next element in the logical b-tree while building the key -Notes: You may be at any level of the b-tree! -*****************************************************************************/ +/**************************************************************************** +Desc: Go to the next element in the logical b-tree while building the key +****************************************************************************/ RCODE FSBtNextElm( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p pStack) /* Stack of variables for each level */ + FDB * pDb, + LFILE * pLFile, + BTSK * pStack) { - RCODE rc = FERR_OK; /* Return code */ + RCODE rc = FERR_OK; - if( pStack->uiCurElm < BH_OVHD ) /* Before first element in block? */ + if (pStack->uiCurElm < BH_OVHD) { pStack->uiCurElm = BH_OVHD; } - else if( (rc = FSBlkNextElm( pStack)) == FERR_BT_END_OF_DATA) + else if ((rc = FSBlkNextElm( pStack)) == FERR_BT_END_OF_DATA) { - FLMBYTE * pBlk = BLK_ELM_ADDR( pStack, BH_NEXT_BLK ); - FLMUINT blkNum = FB2UD( pBlk ); - if( blkNum != BT_END ) /* If not end, read in the next block */ + FLMBYTE * pBlk = BLK_ELM_ADDR( pStack, BH_NEXT_BLK); + FLMUINT blkNum = FB2UD( pBlk); + + if (blkNum != BT_END) { - /* Current element was last element in the block - goto next block */ - - if( RC_OK(rc = FSGetBlock( pDb, pLFile, blkNum, pStack ))) + + // Current element was last element in the block - go to next + // block + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, blkNum, pStack))) { - /* Set blk end and adjust parent block to next element */ + + // Set blk end and adjust parent block to next element + pBlk = pStack->pBlk; - pStack->uiBlkEnd = (FLMUINT)FB2UW( &pBlk[ BH_ELM_END ]); + pStack->uiBlkEnd = (FLMUINT) FB2UW( &pBlk[BH_ELM_END]); pStack->uiCurElm = BH_OVHD; pStack->uiPKC = 0; pStack->uiPrevElmPKC = 0; - if( pStack->uiFlags & FULL_STACK) /* Adjust the stack if needed */ + if (pStack->uiFlags & FULL_STACK) + { rc = FSAdjustStack( pDb, pLFile, pStack, TRUE); + } } } - } /* At this point if rc == FERR_BT_END_OF_DATA then is at last block, else OK */ + } - if( RC_OK(rc)) /* If there is a next element, setup stack and byKeyBuf[] */ + if (RC_OK( rc)) { - FLMBYTE * pCurElm = CURRENT_ELM( pStack ); + FLMBYTE * pCurElm = CURRENT_ELM( pStack); FLMUINT uiKeyLen; - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) { flmCopyDrnKey( pStack->pKeyBuf, pCurElm); goto Exit; } - /* Copy key to the stack->pKeyBuf & check for end key */ - if( (uiKeyLen = BBE_GET_KL( pCurElm)) != 0) + // Copy key to the stack->pKeyBuf & check for end key + + if ((uiKeyLen = BBE_GET_KL( pCurElm)) != 0) { - FLMUINT uiPKC = (FLMUINT)(BBE_GET_PKC( pCurElm )); - - if( uiKeyLen + uiPKC <= pStack->uiKeyBufSize ) + FLMUINT uiPKC = (FLMUINT) (BBE_GET_PKC( pCurElm)); + + if (uiKeyLen + uiPKC <= pStack->uiKeyBufSize) { pStack->uiKeyLen = (uiKeyLen + uiPKC); - f_memcpy( &pStack->pKeyBuf[ uiPKC], - &pCurElm[ pStack->uiElmOvhd ], uiKeyLen); + f_memcpy( &pStack->pKeyBuf[uiPKC], &pCurElm[pStack->uiElmOvhd], + uiKeyLen); } else { @@ -1013,125 +1081,116 @@ RCODE FSBtNextElm( } } } -Exit: - return( rc ); + +Exit: + + return (rc); } -/*************************************************************************** -Desc: Adjust a full stack if pStack->byFlags & FULL_STACK - If the stack->byFlags is set to FULL_STACK then the parent must - point to the next element when changing to the next block in order - for FSBtInsert() or FSBtDelete() to work correctly during block - splits. -*****************************************************************************/ +/**************************************************************************** +Desc: Adjust a full stack +****************************************************************************/ RCODE FSAdjustStack( - FDB_p pDb, - LFILE * pLFile, /* Logical file definition */ - BTSK_p pStack, /* Stack of variables for each level */ - FLMBOOL bMovedNext) + FDB * pDb, + LFILE * pLFile, + BTSK * pStack, + FLMBOOL bMovedNext) { - RCODE rc = FERR_OK; + RCODE rc = FERR_OK; pStack->uiFlags = FULL_STACK; - /**--------------------------------------------------------------------- - *** Pop the stack and go to the next element - *** This is a recursive call back to FSBtNextElm() or FSBtPrevElm() - *** Watch out, this will not work if the concurrency model changes - *** to a b-tree locking method like other products use. - ***--------------------------------------------------------------------*/ - - /* Pop the pStack going to the parents block */ + // Pop the stack and go to the next element This is a recursive call + // back to FSBtNextElm() or FSBtPrevElm() Watch out, this will not work + // if the concurrency model changes to a b-tree locking method like + // other products use. + // + // Pop the pStack going to the parents block + pStack--; - /* It is very rare that block will need to be read. Maybe - some sort of split case. The block should have already have been - read. - */ - - if( RC_OK(rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + // It is very rare that block will need to be read. Maybe some sort of + // split case. The block should have already have been read. + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) { - rc = bMovedNext - ? FSBtNextElm( pDb, pLFile, pStack) /* Next element */ - : FSBtPrevElm( pDb, pLFile, pStack); /* Previous element */ + rc = bMovedNext + ? FSBtNextElm( pDb, pLFile, pStack) + : FSBtPrevElm( pDb, pLFile, pStack); } - /* Push the pStack and unpin the current block */ - pStack++; + // Push the pStack and unpin the current block - return( rc ); + pStack++; + return (rc); } -/*************************************************************************** -Desc: Read in a block from the cache and set most stack elements. -*****************************************************************************/ - +/**************************************************************************** +Desc: Read in a block from the cache and set most stack elements. +****************************************************************************/ RCODE FSGetBlock( - FDB_p pDb, - LFILE * pLFile, // Logical file definition - FLMUINT uiBlkAddr, // Block Address to read. - BTSK_p pStack) // Stack of variables for each level + FDB * pDb, + LFILE * pLFile, + FLMUINT uiBlkAddr, + BTSK * pStack) { RCODE rc = FERR_OK; FLMBYTE * pBlk; - /* - Release whatever block might be there first. If no block is - there (pStack->pSCache == NULL), FSReleaseBlock does nothing. Stacks - are ALWAYS initialized to set pSCache to NULL, so this is OK to call - even if stack has never been used to read a block yet. - */ + // Release whatever block might be there first. If no block is there + // (pStack->pSCache == NULL), FSReleaseBlock does nothing. Stacks are + // ALWAYS initialized to set pSCache to NULL, so this is OK to call + // even if stack has never been used to read a block yet. - if( pStack->pSCache) + if (pStack->pSCache) { - /* If we already have the block we want, keep it! */ - if( pStack->pSCache->uiBlkAddress != uiBlkAddr) + // If we already have the block we want, keep it! + + if (pStack->pSCache->uiBlkAddress != uiBlkAddr) { FSReleaseBlock( pStack, FALSE); } } - if( !pStack->pSCache) + if (!pStack->pSCache) { flmAssert( !pStack->pBlk); - if( RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, - uiBlkAddr, NULL, &pStack->pSCache))) + if (RC_BAD( rc = ScaGetBlock( pDb, pLFile, BHT_LEAF, uiBlkAddr, NULL, + &pStack->pSCache))) { goto Exit; } } pStack->pBlk = pBlk = pStack->pSCache->pucBlk; - if( pStack->uiBlkAddr != uiBlkAddr) + if (pStack->uiBlkAddr != uiBlkAddr) { FLMUINT uiBlkType; pStack->uiBlkAddr = uiBlkAddr; - // set other pStack elements. + // Set other pStack elements. - pStack->uiBlkType = uiBlkType = (FLMUINT)(BH_GET_TYPE( pBlk )); + pStack->uiBlkType = uiBlkType = (FLMUINT) (BH_GET_TYPE( pBlk)); - /** - *** The standard overhead is used in the stack - *** Compares are made to determine if the element is extended. - **/ + // The standard overhead is used in the stack Compares are made to + // determine if the element is extended. - if( uiBlkType == BHT_LEAF) + if (uiBlkType == BHT_LEAF) { pStack->uiElmOvhd = BBE_KEY; } - else if( uiBlkType == BHT_NON_LEAF_DATA) + else if (uiBlkType == BHT_NON_LEAF_DATA) { pStack->uiElmOvhd = BNE_DATA_OVHD; } - else if( uiBlkType == BHT_NON_LEAF) + else if (uiBlkType == BHT_NON_LEAF) { pStack->uiElmOvhd = BNE_KEY_START; } - else if( uiBlkType == BHT_NON_LEAF_COUNTS) + else if (uiBlkType == BHT_NON_LEAF_COUNTS) { pStack->uiElmOvhd = BNE_KEY_COUNTS_START; } @@ -1143,46 +1202,48 @@ RCODE FSGetBlock( } pStack->uiKeyLen = pStack->uiPKC = pStack->uiPrevElmPKC = 0; - pStack->uiLevel = (FLMUINT)pBlk[ BH_LEVEL ]; + pStack->uiLevel = (FLMUINT) pBlk[BH_LEVEL]; pStack->uiCurElm = BH_OVHD; } - pStack->uiBlkEnd = (FLMUINT)FB2UW( &pBlk[ BH_ELM_END ] ); + + pStack->uiBlkEnd = (FLMUINT) FB2UW( &pBlk[BH_ELM_END]); Exit: - - return( rc ); + + return (rc); } -/*************************************************************************** -Desc: Release all of the cache associated with a stack. -***************************************************************************/ +/**************************************************************************** +Desc: Release all of the cache associated with a stack. +****************************************************************************/ void FSReleaseStackCache( - BTSK_p pStack, + BTSK * pStack, FLMUINT uiNumLevels, FLMBOOL bMutexAlreadyLocked) { - FLMBOOL bSemLocked = FALSE; + FLMBOOL bMutexLocked = FALSE; - while( uiNumLevels) + while (uiNumLevels) { - if( pStack->pSCache) + if (pStack->pSCache) { - if( !bSemLocked && !bMutexAlreadyLocked) + if (!bMutexLocked && !bMutexAlreadyLocked) { f_mutexLock( gv_FlmSysData.hShareMutex); - bSemLocked = TRUE; + bMutexLocked = TRUE; } + ScaReleaseCache( pStack->pSCache, TRUE); pStack->pSCache = NULL; pStack->pBlk = NULL; } + uiNumLevels--; pStack++; } - if( bSemLocked) + + if (bMutexLocked) { f_mutexUnlock( gv_FlmSysData.hShareMutex); } } - - diff --git a/flaim/src/fssplblk.cpp b/flaim/src/fssplblk.cpp index 4e933db..0abfe69 100644 --- a/flaim/src/fssplblk.cpp +++ b/flaim/src/fssplblk.cpp @@ -1,945 +1,910 @@ -//------------------------------------------------------------------------- -// Desc: B-tree block splitting. -// Tabs: 3 -// -// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fssplblk.cpp 12289 2006-01-19 14:56:21 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE FSBtResetStack( - FDB * pDb, - LFILE * pLFile, - BTSK_p * ppStack, - FLMBYTE * pElement, - FLMUINT uiElmLen); - -FSTATIC RCODE FSMoveToNextBlk( - FDB * pDb, - LFILE * pLFile, - BTSK_p * ppStack, - FLMUINT nextBlkNum, - FLMBYTE * pElement, - FLMUINT elmLen, - FLMUINT uiBlockSize, - FLMUINT * blkNumRV, - FLMUINT * curElmRV); - -/*************************************************************************** -Desc: Split a block using different algorithms depending on context -Out: ppStack points to current pStack element -Return: RCODE - 0=OK or error code. -Notes: goto's are added to insure proper cleanup and to help maintain flow. -*****************************************************************************/ -RCODE FSBlkSplit( - FDB * pDb, - LFILE * pLFile, - BTSK_p * ppStack, - FLMBYTE * pElement, - FLMUINT elmLen) -{ - RCODE rc = FERR_OK; - FLMUINT uiBlockSize = pDb->pFile->FileHdr.uiBlockSize; - BTSK_p pStack = *ppStack; - FLMUINT oldCurElm = pStack->uiCurElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMUINT tempWord; - FLMUINT elmKeyLen; - FLMUINT prevKeyCnt; - FLMUINT curElm; - FLMBYTE * curElmPtr; - FLMBYTE * pBlk; - FLMUINT blkNum = pStack->uiBlkAddr; - FLMUINT uiBlkEnd; - BTSK newBlkStk; - BTSK nextBlkStk; - FLMBYTE * newBlkPtr; - FLMBYTE * nextBlkPtr; - FLMUINT newBlkNum; - FLMUINT nextBlkNum; - FLMUINT blkNumRestore = 0; - FLMUINT curElmRestore = 0; - FLMBOOL bNewRootFlag; - FLMBOOL bDoubleSplit; - DB_STATS * pDbStats; - - f_yieldCPU(); - bNewRootFlag = bDoubleSplit = FALSE; - FSInitStackCache( &newBlkStk, 1); - FSInitStackCache( &nextBlkStk, 1); - - if( (pDbStats = pDb->pDbStats) != NULL) - { - LFILE_STATS * pLFileStats; - - if( (pLFileStats = fdbGetLFileStatPtr( pDb, pLFile)) != NULL) - { - pLFileStats->bHaveStats = - pDbStats->bHaveStats = TRUE; - pLFileStats->ui64BlockSplits++; - } - } - - /*************************************************************************** - *** Algorithm designed Dec 30, 1991 - Implemented July 21, 1992 - *** Algorithm too difficult to implement when designed. Implemented to save - *** disk space, improve speed and reduce code by using shared routines. - *** - *** If there is room to move data to the next block then do it - *** and update the parent block with the new last element. Otherwise... - *** Divide data from current block and next block into the new block - *** (2/3 split). Delete parent element and update parent /w 2 elements. - *** - *************************************************************************** - *** - *** SPLIT THE BLOCK - old code before July 21, 1992 - *** - *** Allocate a new block, find the split point the divide the data - *** between the two blocks. Build a new non-leaf element to insert into - *** the parent block. Check for root splits and then recursively call - *** FSBtInsert() in insert the created non-leaf element. - *** - ***************************************************************************/ - - // Reset the stack if not a FULL_STACK, fast data inserts use NO_STACK - if( pStack->uiFlags & NO_STACK ) - { - if( RC_BAD( rc = FSBtResetStack( pDb, pLFile, &pStack, pElement, elmLen))) - { - goto Exit; - } - } - - // Log the block before modifying it - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack ))) - { - goto Exit; - } - - pBlk = pStack->pBlk; - bNewRootFlag = BH_IS_ROOT_BLK(pBlk); - - if( (nextBlkNum = FB2UD( &pBlk[ BH_NEXT_BLK ])) != BT_END) - { - /**----------------------------------------------------------------- - *** Try to move the elements from the current block to - *** the next block while inserting the element. If this - *** succeeds than we are better off than spliting blocks. - *** If succeeds then all block operations have been taken care of. - ***----------------------------------------------------------------*/ - - if( RC_OK( rc = FSMoveToNextBlk( pDb, pLFile, &pStack, nextBlkNum, - pElement, elmLen, uiBlockSize, - &blkNumRestore, &curElmRestore))) - { - goto FSBlkSplit_position; - } - - if( rc != FERR_BLOCK_FULL) - { - goto Exit; - } - } - /**----------------------------------------------------------------- - *** Initialize variables, create a new block and setup header. - *** This is common stuff that will be done if you are - *** splitting a RIGHT-MOST block or a middle block. - *** Remember we could be working with leaf or non-leaf blks. - ***----------------------------------------------------------------*/ - - if( RC_BAD( rc = ScaCreateBlock( pDb, pLFile, &newBlkStk.pSCache ))) - { - goto Exit; - } - - newBlkStk.pBlk = newBlkStk.pSCache->pucBlk; - - newBlkPtr = GET_CABLKPTR( &newBlkStk); - newBlkNum = GET_BH_ADDR( newBlkPtr ); - pBlk = pStack->pBlk; - uiBlkEnd = pStack->uiBlkEnd; - UD2FBA( nextBlkNum, &newBlkPtr[ BH_NEXT_BLK ]); - UD2FBA( blkNum, &newBlkPtr[ BH_PREV_BLK ]); - UD2FBA( newBlkNum, &pBlk[ BH_NEXT_BLK ]); - - /* - Write over the root bit if present as set type. - VISIT: Converting from 2x to 3x this is a good time to - convert all elements to 3x non-leaf element format. - */ - newBlkPtr[ BH_TYPE ] = pBlk[ BH_TYPE ] = (FLMBYTE)(BH_GET_TYPE( pBlk )); - newBlkPtr[ BH_LEVEL ] = pBlk[ BH_LEVEL ]; - tempWord = FB2UW( &pBlk[ BH_LOG_FILE_NUM ]); - UW2FBA( tempWord, &newBlkPtr[ BH_LOG_FILE_NUM ]); - UW2FBA( BH_OVHD, &newBlkPtr[ BH_BLK_END ]); - /**---------------------------------------------------------------------- - *** In both cases (middle or end split) if you split at the wrong - *** place you will still not be able to fit the element[] in the block. - *** The while loop will insure at least a split into two blocks where - *** there may not be room to move any elements from the next block. - *** NOTE: the max element may reach 793 bytes (640=Key,150=references). - *** Exception: - *** For 1K blocks, you may insert in the middle where the next (is last) - *** element + elmLen > uiBlockSize AND oldCurElm + elmLen > uiBlockSize. - *** In this case you must do double block split by inserting the element - *** at the bottom of this routine after all splitting has been done. - ***---------------------------------------------------------------------*/ - - pStack->uiCurElm = (nextBlkNum == BT_END) - ? (FFILE_MAX_FILL * - pDb->pFile->FileHdr.uiBlockSize / 100) - : ((uiBlockSize / 20) * 13); /* Leave at least 65% full */ - - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0))) - { - goto Exit; - } - - if( pStack->uiCmpStatus == BT_GT_KEY ) /* scanTo didn't move current elm's key */ - { - /* Save the key in the pKeyBuf */ - curElmPtr = &pBlk[ pStack->uiCurElm ]; - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) - { - flmCopyDrnKey( pStack->pKeyBuf, curElmPtr); - } - else - { - elmKeyLen = (FLMUINT)(BBE_GET_KL( curElmPtr )); - if( elmKeyLen) /* Copy key into pKeyBuf */ - { - prevKeyCnt = (FLMUINT)(BBE_GET_PKC( curElmPtr )); - f_memcpy( &pStack->pKeyBuf[ prevKeyCnt ], - &curElmPtr[ uiElmOvhd ], elmKeyLen ); - } - } - } /* pStack->wCurElm is always > BH_OVHD */ - - curElm = pStack->uiCurElm; - - /**------------------------------------------------------------------- - *** Check to see if the new element will fit whereever it goes. - *** Don't try to optimally place it because the next block may move - *** stuff over. curElm may be at BLK_END value or BLK_END-uiElmOvhd - *** 08/12/96 - Bug found moving the LEM only to the new block. - *** This happened on a large data element with PKC of 2 where the - *** split moved ONLY the LEM (last element marker). - *** Real special case where we have not dupped with stopmer or TST. - *** Here are the specs... - - In Insert Element the insert failed on... - if( wBlkEnd + uiElmOvhd + insertLen > uiBlockSize) - - and so this block split routine is called. - - so the original code... - while( (curElm > oldCurElm ) && (curElm + elmLen + uiElmOvhd > uiBlockSize )) - - works find except on a worst case split. - - Given that: - curElm + uiElmOvhd == wBlkEnd - and elmLen = insertLen + PCKLen - - Substitue the variables for the worst case split and we get... - while( ... (wBlkEnd + insertLen + PCKLen > uiBlockSize) - - This resulted in a FALSE condition for our worst case split. - Solving the two equations for two false conditions results in: - PCKLen < uiElmOvhd - - Original code before 08/12/96... - while( (curElm > oldCurElm ) && (curElm + elmLen + uiElmOvhd > uiBlockSize )) - ***------------------------------------------------------------------*/ - - while( (curElm > oldCurElm ) - && (curElm + elmLen + uiElmOvhd + uiElmOvhd > uiBlockSize )) - { - FSBtPrevElm( pDb, pLFile, pStack ); - curElm = pStack->uiCurElm; - } - - newBlkStk.uiBlkAddr = newBlkNum; - newBlkStk.pKeyBuf = pStack->pKeyBuf; - FSBlkToStack( &newBlkStk ); /* Setup block pointers & values */ - newBlkStk.uiKeyBufSize = pStack->uiKeyBufSize; - - curElmPtr = &pBlk[ curElm ]; /* Point to split point */ - - if( curElm == oldCurElm ) /* Decide which block to put newElm */ - { - /* Decide whether to place the new element in the current or new block */ - /* Give preference to placing with the current block - fills better */ - if( (curElm + elmLen + uiElmOvhd < uiBlockSize ) - && ((uiBlkEnd - curElm) > uiElmOvhd)) - goto Addto_Current_Blk; /* Place with the current block */ - - if( uiBlkEnd > curElm) /* Move if not at end of block */ - FSBlkMoveElms( &newBlkStk, curElmPtr, - (FLMUINT)(uiBlkEnd - curElm), pStack->pKeyBuf); - - /* Set the block end in the current blocks header & restore values */ - pStack->uiBlkEnd = curElm; - UW2FBA( curElm, &pBlk[ BH_BLK_END ]); - blkNumRestore = newBlkNum; - curElmRestore = BH_OVHD; /* Setup to insert element*/ - newBlkStk.uiCurElm = curElmRestore; - - if( newBlkStk.uiBlkEnd + elmLen + uiElmOvhd > uiBlockSize) - { - bDoubleSplit = 1; /* Double split - move element later */ - } - else - { - FSBlkMoveElms( &newBlkStk, pElement, elmLen, NULL ); - } - } - - else if( curElm > oldCurElm ) /* Place new element in current blk */ - { -Addto_Current_Blk: - /* First move stuff over to the new blk */ - FSBlkMoveElms( &newBlkStk, curElmPtr, - (FLMUINT)(uiBlkEnd - curElm), pStack->pKeyBuf); - - /* Set the block end in the current blocks header */ - pStack->uiBlkEnd = curElm; - UW2FBA( curElm, &pBlk[ BH_BLK_END ]); - blkNumRestore = blkNum; - curElmRestore = oldCurElm; /* Setup to insert element*/ - pStack->uiCurElm = curElmRestore; - FSBlkMoveElms( pStack, pElement, elmLen, NULL ); - } - else if( curElm < oldCurElm) /* Place new element in new block */ - { - blkNumRestore = newBlkNum; /* Don't mess with the order! */ - FSBlkMoveElms( &newBlkStk, curElmPtr, - (FLMUINT)(oldCurElm-curElm), pStack->pKeyBuf); - newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; - curElmRestore = newBlkStk.uiCurElm; - - // May not fit with 1K blocks - check for double split - - if( curElmRestore + elmLen + (uiBlkEnd - oldCurElm) + uiElmOvhd > uiBlockSize) - { - bDoubleSplit = 1; - } - else - { - FSBlkMoveElms( &newBlkStk, pElement, elmLen, NULL ); - } - - newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; - pStack->uiCurElm = oldCurElm; /* Position for scanTo */ - - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0))) - { - goto Exit; - } - - // GWBUG (8/98) Check if oldCurElm < uiBlkEnd - - if( oldCurElm < uiBlkEnd) - { - FSBlkMoveElms( &newBlkStk, &pBlk[oldCurElm], - (FLMUINT)(uiBlkEnd - oldCurElm), - pStack->pKeyBuf ); - } - - // Set the block end in the current blocks header - - pStack->uiBlkEnd = curElm; - UW2FBA( curElm, &pBlk[ BH_BLK_END ]); - } - - // All done with the current block - unpin and set to dirty - - /**------------------------------------------------------------- - *** All done moving data from current block to new block. - *** if created new right most block - *** check if new to create new root block and init new root (easy) - *** else - *** try to move stuff from the next block into the new block - ***------------------------------------------------------------*/ - - if( nextBlkNum == BT_END ) - { - FLMUINT uiLfNum = pLFile->uiLfNum; - - // We are done with block - - FSReleaseBlock( &newBlkStk, FALSE); - - // At the root? - - if( bNewRootFlag) - { - FLMBYTE byType; - - /**-------------------------------------------------------------------- - *** Create a new root block - *** Hitting 6 levels at 11.5 keys per block would be 2,000,000 blocks - ***-------------------------------------------------------------------*/ - - if( pStack->uiLevel + 1 >= BH_MAX_LEVELS) - { - rc = RC_SET( FERR_BTREE_FULL); - goto Exit; - } - - // Set the default block type from what the type of the current root - // or use the database version to decide. - - if( pLFile->uiLfType == LF_INDEX) - { - if( pLFile->pIxd->uiFlags & IXD_POSITIONING) - byType = BHT_NON_LEAF_COUNTS + BHT_ROOT_BLK; - else - byType = BHT_NON_LEAF + BHT_ROOT_BLK; - } - else - byType = BHT_NON_LEAF_DATA + BHT_ROOT_BLK; - - // Move all pStack elements down by doing a shift - - shiftN( (FLMBYTE *) pStack, - (FLMUINT)(sizeof(BTSK) * (pStack->uiLevel+1)), - (FLMINT)sizeof(BTSK)); - - // Create a new block - - if( RC_BAD( rc = ScaCreateBlock( pDb, pLFile, &pStack->pSCache))) - { - goto Exit; - } - - pBlk = pStack->pBlk = pStack->pSCache->pucBlk; - - // Set prev/next block addresses to BT_END - - UD2FBA( BT_END, &pBlk[ BH_PREV_BLK ]); - UD2FBA( BT_END, &pBlk[ BH_NEXT_BLK ]); - UW2FBA( BH_OVHD, &pBlk[ BH_BLK_END ]); - - // Set logical file number in the block header and block type - - UW2FBA( uiLfNum, &pBlk[ BH_LOG_FILE_NUM ]); - - pBlk[ BH_TYPE ] = byType; - pBlk[ BH_LEVEL ] = (FLMBYTE)(++(pStack->uiLevel)); - pStack->uiBlkAddr = GET_BH_ADDR( pBlk ); - FSBlkToStack( pStack); - pLFile->uiRootBlk = pStack->uiBlkAddr; - - // Always update the pLFile because level is incremented - - rc = flmLFileWrite( pDb, pLFile); - pStack++; - *ppStack = pStack; - - if( RC_BAD( rc)) - { - goto Exit; - } - } - } - else /* move stuff from the right block */ - { /* Remember that newBlk is still pinned */ - FLMINT iBytesToMove; /* 03/20/96 - made a signed value. */ - - nextBlkStk.pKeyBuf = pStack->pKeyBuf; - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, nextBlkNum, &nextBlkStk))) - { - goto Exit; - } - - if( RC_BAD( rc = FSLogPhysBlk( pDb, &nextBlkStk))) - { - goto Exit; - } - - nextBlkStk.uiKeyBufSize = pStack->uiKeyBufSize; - nextBlkPtr = nextBlkStk.pBlk; - UD2FBA( newBlkNum, &nextBlkPtr[ BH_PREV_BLK ]); /* UPDATE PREV_BLK */ - - // Try to move so that the two blocks have about the same free space - - iBytesToMove = (FLMINT) ((nextBlkStk.uiBlkEnd - newBlkStk.uiBlkEnd) / 2); - - if( iBytesToMove > 100) /* Don't even bother if neg or <100 */ - { - // Log the block before modifying it. Moved 03/20/96 from 5 above.*/ - - nextBlkStk.uiCurElm = iBytesToMove + BH_OVHD; - if( RC_BAD( rc = FSBtScanTo( &nextBlkStk, NULL, 0, 0))) - { - goto Exit; - } - - while( (nextBlkStk.uiCurElm > BH_OVHD) && - (nextBlkStk.uiCurElm + newBlkStk.uiBlkEnd + - uiElmOvhd - BH_OVHD >= uiBlockSize)) - { - (void)FSBtPrevElm( pDb, pLFile, &nextBlkStk ); - } - - /* GWUG 23654: - ** Never try to move elements from the next block to the - ** new block if we are positioned on the first element. - ** Added 9/10/96. - */ - - // Never try to move if on LEM or at the end - - if( (nextBlkStk.uiCurElm > BH_OVHD) && - (nextBlkStk.uiCurElm + uiElmOvhd < nextBlkStk.uiBlkEnd)) - { - FLMUINT tempEnd; - - /* 03/20/96 removed..if( rc == BT_GT_KEY ) */ - /* Always make sure the key is in the buffer. */ - /* Save the key in the pKeyBuf */ - - curElmPtr = &nextBlkPtr[ nextBlkStk.uiCurElm ]; - if( pStack->uiBlkType != BHT_NON_LEAF_DATA) - { - elmKeyLen = (FLMUINT)(BBE_GET_KL( curElmPtr )); - if( elmKeyLen) /* Copy key into pKeyBuf */ - { - prevKeyCnt = (FLMUINT)(BBE_GET_PKC( curElmPtr )); - f_memcpy( &(nextBlkStk.pKeyBuf)[ prevKeyCnt ], - &curElmPtr[ uiElmOvhd ], elmKeyLen ); - } - } - - // Out 9/10/96 - Check is above. - // if( nextBlkStk.wCurElm + uiElmOvhd < nextBlkStk.wBlkEnd) - - tempWord = nextBlkStk.uiCurElm; - newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; /* Be sure to position */ - - FSBlkMoveElms( &newBlkStk, &nextBlkPtr[ BH_OVHD ], - (FLMUINT)(tempWord - BH_OVHD), NULL ); - - // Move the elements in the next block DOWN expanding PKC - - tempEnd = nextBlkStk.uiBlkEnd; - - // Make sure uiBlkEnd is reality or move will not work! - - nextBlkStk.uiBlkEnd = nextBlkStk.uiCurElm = BH_OVHD; - UW2FBA( BH_OVHD, &nextBlkPtr[ BH_BLK_END]); /* Not really needed*/ - - FSBlkMoveElms( &nextBlkStk, &nextBlkPtr[ tempWord ], - (FLMUINT)(tempEnd - tempWord), - nextBlkStk.pKeyBuf); - - if( (pStack-1)->uiBlkType == BHT_NON_LEAF_COUNTS) - { - if( RC_BAD( rc = FSUpdateAdjacentBlkCounts( pDb, pLFile, - pStack, &nextBlkStk))) - { - goto Exit; - } - } - } - } - - FSReleaseBlock( &newBlkStk, FALSE); - } - - /**-------------------------------------------------------------------- - *** Insert the new last element in the current block replacing what - *** is there. Insert the last element from the new block. - *** - *** All blocks should be dirty and unpined! This means we have to read - *** them in again. - ***-------------------------------------------------------------------*/ - - if( RC_BAD(rc = FSGetBlock( pDb, pLFile, blkNum, pStack))) - { - goto Exit; - } - - if( pStack->uiCurElm >= pStack->uiBlkEnd) - { - pStack->uiCurElm = curElm; - } - - // Passing 0 means insert only. - - if( RC_BAD( rc = FSNewLastBlkElm( pDb, pLFile, &pStack, - (nextBlkNum == BT_END ) ? 0: FSNLBE_LESS ))) - { - *ppStack = pStack; - goto Exit; - } - - if( RC_BAD( rc = FSAdjustStack( pDb, pLFile, pStack, TRUE))) - { - if( rc != FERR_BT_END_OF_DATA ) - { - goto Exit; - } - } - - // Parent is positioned to the nextBlk element. - - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, newBlkNum, pStack))) - { - goto Exit; - } - - if( (nextBlkNum == BT_END) && !bNewRootFlag) - { - FLMUINT uiNewRefCount; - FLMUINT uiOldRefCount; - FLMBYTE * pTmpElement; - - // Only update the counts if the inserting a key and not replacing. - - if( (pStack-1)->uiBlkType == BHT_NON_LEAF_COUNTS) - { - if( RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, - pStack->uiBlkEnd, NULL, NULL, &uiNewRefCount))) - { - goto Exit; - } - } - - pStack--; - - // Modify the parent last element marker (LEM) to point to - // the new last block. THEN delete the previous element that - // also pointer to the new last block. - - // Read the parent block - - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) - { - return( rc ); - } - - if( RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) - { - return( rc ); - } - - // Change where element points to in the last element marker (LEM) - - pTmpElement = pStack->pBlk + pStack->uiCurElm; - FSSetChildBlkAddr( pTmpElement, newBlkNum, pStack->uiElmOvhd); - - if( pStack->uiBlkType == BHT_NON_LEAF_COUNTS) - { - uiOldRefCount = FB2UD( &pTmpElement[ BNE_CHILD_COUNT]); - if( RC_BAD( rc = FSChangeBlkCounts( pDb, pStack, - (FLMINT) (uiNewRefCount - uiOldRefCount)))) - { - goto Exit; - } - UD2FBA( uiNewRefCount, &pTmpElement[ BNE_CHILD_COUNT]); - } - pStack++; - } - else - { - // Inserts the new element into the tree. - rc = FSNewLastBlkElm( pDb, pLFile, &pStack, 0); - } - -FSBlkSplit_position: - - *ppStack = pStack; - - // Read in block - should be positioned to the current element inserted - - if( RC_OK(rc)) - { - // Parent element is on the newBlock - see if you need to back up - - if( blkNumRestore == blkNum ) - { - if( RC_BAD( rc = FSAdjustStack( pDb, pLFile, pStack, FALSE))) - { - if( rc != FERR_BT_END_OF_DATA) - { - goto Exit; - } - } - } - - if( RC_OK( rc = FSGetBlock( pDb, pLFile, blkNumRestore, pStack))) - { - // Set up the key buffer (pKeyBuf) to be correct for future inserts - - pStack->uiCurElm = curElmRestore; - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0))) - { - goto Exit; - } - - if( bDoubleSplit) - { - // Now insert the element if flag set - // This will cause another split. - // RECURSIVE CALL - - rc = FSBlkSplit( pDb, pLFile, ppStack, pElement, elmLen); - } - } - } - -Exit: - - FSReleaseBlock( &newBlkStk, FALSE); - FSReleaseBlock( &nextBlkStk, FALSE); - - return( rc); -} - -/*************************************************************************** -Desc: Reset the pStack to set up for a block split -Return: Offset into split point in block 1 (pCache) -Out: Offset where to split the block -Notes: Must guarantee at least 1 element in both blocks. -*****************************************************************************/ -FSTATIC RCODE FSBtResetStack( - FDB * pDb, /* Pointer to database DBC structure. */ - LFILE * pLFile, /* Logical file definition */ - BTSK_p * ppStack, /* Stack of variables for each level */ - FLMBYTE * pElement, /* The input element to insert */ - FLMUINT elmLen) /* Length of the element */ -{ - RCODE rc; - BTSK_p pStack = *ppStack; /* Stack holding all state info */ - FLMUINT oldPKC = pStack->uiPKC;/* Save old PKC value */ - FLMUINT oldPvElmPKC = pStack->uiPrevElmPKC;/* Save old prev elm PKC value */ - FLMUINT oldBlock = pStack->uiBlkAddr; /* Save old block number */ - FLMUINT oldCurElm = pStack->uiCurElm;/* Save old current element value */ - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - - if( RC_BAD(rc = FSBtSearch( pDb, pLFile, - &pStack,&pElement[uiElmOvhd], - (elmLen-uiElmOvhd),0))) - return( rc ); - - /* In case of continuation elements, parse to matching curElm */ - while( (oldBlock != pStack->uiBlkAddr ) && - (oldCurElm != pStack->uiCurElm )) - { - if( (rc = FSBtNextElm( pDb, pLFile, pStack )) == FERR_BT_END_OF_DATA) - { - return( RC_SET( FERR_BTREE_ERROR) ); - } - else if( RC_BAD( rc)) - { - return( rc); - } - } - - // Reset original PKC values - - pStack->uiPKC = oldPKC; - pStack->uiPrevElmPKC = oldPvElmPKC; - *ppStack = pStack; - pStack->uiFlags = FULL_STACK; - - return( FERR_OK); -} - -/**************************************************************************** -Desc: Try to move elements between two blocks while inserting an element - Set up pStack to point to where element was inserted. -Out: pStack updated to point to current element -Return: RCODE, FERR_OK - OK, FAILURE - cannot move, else error number -Notes: Stack could point to leaf or non-leaf nodes. Parent elements - should point to the next block so caller can fixup parent element. -****************************************************************************/ -FSTATIC RCODE FSMoveToNextBlk( - FDB * pDb, - LFILE * pLFile, - BTSK_p * ppStack, - FLMUINT nextBlkNum, - FLMBYTE * pElement, - FLMUINT elmLen, - FLMUINT uiBlockSize, - FLMUINT * blkNumRV, - FLMUINT * curElmRV) -{ - RCODE rc = FERR_OK; - BTSK_p pStack = *ppStack; - FLMUINT uiBlkEnd = pStack->uiBlkEnd; - FLMUINT oldCurElm = pStack->uiCurElm; // Original current element value - FLMBYTE * curElmPtr; - BTSK nextBlkStk; // Used for the move element routine - FLMUINT nextBlkFreeBytes; - FLMUINT elmKeyLen; - FLMUINT prevKeyCnt; - FLMUINT curElm; - FLMUINT uiElmOvhd = pStack->uiElmOvhd; - FLMBOOL bInsertInCurrentBlock; - FLMBYTE * pBlk = pStack->pBlk; - - FSInitStackCache( &nextBlkStk, 1); - nextBlkStk.pKeyBuf = pStack->pKeyBuf; - - if( RC_BAD( rc = FSGetBlock( pDb, pLFile, nextBlkNum, &nextBlkStk))) - { - goto Exit; - } - - nextBlkFreeBytes = (FLMUINT)(uiBlockSize - nextBlkStk.uiBlkEnd - uiElmOvhd); - pStack->uiCurElm = (uiBlkEnd - (nextBlkFreeBytes / 2)); - - if( RC_BAD(rc = FSBtScanTo( pStack, NULL, 0, 0))) - { - goto Exit; - } - - rc = (pStack->uiCmpStatus == BT_END_OF_DATA) ? FERR_BT_END_OF_DATA : FERR_OK; - - for( ; RC_OK(rc); rc = FSBlkNextElm( pStack)) - { - // The current element is positioned to mininum split point. - // Keep testing till at end of block or split will fit - // within both blocks while still adding the element to insert. - - // Save the key in the pKeyBuf so can move entire element - - curElmPtr = CURRENT_ELM( pStack ); - - if( pStack->uiBlkType == BHT_NON_LEAF_DATA) - { - prevKeyCnt = elmKeyLen = 0; - } - else - { - prevKeyCnt = (FLMUINT)(BBE_GET_PKC( curElmPtr)); - elmKeyLen = (FLMUINT)(BBE_GET_KL( curElmPtr)); - } - - if( elmKeyLen) // Copy key into pKeyBuf. - { - f_memcpy( &pStack->pKeyBuf[ prevKeyCnt ], - &curElmPtr[ uiElmOvhd ], elmKeyLen ); - } - - // Will element be inserted into the current block? - - if( oldCurElm <= (curElm = pStack->uiCurElm)) - { - // Insert the element in the current block - could be at the end - - if( curElm + elmLen + uiElmOvhd > uiBlockSize ) - { - rc = FERR_BT_END_OF_DATA; - break; - } - - // Left fits - try right block - could fail because of pkc value/ - - if( prevKeyCnt + (uiBlkEnd - curElm) >= nextBlkFreeBytes) - { - continue; // Doesn't fit - try again - } - - bInsertInCurrentBlock = TRUE; - } - else - { - // Moving elements from current block so no need to check it - // Cannot remember why I put BBE_PKC_MAX in the line below - - if( elmLen + prevKeyCnt + BBE_PKC_MAX + - (uiBlkEnd - curElm) >= nextBlkFreeBytes) - { - continue; - } - - bInsertInCurrentBlock = FALSE; - } - - if( RC_BAD( rc = FSLogPhysBlk( pDb, &nextBlkStk))) - { - goto Exit; - } - - if( bInsertInCurrentBlock) - { - FSBlkMoveElms( &nextBlkStk, curElmPtr, - (FLMUINT)(uiBlkEnd - curElm), pStack->pKeyBuf); - pStack->uiBlkEnd = curElm; - UW2FBA( curElm, &pBlk[ BH_BLK_END ]); - *curElmRV = oldCurElm; - pStack->uiCurElm = (*curElmRV); - FSBlkMoveElms( pStack, pElement, elmLen, NULL ); - *blkNumRV = pStack->uiBlkAddr; - } - else - { - FSBlkMoveElms( &nextBlkStk, curElmPtr, - (FLMUINT)(uiBlkEnd - curElm), pStack->pKeyBuf); - pStack->uiBlkEnd = curElm; - UW2FBA( curElm, &pBlk[ BH_BLK_END ]); - *curElmRV = (FLMUINT)(BH_OVHD + prevKeyCnt + (oldCurElm - curElm)); - nextBlkStk.uiCurElm = (*curElmRV); - FSBlkMoveElms( &nextBlkStk, pElement, elmLen, NULL ); - *blkNumRV = nextBlkNum; - } - - if( pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) - { - if( RC_BAD( rc = FSUpdateAdjacentBlkCounts( pDb, pLFile, - pStack, &nextBlkStk))) - { - goto Exit; - } - } - - break; - } - - // If cannot move then return - - if( RC_BAD(rc)) - { - if( rc == FERR_BT_END_OF_DATA) - { - // Restore old current element - pStack->uiCurElm = oldCurElm; - rc = RC_SET( FERR_BLOCK_FULL); - } - - goto Exit; - } - - // Fix up the elements in the parent block pointing to the new - // last element in the current block. REMEMBER - pStack may change - // on you! - - rc = FSNewLastBlkElm( pDb, pLFile, ppStack, FSNLBE_LESS | FSNLBE_POSITION); - -Exit: - - FSReleaseBlock( &nextBlkStk, FALSE); - return( rc); -} +//------------------------------------------------------------------------- +// Desc: B-tree block splitting. +// Tabs: 3 +// +// Copyright (c) 1991-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: fssplblk.cpp 12289 2006-01-19 14:56:21 -0700 (Thu, 19 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +FSTATIC RCODE FSBtResetStack( + FDB * pDb, + LFILE * pLFile, + BTSK ** ppStack, + FLMBYTE * pElement, + FLMUINT uiElmLen); + +FSTATIC RCODE FSMoveToNextBlk( + FDB * pDb, + LFILE * pLFile, + BTSK ** ppStack, + FLMUINT nextBlkNum, + FLMBYTE * pElement, + FLMUINT elmLen, + FLMUINT uiBlockSize, + FLMUINT * blkNumRV, + FLMUINT * curElmRV); + +/**************************************************************************** +Desc: Split a block using different algorithms depending on context +****************************************************************************/ +RCODE FSBlkSplit( + FDB * pDb, + LFILE * pLFile, + BTSK ** ppStack, + FLMBYTE * pElement, + FLMUINT elmLen) +{ + RCODE rc = FERR_OK; + FLMUINT uiBlockSize = pDb->pFile->FileHdr.uiBlockSize; + BTSK * pStack = *ppStack; + FLMUINT oldCurElm = pStack->uiCurElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMUINT tempWord; + FLMUINT elmKeyLen; + FLMUINT prevKeyCnt; + FLMUINT curElm; + FLMBYTE * curElmPtr; + FLMBYTE * pBlk; + FLMUINT blkNum = pStack->uiBlkAddr; + FLMUINT uiBlkEnd; + BTSK newBlkStk; + BTSK nextBlkStk; + FLMBYTE * newBlkPtr; + FLMBYTE * nextBlkPtr; + FLMUINT newBlkNum; + FLMUINT nextBlkNum; + FLMUINT blkNumRestore = 0; + FLMUINT curElmRestore = 0; + FLMBOOL bNewRootFlag; + FLMBOOL bDoubleSplit; + DB_STATS * pDbStats; + + bNewRootFlag = FALSE; + bDoubleSplit = FALSE; + + FSInitStackCache( &newBlkStk, 1); + FSInitStackCache( &nextBlkStk, 1); + + if ((pDbStats = pDb->pDbStats) != NULL) + { + LFILE_STATS* pLFileStats; + + if ((pLFileStats = fdbGetLFileStatPtr( pDb, pLFile)) != NULL) + { + pLFileStats->bHaveStats = pDbStats->bHaveStats = TRUE; + pLFileStats->ui64BlockSplits++; + } + } + + // If there is room to move data to the next block then do it + // and update the parent block with the new last element. Otherwise... + // Divide data from current block and next block into the new block + // (2/3 split). Delete parent element and update parent /w 2 elements. + + if (pStack->uiFlags & NO_STACK) + { + if (RC_BAD( rc = FSBtResetStack( pDb, pLFile, &pStack, pElement, elmLen))) + { + goto Exit; + } + } + + // Log the block before modifying it + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + goto Exit; + } + + pBlk = pStack->pBlk; + bNewRootFlag = BH_IS_ROOT_BLK( pBlk); + + if ((nextBlkNum = FB2UD( &pBlk[BH_NEXT_BLK])) != BT_END) + { + + // Try to move the elements from the current block to the next block + // while inserting the element. If this succeeds than we are better + // off than spliting blocks. If succeeds then all block operations + // have been taken care of. + + if (RC_OK( rc = FSMoveToNextBlk( pDb, pLFile, &pStack, nextBlkNum, + pElement, elmLen, uiBlockSize, &blkNumRestore, &curElmRestore))) + { + goto FSBlkSplit_position; + } + + if (rc != FERR_BLOCK_FULL) + { + goto Exit; + } + } + + // Initialize variables, create a new block and setup header. This is + // common stuff that will be done if you are splitting a RIGHT-MOST + // block or a middle block. Remember we could be working with leaf or + // non-leaf blks. + + if (RC_BAD( rc = ScaCreateBlock( pDb, pLFile, &newBlkStk.pSCache))) + { + goto Exit; + } + + newBlkStk.pBlk = newBlkStk.pSCache->pucBlk; + + newBlkPtr = GET_CABLKPTR( &newBlkStk); + newBlkNum = GET_BH_ADDR( newBlkPtr); + + pBlk = pStack->pBlk; + uiBlkEnd = pStack->uiBlkEnd; + + UD2FBA( nextBlkNum, &newBlkPtr[BH_NEXT_BLK]); + UD2FBA( blkNum, &newBlkPtr[BH_PREV_BLK]); + UD2FBA( newBlkNum, &pBlk[BH_NEXT_BLK]); + + // Write over the root bit if present as set type. + + newBlkPtr[BH_TYPE] = pBlk[BH_TYPE] = (FLMBYTE) (BH_GET_TYPE( pBlk)); + newBlkPtr[BH_LEVEL] = pBlk[BH_LEVEL]; + tempWord = FB2UW( &pBlk[BH_LOG_FILE_NUM]); + UW2FBA( tempWord, &newBlkPtr[BH_LOG_FILE_NUM]); + UW2FBA( BH_OVHD, &newBlkPtr[BH_BLK_END]); + + // In both cases (middle or end split) if you split at the wrong place + // you will still not be able to fit the element[] in the block. The + // while loop will insure at least a split into two blocks where there + // may not be room to move any elements from the next block. + + pStack->uiCurElm = (nextBlkNum == BT_END) + ? (FFILE_MAX_FILL * pDb->pFile->FileHdr.uiBlockSize / 100) + : ((uiBlockSize / 20) * 13); // Leave at least 65% full + + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0))) + { + goto Exit; + } + + if (pStack->uiCmpStatus == BT_GT_KEY) + { + + // Save the key in the pKeyBuf + + curElmPtr = &pBlk[pStack->uiCurElm]; + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) + { + flmCopyDrnKey( pStack->pKeyBuf, curElmPtr); + } + else + { + elmKeyLen = (FLMUINT) (BBE_GET_KL( curElmPtr)); + + if (elmKeyLen) + { + // Copy key into pKeyBuf + + prevKeyCnt = (FLMUINT) (BBE_GET_PKC( curElmPtr)); + f_memcpy( &pStack->pKeyBuf[prevKeyCnt], &curElmPtr[uiElmOvhd], + elmKeyLen); + } + } + } + + curElm = pStack->uiCurElm; + + // Check to see if the new element will fit whereever it goes. Don't + // try to optimally place it because the next block may move stuff + // over. + + while ((curElm > oldCurElm) && + (curElm + elmLen + uiElmOvhd + uiElmOvhd > uiBlockSize)) + { + FSBtPrevElm( pDb, pLFile, pStack); + curElm = pStack->uiCurElm; + } + + newBlkStk.uiBlkAddr = newBlkNum; + newBlkStk.pKeyBuf = pStack->pKeyBuf; + FSBlkToStack( &newBlkStk); + newBlkStk.uiKeyBufSize = pStack->uiKeyBufSize; + + curElmPtr = &pBlk[curElm]; + + if (curElm == oldCurElm) + { + + // Decide whether to place the new element in the current or new + // block. Give preference to placing with the current block. + + if ((curElm + elmLen + uiElmOvhd < uiBlockSize) && + ((uiBlkEnd - curElm) > uiElmOvhd)) + { + // Place with the current block + + goto Addto_Current_Blk; + } + + if (uiBlkEnd > curElm) + { + // Move if not at end of block + + FSBlkMoveElms( &newBlkStk, curElmPtr, (FLMUINT) (uiBlkEnd - curElm), + pStack->pKeyBuf); + } + + // Set the block end in the current blocks header & restore values + + pStack->uiBlkEnd = curElm; + UW2FBA( curElm, &pBlk[BH_BLK_END]); + blkNumRestore = newBlkNum; + + // Move if not at end of block + + curElmRestore = BH_OVHD; + newBlkStk.uiCurElm = curElmRestore; + + if (newBlkStk.uiBlkEnd + elmLen + uiElmOvhd > uiBlockSize) + { + // Double split - move element later + + bDoubleSplit = 1; + } + else + { + FSBlkMoveElms( &newBlkStk, pElement, elmLen, NULL); + } + } + else if (curElm > oldCurElm) + { +Addto_Current_Blk: + + // First move stuff over to the new blk + + FSBlkMoveElms( &newBlkStk, curElmPtr, (FLMUINT) (uiBlkEnd - curElm), + pStack->pKeyBuf); + + // Set the block end in the current blocks header + + pStack->uiBlkEnd = curElm; + UW2FBA( curElm, &pBlk[BH_BLK_END]); + blkNumRestore = blkNum; + curElmRestore = oldCurElm; + + // Setup to insert element + + pStack->uiCurElm = curElmRestore; + FSBlkMoveElms( pStack, pElement, elmLen, NULL); + } + else if (curElm < oldCurElm) + { + blkNumRestore = newBlkNum; + FSBlkMoveElms( &newBlkStk, curElmPtr, (FLMUINT) (oldCurElm - curElm), + pStack->pKeyBuf); + newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; + curElmRestore = newBlkStk.uiCurElm; + + // May not fit with 1K blocks - check for double split + + if (curElmRestore + elmLen + + (uiBlkEnd - oldCurElm) + uiElmOvhd > uiBlockSize) + { + bDoubleSplit = 1; + } + else + { + FSBlkMoveElms( &newBlkStk, pElement, elmLen, NULL); + } + + newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; + pStack->uiCurElm = oldCurElm; + + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0))) + { + goto Exit; + } + + if (oldCurElm < uiBlkEnd) + { + FSBlkMoveElms( &newBlkStk, &pBlk[oldCurElm], + (FLMUINT) (uiBlkEnd - oldCurElm), pStack->pKeyBuf); + } + + // Set the block end in the current blocks header + + pStack->uiBlkEnd = curElm; + UW2FBA( curElm, &pBlk[BH_BLK_END]); + } + + // All done with the current block - unpin and set to dirty. + // + // All done moving data from current block to new block. If created new + // right most block check if new to create new root block and init new + // root (easy) else try to move stuff from the next block into the new + // block. + + if (nextBlkNum == BT_END) + { + FLMUINT uiLfNum = pLFile->uiLfNum; + + // We are done with block + + FSReleaseBlock( &newBlkStk, FALSE); + + // At the root? + + if (bNewRootFlag) + { + FLMBYTE byType; + + // Create a new root block + + if (pStack->uiLevel + 1 >= BH_MAX_LEVELS) + { + rc = RC_SET( FERR_BTREE_FULL); + goto Exit; + } + + // Set the block type + + if (pLFile->uiLfType == LF_INDEX) + { + if (pLFile->pIxd->uiFlags & IXD_POSITIONING) + { + byType = BHT_NON_LEAF_COUNTS + BHT_ROOT_BLK; + } + else + { + byType = BHT_NON_LEAF + BHT_ROOT_BLK; + } + } + else + { + byType = BHT_NON_LEAF_DATA + BHT_ROOT_BLK; + } + + // Move all pStack elements down by doing a shift + + shiftN( (FLMBYTE*) pStack, + (FLMUINT) (sizeof(BTSK) * (pStack->uiLevel + 1)), + (FLMINT) sizeof(BTSK)); + + // Create a new block + + if (RC_BAD( rc = ScaCreateBlock( pDb, pLFile, &pStack->pSCache))) + { + goto Exit; + } + + pBlk = pStack->pBlk = pStack->pSCache->pucBlk; + + // Set prev/next block addresses to BT_END + + UD2FBA( BT_END, &pBlk[BH_PREV_BLK]); + UD2FBA( BT_END, &pBlk[BH_NEXT_BLK]); + UW2FBA( BH_OVHD, &pBlk[BH_BLK_END]); + + // Set logical file number in the block header and block type + + UW2FBA( uiLfNum, &pBlk[BH_LOG_FILE_NUM]); + + pBlk[BH_TYPE] = byType; + pBlk[BH_LEVEL] = (FLMBYTE) (++(pStack->uiLevel)); + pStack->uiBlkAddr = GET_BH_ADDR( pBlk); + FSBlkToStack( pStack); + pLFile->uiRootBlk = pStack->uiBlkAddr; + + // Always update the pLFile because level is incremented + + rc = flmLFileWrite( pDb, pLFile); + pStack++; + *ppStack = pStack; + + if (RC_BAD( rc)) + { + goto Exit; + } + } + } + else + { + FLMINT iBytesToMove; + + // Move stuff from the right block + // Remember that newBlk is still pinned + + nextBlkStk.pKeyBuf = pStack->pKeyBuf; + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, nextBlkNum, &nextBlkStk))) + { + goto Exit; + } + + if (RC_BAD( rc = FSLogPhysBlk( pDb, &nextBlkStk))) + { + goto Exit; + } + + nextBlkStk.uiKeyBufSize = pStack->uiKeyBufSize; + nextBlkPtr = nextBlkStk.pBlk; + UD2FBA( newBlkNum, &nextBlkPtr[BH_PREV_BLK]); + + // Try to move so that the two blocks have about the same free space + + iBytesToMove = (FLMINT) ((nextBlkStk.uiBlkEnd - newBlkStk.uiBlkEnd) / 2); + + if (iBytesToMove > 100) + { + + // Log the block before modifying it. + + nextBlkStk.uiCurElm = iBytesToMove + BH_OVHD; + if (RC_BAD( rc = FSBtScanTo( &nextBlkStk, NULL, 0, 0))) + { + goto Exit; + } + + while ((nextBlkStk.uiCurElm > BH_OVHD) && + (nextBlkStk.uiCurElm + newBlkStk.uiBlkEnd + + uiElmOvhd - BH_OVHD >= uiBlockSize)) + { + (void) FSBtPrevElm( pDb, pLFile, &nextBlkStk); + } + + // Never try to move elements from the next block to the new + // block if we are positioned on the first element. Never try + // to move if on LEM or at the end + + if ((nextBlkStk.uiCurElm > BH_OVHD) && + (nextBlkStk.uiCurElm + uiElmOvhd < nextBlkStk.uiBlkEnd)) + { + FLMUINT tempEnd; + + // Save the key in the pKeyBuf + + curElmPtr = &nextBlkPtr[nextBlkStk.uiCurElm]; + if (pStack->uiBlkType != BHT_NON_LEAF_DATA) + { + elmKeyLen = (FLMUINT) (BBE_GET_KL( curElmPtr)); + + if (elmKeyLen) + { + // Copy key into pKeyBuf + + prevKeyCnt = (FLMUINT) (BBE_GET_PKC( curElmPtr)); + f_memcpy( &(nextBlkStk.pKeyBuf)[prevKeyCnt], + &curElmPtr[uiElmOvhd], elmKeyLen); + } + } + + tempWord = nextBlkStk.uiCurElm; + newBlkStk.uiCurElm = newBlkStk.uiBlkEnd; + + FSBlkMoveElms( &newBlkStk, &nextBlkPtr[BH_OVHD], + (FLMUINT) (tempWord - BH_OVHD), NULL); + + // Move the elements in the next block DOWN expanding PKC + + tempEnd = nextBlkStk.uiBlkEnd; + + // Make sure uiBlkEnd is reality or move will not work! + + nextBlkStk.uiBlkEnd = nextBlkStk.uiCurElm = BH_OVHD; + UW2FBA( BH_OVHD, &nextBlkPtr[BH_BLK_END]); + + FSBlkMoveElms( &nextBlkStk, &nextBlkPtr[tempWord], + (FLMUINT) (tempEnd - tempWord), nextBlkStk.pKeyBuf); + + if ((pStack - 1)->uiBlkType == BHT_NON_LEAF_COUNTS) + { + if (RC_BAD( rc = FSUpdateAdjacentBlkCounts( pDb, pLFile, pStack, + &nextBlkStk))) + { + goto Exit; + } + } + } + } + + FSReleaseBlock( &newBlkStk, FALSE); + } + + // Insert the new last element in the current block replacing what is + // there. Insert the last element from the new block. All blocks should + // be dirty and unpined! This means we have to read them in again. + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, blkNum, pStack))) + { + goto Exit; + } + + if (pStack->uiCurElm >= pStack->uiBlkEnd) + { + pStack->uiCurElm = curElm; + } + + // Passing 0 means insert only. + + if (RC_BAD( rc = FSNewLastBlkElm( pDb, pLFile, &pStack, + (nextBlkNum == BT_END) ? 0 : FSNLBE_LESS))) + { + *ppStack = pStack; + goto Exit; + } + + if (RC_BAD( rc = FSAdjustStack( pDb, pLFile, pStack, TRUE))) + { + if (rc != FERR_BT_END_OF_DATA) + { + goto Exit; + } + } + + // Parent is positioned to the nextBlk element. + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, newBlkNum, pStack))) + { + goto Exit; + } + + if ((nextBlkNum == BT_END) && !bNewRootFlag) + { + FLMUINT uiNewRefCount; + FLMUINT uiOldRefCount; + FLMBYTE* pTmpElement; + + // Only update the counts if the inserting a key and not replacing. + + if ((pStack - 1)->uiBlkType == BHT_NON_LEAF_COUNTS) + { + if (RC_BAD( rc = FSBlockCounts( pStack, BH_OVHD, pStack->uiBlkEnd, + NULL, NULL, &uiNewRefCount))) + { + goto Exit; + } + } + + pStack--; + + // Modify the parent last element marker (LEM) to point to the new + // last block. THEN delete the previous element that also pointer to + // the new last block. + // + // Read the parent block + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, pStack->uiBlkAddr, pStack))) + { + return (rc); + } + + if (RC_BAD( rc = FSLogPhysBlk( pDb, pStack))) + { + return (rc); + } + + // Change where element points to in the last element marker (LEM) + + pTmpElement = pStack->pBlk + pStack->uiCurElm; + FSSetChildBlkAddr( pTmpElement, newBlkNum, pStack->uiElmOvhd); + + if (pStack->uiBlkType == BHT_NON_LEAF_COUNTS) + { + uiOldRefCount = FB2UD( &pTmpElement[BNE_CHILD_COUNT]); + if (RC_BAD( rc = FSChangeBlkCounts( pDb, pStack, + (FLMINT) (uiNewRefCount - uiOldRefCount)))) + { + goto Exit; + } + + UD2FBA( uiNewRefCount, &pTmpElement[BNE_CHILD_COUNT]); + } + + pStack++; + } + else + { + + // Inserts the new element into the tree. + + rc = FSNewLastBlkElm( pDb, pLFile, &pStack, 0); + } + +FSBlkSplit_position: + + *ppStack = pStack; + + // Read in block - should be positioned to the current element inserted + + if (RC_OK( rc)) + { + + // Parent element is on the newBlock - see if you need to back up + + if (blkNumRestore == blkNum) + { + if (RC_BAD( rc = FSAdjustStack( pDb, pLFile, pStack, FALSE))) + { + if (rc != FERR_BT_END_OF_DATA) + { + goto Exit; + } + } + } + + if (RC_OK( rc = FSGetBlock( pDb, pLFile, blkNumRestore, pStack))) + { + + // Set up the key buffer (pKeyBuf) to be correct for future + // inserts + + pStack->uiCurElm = curElmRestore; + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0))) + { + goto Exit; + } + + if (bDoubleSplit) + { + + // Now insert the element if flag set This will cause another + // split. RECURSIVE CALL + + rc = FSBlkSplit( pDb, pLFile, ppStack, pElement, elmLen); + } + } + } + +Exit: + + FSReleaseBlock( &newBlkStk, FALSE); + FSReleaseBlock( &nextBlkStk, FALSE); + return (rc); +} + +/**************************************************************************** +Desc: Reset the pStack to set up for a block split +****************************************************************************/ +FSTATIC RCODE FSBtResetStack( + FDB * pDb, // Pointer to database DBC structure. + LFILE * pLFile, // Logical file definition + BTSK ** ppStack, // Stack of variables for each level + FLMBYTE * pElement, // The input element to insert + FLMUINT elmLen) // Length of the element +{ + RCODE rc; + BTSK * pStack = *ppStack; // Stack holding all state info + FLMUINT oldPKC = pStack->uiPKC; // Save old PKC value + FLMUINT oldPvElmPKC = pStack->uiPrevElmPKC; // Save old prev elm PKC value + FLMUINT oldBlock = pStack->uiBlkAddr; // Save old block number + FLMUINT oldCurElm = pStack->uiCurElm; // Save old current element value + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + + if (RC_BAD( rc = FSBtSearch( pDb, pLFile, &pStack, &pElement[uiElmOvhd], + (elmLen - uiElmOvhd), 0))) + { + return (rc); + } + + // In case of continuation elements, parse to matching curElm + + while ((oldBlock != pStack->uiBlkAddr) && (oldCurElm != pStack->uiCurElm)) + { + if ((rc = FSBtNextElm( pDb, pLFile, pStack)) == FERR_BT_END_OF_DATA) + { + return (RC_SET( FERR_BTREE_ERROR)); + } + else if (RC_BAD( rc)) + { + return (rc); + } + } + + // Reset original PKC values + + pStack->uiPKC = oldPKC; + pStack->uiPrevElmPKC = oldPvElmPKC; + *ppStack = pStack; + pStack->uiFlags = FULL_STACK; + + return (FERR_OK); +} + +/**************************************************************************** +Desc: Try to move elements between two blocks while inserting an element +****************************************************************************/ +FSTATIC RCODE FSMoveToNextBlk( + FDB * pDb, + LFILE * pLFile, + BTSK ** ppStack, + FLMUINT nextBlkNum, + FLMBYTE * pElement, + FLMUINT elmLen, + FLMUINT uiBlockSize, + FLMUINT * blkNumRV, + FLMUINT * curElmRV) +{ + RCODE rc = FERR_OK; + BTSK * pStack = *ppStack; + FLMUINT uiBlkEnd = pStack->uiBlkEnd; + FLMUINT oldCurElm = pStack->uiCurElm; + FLMBYTE * curElmPtr; + BTSK nextBlkStk; + FLMUINT nextBlkFreeBytes; + FLMUINT elmKeyLen; + FLMUINT prevKeyCnt; + FLMUINT curElm; + FLMUINT uiElmOvhd = pStack->uiElmOvhd; + FLMBOOL bInsertInCurrentBlock; + FLMBYTE * pBlk = pStack->pBlk; + + FSInitStackCache( &nextBlkStk, 1); + nextBlkStk.pKeyBuf = pStack->pKeyBuf; + + if (RC_BAD( rc = FSGetBlock( pDb, pLFile, nextBlkNum, &nextBlkStk))) + { + goto Exit; + } + + nextBlkFreeBytes = (FLMUINT) (uiBlockSize - nextBlkStk.uiBlkEnd - uiElmOvhd); + pStack->uiCurElm = (uiBlkEnd - (nextBlkFreeBytes / 2)); + + if (RC_BAD( rc = FSBtScanTo( pStack, NULL, 0, 0))) + { + goto Exit; + } + + rc = (pStack->uiCmpStatus == BT_END_OF_DATA) + ? FERR_BT_END_OF_DATA + : FERR_OK; + + for (; RC_OK( rc); rc = FSBlkNextElm( pStack)) + { + + // The current element is positioned to mininum split point. Keep + // testing till at end of block or split will fit within both blocks + // while still adding the element to insert. + // + // Save the key in the pKeyBuf so can move entire element + + curElmPtr = CURRENT_ELM( pStack); + + if (pStack->uiBlkType == BHT_NON_LEAF_DATA) + { + prevKeyCnt = elmKeyLen = 0; + } + else + { + prevKeyCnt = (FLMUINT) (BBE_GET_PKC( curElmPtr)); + elmKeyLen = (FLMUINT) (BBE_GET_KL( curElmPtr)); + } + + if (elmKeyLen) + { + // Copy key into pKeyBuf + + f_memcpy( &pStack->pKeyBuf[prevKeyCnt], &curElmPtr[uiElmOvhd], + elmKeyLen); + } + + // Will element be inserted into the current block? + + if (oldCurElm <= (curElm = pStack->uiCurElm)) + { + + // Insert the element in the current block - could be at the end + + if (curElm + elmLen + uiElmOvhd > uiBlockSize) + { + rc = FERR_BT_END_OF_DATA; + break; + } + + // Left fits - try right block - could fail because of pkc value/ + + if (prevKeyCnt + (uiBlkEnd - curElm) >= nextBlkFreeBytes) + { + // Doesn't fit - try again + + continue; + } + + bInsertInCurrentBlock = TRUE; + } + else + { + + // Moving elements from current block so no need to check it + // Cannot remember why I put BBE_PKC_MAX in the line below + + if (elmLen + prevKeyCnt + BBE_PKC_MAX + + (uiBlkEnd - curElm) >= nextBlkFreeBytes) + { + continue; + } + + bInsertInCurrentBlock = FALSE; + } + + if (RC_BAD( rc = FSLogPhysBlk( pDb, &nextBlkStk))) + { + goto Exit; + } + + if (bInsertInCurrentBlock) + { + FSBlkMoveElms( &nextBlkStk, curElmPtr, (FLMUINT) (uiBlkEnd - curElm), + pStack->pKeyBuf); + + pStack->uiBlkEnd = curElm; + UW2FBA( curElm, &pBlk[BH_BLK_END]); + *curElmRV = oldCurElm; + pStack->uiCurElm = (*curElmRV); + + FSBlkMoveElms( pStack, pElement, elmLen, NULL); + *blkNumRV = pStack->uiBlkAddr; + } + else + { + FSBlkMoveElms( &nextBlkStk, curElmPtr, (FLMUINT) (uiBlkEnd - curElm), + pStack->pKeyBuf); + + pStack->uiBlkEnd = curElm; + UW2FBA( curElm, &pBlk[BH_BLK_END]); + *curElmRV = (FLMUINT) (BH_OVHD + prevKeyCnt + (oldCurElm - curElm)); + nextBlkStk.uiCurElm = (*curElmRV); + + FSBlkMoveElms( &nextBlkStk, pElement, elmLen, NULL); + *blkNumRV = nextBlkNum; + } + + if (pLFile->pIxd && (pLFile->pIxd->uiFlags & IXD_POSITIONING)) + { + if (RC_BAD( rc = FSUpdateAdjacentBlkCounts( pDb, pLFile, pStack, + &nextBlkStk))) + { + goto Exit; + } + } + break; + } + + // If cannot move then return + + if (RC_BAD( rc)) + { + if (rc == FERR_BT_END_OF_DATA) + { + + // Restore old current element + + pStack->uiCurElm = oldCurElm; + rc = RC_SET( FERR_BLOCK_FULL); + } + + goto Exit; + } + + // Fix up the elements in the parent block pointing to the new last + // element in the current block. REMEMBER - pStack may change on you! + + rc = FSNewLastBlkElm( pDb, pLFile, ppStack, FSNLBE_LESS | FSNLBE_POSITION); + +Exit: + + FSReleaseBlock( &nextBlkStk, FALSE); + return (rc); +} diff --git a/flaim/src/fstructs.h b/flaim/src/fstructs.h index 4dda97d..3e88aa4 100644 --- a/flaim/src/fstructs.h +++ b/flaim/src/fstructs.h @@ -25,6 +25,15 @@ #ifndef FSTRUCTS_H #define FSTRUCTS_H +struct FFILE; +struct FNOTIFY; +struct FBUCKET; +struct QUERY_HDR; +struct CDL; +struct FDICT; +struct CP_INFO; +struct IFD; + /************************************************************************** Typedefs for structure pointers. **************************************************************************/ @@ -317,7 +326,7 @@ typedef int (* RECV_BUFFER_FN)( // IMPORTANT NOTE: No other include files should follow this one except // for fpackoff.h -#define LOG_HEADER_SIZE 400 +#define LOG_HEADER_SIZE 512 #define LOG_HEADER_SIZE_VER40 88 // C/S Address types @@ -327,7 +336,9 @@ typedef int (* RECV_BUFFER_FN)( #define FLM_CS_STREAM_ADDR 0x02 // Define the overhead space required to manage encrypted fields. -#define FLM_ENC_FLD_OVERHEAD 7 // Rosalind overhead + +#define FLM_ENC_FLD_OVERHEAD 7 + #define FLD_ENC_FLAGS 0 #define FLD_ENC_ENCID 1 #define FLD_ENC_DATA_LEN 3 @@ -352,25 +363,21 @@ typedef FLMUINT (* UNPROTECT_PAGE_FUNC)( typedef FLMUINT (* SET_DBG_PAGE_WRITER_FUNC)( FLMUINT uiThreadId); -#ifdef FLM_DEBUG -typedef struct SCache_Use * SCACHE_USE_p; /**************************************************************************** -Struct: SCACHE_USE (Cache Block Use) Desc: This is a debug only structure that is used to keep track of the threads that are currently using a block. ****************************************************************************/ -typedef struct SCache_Use +#ifdef FLM_DEBUG +typedef struct SCACHE_USE { - SCACHE_USE_p pNext; // Pointer to next SCACHE_USE structure in + SCACHE_USE * pNext; // Pointer to next SCACHE_USE structure in // the list. FLMUINT uiThreadId; // Thread ID of thread using the block. FLMUINT uiUseCount; // Use count for this particular thread. } SCACHE_USE; #endif - /**************************************************************************** -Struct: SCACHE (Cache Block) Desc: This is the header structure for a cached data block. ****************************************************************************/ typedef struct SCACHE @@ -387,7 +394,7 @@ typedef struct SCACHE // the structure. We keep a pointer to it // so we are not always having to calculate // its address. - FFILE_p pFile; // Pointer to the file this data block + FFILE * pFile; // Pointer to the file this data block // belongs to. FLMUINT uiBlkAddress; // Block address. SCACHE * pPrevInGlobalList; @@ -428,7 +435,7 @@ typedef struct SCACHE // just different versions of the same // block. The next block is an older // version of the block. - FNOTIFY_p pNotifyList; // This is a pointer to a list of threads + FNOTIFY * pNotifyList; // This is a pointer to a list of threads // that want to be notified when a pending // I/O is complete. This pointer is only // non-null if the block is currently being @@ -519,17 +526,16 @@ typedef struct SCACHE #ifdef FLM_DEBUG FLMUINT uiChecksum; // Checksum for the block and header. - SCACHE_USE_p pUseList; // This is a pointer to a list of threads + SCACHE_USE * pUseList; // This is a pointer to a list of threads // that are currently using the block. #endif } SCACHE; /**************************************************************************** -Struct: SCACHE_MGR (Cache Manager) Desc: This is the structure that will be embedded in the FLMSYSDATA structure to manage cache. ****************************************************************************/ -typedef struct SCache_Mgr +typedef struct SCACHE_MGR { SCACHE * pMRUCache; // This is a pointer to the // most-recently used cache block. It @@ -614,14 +620,13 @@ typedef struct SCache_Mgr } SCACHE_MGR; /**************************************************************************** -Struct: RCACHE Desc: This structure is used to manage a particular record in the FLAIM record cache. ****************************************************************************/ typedef struct RCACHE { FlmRecord * pRecord; // Pointer to record object in cache. - FFILE_p pFile; // Pointer to the file this record + FFILE * pFile; // Pointer to the file this record // belongs to. FLMUINT uiContainer; // Container the record comes from FLMUINT uiDrn; // Data record number. @@ -647,7 +652,7 @@ typedef struct RCACHE // memory was allocated on the heap RCACHE * pNextInHeapList; // Next in the list of records whose // memory was allocated on the heap - FNOTIFY_p pNotifyList; // This is a pointer to a list of + FNOTIFY * pNotifyList; // This is a pointer to a list of // threads that want to be notified // when a pending I/O is complete. // This pointer is only non-null if the @@ -733,12 +738,11 @@ typedef struct RCACHE } RCACHE; /**************************************************************************** -Struct: RCACHE_MGR (FLAIM Record Cache Manager) Desc: This structure defines the header information that is used to control the FLAIM record cache. This structure will be embedded in the FLMSYSDATA structure. ****************************************************************************/ -typedef struct +typedef struct RCACHE_MGR { RCACHE * pPurgeList; // List of RCACHE structures that // need to be purged when use @@ -777,55 +781,50 @@ typedef struct #define FTHREAD_ACTION_INDEX_OFFLINE 1 /*************************************************************************** -Struct: F_BKGND_IX (FLAIM Background Indexing Context) Desc: Contains elements for passing parms into the background thread. ***************************************************************************/ -typedef struct F_BkgndIx +typedef struct F_BKGND_IX { - FFILE_p pFile; + FFILE * pFile; FLMUINT uiIndexingAction; FINDEX_STATUS indexStatus; - F_BKGND_IX_p pPrev; - F_BKGND_IX_p pNext; + F_BKGND_IX * pPrev; + F_BKGND_IX * pNext; } F_BKGND_IX; /*************************************************************************** -Struct: FEVENT (FLAIM Event Structure) Desc: This is the FLAIM Event Structure. It keeps track of a registered event callback function that has been registered for a particular event category. ***************************************************************************/ -typedef struct F_Event +typedef struct FEVENT { FEventCategory eCategory; FEVENT_CB fnEventCB; void * pvAppData; - FEVENT_p pNext; - FEVENT_p pPrev; + FEVENT * pNext; + FEVENT * pPrev; } FEVENT; /*************************************************************************** -Struct: FEVENT_HDR (FLAIM Event Header Structure) Desc: This is the FLAIM Event Header Structure. It is the header for the list of events that have been registered for a particular event category. ***************************************************************************/ -typedef struct F_Event_Hdr +typedef struct FEVENT_HDR { - FEVENT_p pEventCBList; // List of registered event callbacks. + FEVENT * pEventCBList; // List of registered event callbacks. F_MUTEX hMutex; // Mutex to control access to the // the event list. } FEVENT_HDR; - /*************************************************************************** -Struct: HTTPCONFIGPARAMS (HTTP configuration parameters) Desc: Contains various parameters needed for displaying debugging data via http. (The reason for all of the function pointers is so that we can compile and link without an http stack if one isn't available and we can dynamicly load one in after we've started.) ***************************************************************************/ -typedef struct +typedef struct HTTPCONFIGPARAMS { F_MUTEX hMutex; FLMUINT uiUseCount; // Webpage display functions increment this while @@ -863,17 +862,16 @@ typedef struct } HTTPCONFIGPARAMS; /*************************************************************************** -Struct: FLMSYSDATA (FLAIM System Data Structure) Desc: This is the FLAIM Shared System Data Structure. It is the anchor for all of the other shared structures. ***************************************************************************/ -typedef struct FlmSystemData +typedef struct FLMSYSDATA { - FFILE_p pMrnuFile; // Pointer to the most recently non-used + FFILE * pMrnuFile; // Pointer to the most recently non-used // FFILE structure. - FFILE_p pLrnuFile; // Pointer to the least recently non-used + FFILE * pLrnuFile; // Pointer to the least recently non-used // FFILE structure. - FBUCKET_p pFileHashTbl; // File name hash table (array of FBUCKET). + FBUCKET * pFileHashTbl; // File name hash table (array of FBUCKET). #define FILE_HASH_ENTRIES 256 FLMUINT uiNextFFileId; // ID that will be assigned to the next @@ -941,8 +939,8 @@ typedef struct FlmSystemData FLM_STATS Stats; // Statistics structure F_MUTEX hQueryMutex; // Mutex for managing query list - QUERY_HDR_p pNewestQuery; // Head of query list (newest) - QUERY_HDR_p pOldestQuery; // Tail of query list (oldest) + QUERY_HDR * pNewestQuery; // Head of query list (newest) + QUERY_HDR * pOldestQuery; // Tail of query list (oldest) FLMUINT uiQueryCnt; // Number of queries in the list FLMUINT uiMaxQueries; // Maximum number of queries to keep around FLMBOOL bNeedToUnsetMaxQueries; @@ -953,7 +951,7 @@ typedef struct FlmSystemData // Has statistics structure been // initialized? - char szTempDir[F_PATH_MAX_SIZE]; + char szTempDir[ F_PATH_MAX_SIZE]; // Temporary working directory for // ResultSets, RecordCache // and other sub-systems that need @@ -965,7 +963,9 @@ typedef struct FlmSystemData // unused structures in memory before // freeing them. FLMBYTE ucBlobExt [64];// Blob Override extension - FEVENT_HDR EventHdrs [F_MAX_EVENT_CATEGORIES]; + FEVENT_HDR LockEvents; // Lock events + FEVENT_HDR UpdateEvents; // Update events + FEVENT_HDR SizeEvents; // Size threshold events POOL KRefPool; // Memory Pool that is only used by // record updaters for key building @@ -1029,7 +1029,7 @@ typedef struct FlmSystemData Desc: This is the hash bucket header structure. Each bucket header points to a list of items that belong to the bucket. ***************************************************************************/ -typedef struct FBucket +typedef struct FBUCKET { void * pFirstInBucket; // Pointer to first item in the bucket. // The type of structure being pointed to @@ -1037,12 +1037,11 @@ typedef struct FBucket FLMUINT uiHashValue; // Hash value for this bucket. } FBUCKET; - /**************************************************************************** Desc: This structure is used to sort keys before the keys are actually added to an index. ****************************************************************************/ -typedef struct Kref_Entry +typedef struct KREF_ENTRY { FLMUINT uiFlags; // Flags for this KREF entry. #define KREF_UNIQUE_KEY 0x01 @@ -1066,11 +1065,11 @@ typedef struct Kref_Entry /**************************************************************************** Desc: This structure is used in the key building process ****************************************************************************/ -typedef struct Kref_Cntrl +typedef struct KREF_CNTRL { - KREF_ENTRY_p * pKrefTbl; // Pointer to KREF Table which is an array of - // KREF_ENTRY_p pointers. - CDL_p * ppCdlTbl; // Pointer to table of CDL pointers. + KREF_ENTRY ** pKrefTbl; // Pointer to KREF Table which is an array of + // KREF_ENTRY * pointers. + CDL ** ppCdlTbl; // Pointer to table of CDL pointers. // There is one CDL pointer per IFD. FLMBYTE * pIxHasCmpKeys; // Pointer to table of FLMBYTEs. There // is one FLMBYTE for each index. The @@ -1096,14 +1095,12 @@ typedef struct Kref_Cntrl void * pReset; // Used to reset pool for failed records. } KREF_CNTRL; - /**************************************************************************** -Struct: FDIAG (Diagnostic Information) Desc: This structure keeps track of diagnostic information (if any) associated with the last FLAIM operation. It is reset at the beginning of every operation. ****************************************************************************/ -typedef struct FDiag +typedef struct FDIAG { FLMUINT uiInfoFlags; // Bit flags indicating what diagnostic // information, if any, was recorded by @@ -1119,14 +1116,13 @@ typedef struct FDiag FLMUINT uiFieldType; // contains data for FLM_DIAG_FIELD_TYPE FLMUINT uiEncId; // contains data for FLM_DIAG_ENC_ID -} FDIAG, * FDIAG_p; +} FDIAG; /**************************************************************************** -Struct: CS_CONTEXT (Client/Server Context) Desc: This structure keeps track of a connection that is in progress with a server. ****************************************************************************/ -typedef struct CS_Context +typedef struct CS_CONTEXT { void * pTcpClient; void * pDDSLocalRequestFunc; @@ -1164,7 +1160,6 @@ typedef struct CS_Context } CS_CONTEXT; /************************************************************************** -Struct: LOG_HDR (Log Header Information) Desc: Information from the log header. The fields in this structure are used temporarily during both read and update transactions. They are set at the beginning of the transaction when the @@ -1172,7 +1167,7 @@ Desc: Information from the log header. The fields in this structure and will be written back into the log header when the update transaction completes. **************************************************************************/ -typedef struct Log_Hdr +typedef struct LOG_HDR { FLMUINT uiCurrTransID; // Current transaction ID. #define TRANS_ID_HIGH_VALUE 0xFFFFFFFF @@ -1183,38 +1178,39 @@ typedef struct Log_Hdr // blocks are allocated at this address. } LOG_HDR; -typedef struct IxStatsTag * IX_STATS_p; - -typedef struct IxStatsTag +/************************************************************************** +Desc: +**************************************************************************/ +typedef struct IX_STATS { FLMUINT uiIndexNum; FLMINT iDeltaRefs; FLMINT iDeltaKeys; - IX_STATS_p pNext; + IX_STATS * pNext; } IX_STATS; -typedef struct IxdFixupTag * IXD_FIXUP_p; - -typedef struct IxdFixupTag +/************************************************************************** +Desc: +**************************************************************************/ +typedef struct IXD_FIXUP { FLMUINT uiIndexNum; FLMUINT uiLastContainerIndexed; FLMUINT uiLastDrnIndexed; - IXD_FIXUP_p pNext; + IXD_FIXUP * pNext; } IXD_FIXUP; /************************************************************************** -Struct: FDB (Database Context Structure) Desc: This structure is the current database context. The database context structure points to a particular FLAIM file and contains the application context for accessing that file. **************************************************************************/ -typedef struct FDb +typedef struct FDB { - FFILE_p pFile; // Pointer to FFILE structure. - FDICT_p pDict; // Pointer to local dictionary - FDB_p pNextForFile; // Next FDB associated with FFILE - FDB_p pPrevForFile; // Prev FDB associated with FFILE + FFILE * pFile; // Pointer to FFILE structure. + FDICT * pDict; // Pointer to local dictionary + FDB * pNextForFile; // Next FDB associated with FFILE + FDB * pPrevForFile; // Prev FDB associated with FFILE void * pvAppData; // Application data that is used // to associate this FDB with // an object in the application @@ -1355,18 +1351,18 @@ typedef struct FDb // been created or deleted during the // transaction - not used for read // transactions. - IXD_FIXUP_p pIxdFixups; // List of indexes whose IXD needs + IXD_FIXUP * pIxdFixups; // List of indexes whose IXD needs // to be restored to its prior // state if the transaction aborts // READ TRANSACTION STUFF - FDB_p pNextReadTrans; // Next active read transaction for + FDB * pNextReadTrans; // Next active read transaction for // this file. // NOTE: If uiKilledTime (see below) // is non-zero, then transaction is // in killed list. - FDB_p pPrevReadTrans; // Previous active read transaction + FDB * pPrevReadTrans; // Previous active read transaction // for this file. // NOTE: If uiKilledTime (see below) // is non-zero, then transaction is @@ -1427,7 +1423,7 @@ typedef struct FDb // of transaction. FLMBOOL bStatsInitialized;// Has statistics structure been // initialized? - CS_CONTEXT_p pCSContext; // Pointer to client/server + CS_CONTEXT * pCSContext; // Pointer to client/server // connection this FDB is associated // with, NULL if none. F_BKGND_IX * pIxStartList; // Indexing threads to start at @@ -1455,10 +1451,10 @@ typedef struct FDb // FLAIM Version Number Defines -#define FLM_VER_POS (FLAIM_NAME_LEN) -#define FLM_VER_LEN 4 -#define FLM_MINOR_VER_POS (FLM_VER_POS + 2) -#define FLM_SMINOR_VER_POS (FLM_VER_POS + 3) +#define FLM_FILE_FORMAT_VER_POS (FLAIM_NAME_LEN) +#define FLM_FILE_FORMAT_VER_LEN 4 +#define FLM_MINOR_VER_POS (FLM_FILE_FORMAT_VER_POS + 2) +#define FLM_SMINOR_VER_POS (FLM_FILE_FORMAT_VER_POS + 3) // Defines to access elements within the database version number @@ -1491,7 +1487,7 @@ typedef struct FDb Desc: This structure contains the file header information for a file as well as its create options. **************************************************************************/ -typedef struct File_Hdr +typedef struct FILE_HDR { FLMUINT uiFirstLFHBlkAddr; // Address of first LFH block. FLMUINT uiVersionNum; // Database version @@ -1505,16 +1501,15 @@ typedef struct File_Hdr } FILE_HDR; /************************************************************************** -Struct: FFILE (FLAIM File Structure) Desc: This structure is the main shared structure for a FLAIM file. It contains static information about the file. **************************************************************************/ -typedef struct FFile +typedef struct FFILE { - FFILE_p pNext; // Next FFILE structure in in name hash + FFILE * pNext; // Next FFILE structure in in name hash // bucket, dependent store hash // bucket, or avail list. - FFILE_p pPrev; // Previous FFILE structure in name hash + FFILE * pPrev; // Previous FFILE structure in name hash // bucket or dependent store hash // bucket. FLMUINT uiFFileId; // Unique FFILE identifier @@ -1522,16 +1517,16 @@ typedef struct FFile FLMUINT uiUseCount; // Number of FDBs currently using this file. FLMUINT uiInternalUseCount; // Number of the uses that are internal // background threads. - FDB_p pFirstDb; // List of ALL FDB's associated with + FDB * pFirstDb; // List of ALL FDB's associated with // this FFILE. char * pszDbPath; // Database file name. char * pszDataDir; // Path for data files. - FFILE_p pNextNUFile; // Next FFILE structure in list of + FFILE * pNextNUFile; // Next FFILE structure in list of // unused files. When use count goes // to zero, the structure is linked // into a list of unused files off of // the FSYSDATA structure. - FFILE_p pPrevNUFile; // Previous FFILE structure in list of + FFILE * pPrevNUFile; // Previous FFILE structure in list of // unused files. SCACHE * pSCacheList; // This is a pointer to a linked list // of all shared cache blocks @@ -1564,15 +1559,15 @@ typedef struct FFile // belonging to this file that need // to be logged to the rollback log // for the current transaction. - FNOTIFY_p pOpenNotifies; // Pointer to a list of notifies to + FNOTIFY * pOpenNotifies; // Pointer to a list of notifies to // perform when this file is finally // opened (points to a linked list of // FNOTIFY structures). - FNOTIFY_p pCloseNotifies; // Pointer to a list of notifies to + FNOTIFY * pCloseNotifies; // Pointer to a list of notifies to // perform when this file is finally // closed (points to a linked list of // FNOTIFY structures). - FDICT_p pDictList; // Pointer to linked list of + FDICT * pDictList; // Pointer to linked list of // dictionaries currently being used // for this file. The linked list // is a list of versions of the @@ -1597,12 +1592,12 @@ typedef struct FFile // sets this value to its // checkpoint. F_Rfl * pRfl; // Pointer RFL object. - FLMBYTE ucLastCommittedLogHdr [LOG_HEADER_SIZE]; + FLMBYTE ucLastCommittedLogHdr[ LOG_HEADER_SIZE]; // This is the last committed log header. - FLMBYTE ucCheckpointLogHdr [LOG_HEADER_SIZE]; + FLMBYTE ucCheckpointLogHdr[ LOG_HEADER_SIZE]; // This is the log header as of the start // of the last checkpoint. - FLMBYTE ucUncommittedLogHdr [LOG_HEADER_SIZE]; + FLMBYTE ucUncommittedLogHdr[ LOG_HEADER_SIZE]; // This is the uncommitted log header. // It is used by the current update // transaction. @@ -1641,8 +1636,13 @@ typedef struct FFile #define LOG_NU_152_153 152 // Two bytes are unused #define LOG_MAX_FILE_SIZE 154 // Multiply by 64K to get actual maximum #define LOG_DATABASE_KEY_LEN 156 // Current Length of the database key -#define LOG_DATABASE_KEY 158 // Wrapped or shrouded copy of the database - // key (Up to 204 bytes long) +#define LOG_DATABASE_KEY 158 // Wrapped or shrouded copy of the database key (max 256 bytes) +#define LOG_RFL_DISK_SPACE_THRESHOLD 414 // RFL disk space threshold in K bytes (0 = unlimited) +#define LOG_RFL_LIMIT_TIME_FREQ 418 // How often (in seconds) to throw an over-the-limit event (0 = ignore) +#define LOG_RFL_LIMIT_SPACE_FREQ 422 // How often (based on the size increase in megabytes since the last event) + // to throw an over-the-limit-event (0 = ignore) + +#define FLM_MAX_DB_ENC_KEY_LEN 256 F_FileIdList * pFileIdList; // List of unique IDs that have been // assigned to the physical files that @@ -1652,6 +1652,7 @@ typedef struct FFile #define MAX_WRITE_BUFFER_BYTES (4 * 1024 * 1024) #define MAX_PENDING_WRITES (MAX_WRITE_BUFFER_BYTES / 4096) #define MAX_LOG_BUFFER_SIZE (256 * 1024) + F_IOBuffer * pCurrLogBuffer; FLMUINT uiCurrLogWriteOffset;// Offset in current write buffer FLMUINT uiCurrLogBlkAddr; // Address of first block in the current @@ -1661,18 +1662,18 @@ typedef struct FFile ServerLockObject * pFileLockObj; // Object for locking the file. ServerLockObject * pWriteLockObj; // Object for locking to do writing. F_FileHdlImp * pLockFileHdl; // Lock file handle for 3.x databases. - FNOTIFY_p pLockNotifies; // Pointer to a list of notifies to + FNOTIFY * pLockNotifies; // Pointer to a list of notifies to // perform when this file is finally // locked (points to a linked list of // FNOTIFY structures). FLMBOOL bBeingLocked; // Flag indicating whether or not this // file is in the process of being // locked for exclusive access. - FDB_p pFirstReadTrans; // Pointer to first read transaction for + FDB * pFirstReadTrans; // Pointer to first read transaction for // this file. - FDB_p pLastReadTrans; // Pointer to last read transaction for + FDB * pLastReadTrans; // Pointer to last read transaction for // this file. - FDB_p pFirstKilledTrans; // List of read transactions that have + FDB * pFirstKilledTrans; // List of read transactions that have // been killed. FLMUINT uiFirstLogBlkAddress;// Address of first block logged for the // current update transaction. @@ -1683,8 +1684,9 @@ typedef struct FFile FLMUINT uiLastCheckpointTime; // Last time we successfully completed a // checkpoint. + F_Thread * pMonitorThrd; // Database monitor thread F_Thread * pCPThrd; // Checkpoint thread. - CP_INFO_p pCPInfo; // Pointer to checkpoint thread's + CP_INFO * pCPInfo; // Pointer to checkpoint thread's // information buffer - used for // communicating information to the // checkpoint thread. @@ -1716,21 +1718,18 @@ typedef struct FFile // that there may be some work to do FMAINT_STATUS maintStatus; char * pszDbPassword; // A password that was used to open the database (may be NULL). - -#define FFILE_MIN_FILL 35 -#define FFILE_MAX_FILL 91 + FLMUINT64 ui64RflDiskUsage; // Current RFL disk space usage estimate (used only if keeping RFL files) } FFILE; /*************************************************************************** -Struct: FNOTIFY (Notify Structure) Desc: This is the notify request structure. Notify requests are linked off of open requests for files or read requests for files so that when an operation is complete that multiple threads are waiting on, all of them will be notified. ***************************************************************************/ -typedef struct FNotify +typedef struct FNOTIFY { - FNOTIFY_p pNext; // Pointer to next FNOTIFY structure in list. + FNOTIFY * pNext; // Pointer to next FNOTIFY structure in list. FLMUINT uiThreadId; // ID of thread requesting the notify RCODE * pRc; // Pointer to a return code variable that is to // be filled in when the operation is completed. @@ -1742,251 +1741,11 @@ typedef struct FNotify // operation is complete. } FNOTIFY; - /**************************************************************************** -Struct: ITT (Item Type Table entry) -Desc: A Item Type consists of a byte that describes the type of item - like a field, index or container. - For fields a ITT will also indicate the fields delete status. -****************************************************************************/ - -typedef struct Itt -{ - FLMUINT uiType; - void * pvItem; // Points to LFILE if index or container - // If field, is NULL or points to first IFD. -} ITT; - -// Bit values for uiType. The 4 low bits contain the field type. -// See FLM_XXXX_TYPE in FLAIM.H for lower four bits. - -#define ITT_FLD_GET_TYPE( pItt) (((pItt)->uiType) & 0x0F) -#define ITT_FLD_IS_INDEXED( pItt) (((pItt)->pvItem) ? TRUE : FALSE) -#define ITT_FLD_GET_STATE( pItt) (((pItt)->uiType) & 0x30) - -#define ITT_FLD_STATE_MASK 0x30 -#define ITT_FLD_STATE_ACTIVE 0x00 // Normal active field -#define ITT_FLD_STATE_CHECKING 0x10 // Field has been marked to be checked -#define ITT_FLD_STATE_UNUSED 0x30 // Field is not used. -#define ITT_FLD_STATE_PURGE 0x20 // Purge this field from the database. - // And delete the dictionary definition - -#define ITT_ENC_STATE_MASK 0x30 -#define ITT_ENC_STATE_ACTIVE 0x00 // Normal active field -#define ITT_ENC_STATE_CHECKING 0x10 // EncDef has been marked to be checked -#define ITT_ENC_STATE_UNUSED 0x30 // EncDef is not used. -#define ITT_ENC_STATE_PURGE 0x20 // EncDef record is being deleted. Decrypt the - // encrypted field as it can no longer be - // encrypted. - -#define ITT_ENCDEF_TYPE 0xAF // Encrypted Definition Record -#define ITT_INDEX_TYPE 0xBF -#define ITT_CONTAINER_TYPE 0xCF -#define ITT_EMPTY_SLOT 0xEF -#define ITT_INFO_MASK 0x0F - -#define ITT_IS_FIELD(pItt) (((pItt)->uiType & ITT_INFO_MASK) != ITT_INFO_MASK) -#define ITT_IS_CONTAINER(pItt) ((pItt)->uiType == ITT_CONTAINER_TYPE) -#define ITT_IS_INDEX(pItt) ((pItt)->uiType == ITT_INDEX_TYPE) -#define ITT_IS_ENCDEF(pItt) ((pItt)->uiType == ITT_ENCDEF_TYPE) - -/**************************************************************************** -Struct: IXD (Index Definition) -Desc: This structure holds the information for an index definition. - There may be multiple IXDs for the same index number. -****************************************************************************/ -typedef struct Ixd -{ - FLMUINT uiIndexNum; // Index number. - FLMUINT uiContainerNum; // Container number being indexed. - IFD_p pFirstIfd; // Points to first IFD - FLMUINT uiNumFlds; // Number of index fields in the IFD. - FLMUINT uiFlags; - #define IXD_UNIQUE 0x00001 // Unique index - #define IXD_COUNT 0x00002 // Count keys and references - #define IXD_EACHWORD 0x00100 // FUTURE: FLAIMs fulltext indexing. - #define IXD_HAS_POST 0x01000 // Has post keys parts. - #define IXD_HAS_SUBSTRING 0x02000 - #define IXD_POSITIONING 0x04000 // The index has positioning counts. - #define IXD_OFFLINE 0x08000 - #define IXD_SUSPENDED 0x10000 - - FLMUINT uiLanguage; // WP.LRS language number (not code!) - #define US_LANG 0 - #define DEFAULT_LANG US_LANG - -#define TRANS_ID_OFFLINE TRANS_ID_HIGH_VALUE -#define TRANS_ID_ALWAYS_ONLINE TRANS_ID_LOW_VALUE - - FLMUINT uiLastContainerIndexed; // Last container indexed if index - // covers multiple containers. - FLMUINT uiLastDrnIndexed; // If value is not DRN_LAST_MARKER then - // update index with keys from a record - // update if drn of record is <= of - // this value. - FLMUINT uiEncId; // The ID / Drn of the Encryption record (if used) -} IXD; - -/**************************************************************************** -Struct: IFD (Index Field Definition) -Desc: This structure contains an index field definition. -****************************************************************************/ -typedef struct Ifd -{ - FLMUINT uiFldNum; // Field being indexed. - FLMUINT uiIndexNum; // Index number. - IXD_p pIxd; // IXD corresponding to wIndexNum - FLMUINT uiFlags; // The first 4 bits contain field type - // Use FLM_XXXXX_TYPE definitions. - - IFD_p pNextInChain; // Next IFD in the chain that has this - // field number and is used in another index. - FLMUINT * pFieldPathCToP; // Child to parent field path (zero term) - FLMUINT * pFieldPathPToC; // Parent to child field path (zero term) - - FLMUINT uiLimit; // Zero or # of characters/bytes to limit. -#define IFD_DEFAULT_LIMIT 256 -#define IFD_DEFAULT_SUBSTRING_LIMIT 48 - - FLMUINT uiCompoundPos; // Position of this field is in - // the compound key. Zero based number. -} IFD; - -#define IFD_GET_FIELD_TYPE(pIfd) ((pIfd)->uiFlags & 0x0F) -#define IFD_SET_FIELD_TYPE(pIfd,type) ((pIfd)->uiFlags = ((pIfd)->uiFlags & 0xFFFFFFF0) | (type)) -#define IFD_FIELD 0x00000010 // There must always be some value -#define IFD_VALUE 0x00000010 // Value agrees with parsing syntax - -#define IFD_EACHWORD 0x00000020 // Index each and every word in the field -#define IFD_CONTEXT 0x00000040 // Index the tag and NOT the value -#define IFD_COMPOUND 0x00000080 // Index multiple fields - -#define IFD_POST 0x00000100 // Place case info at end of compound key -#define IFD_UPPER 0x00000200 // Uppercase keys only -#define IFD_OPTIONAL 0x00000400 // This field is optional (compound) - // Phasing this value out. - -// Note: the unique flag is for future compatiblity. - -#define IFD_UNIQUE_PIECE 0x00000800 // Better name - -#define IFD_REQUIRED_PIECE 0x00001000 // Required piece (not optional) -#define IFD_REQUIRED_IN_SET 0x0002000 // Required within a set of fields. - -#define IFD_LAST 0x00008000 // Last IFD for this index definition - -#define IFD_SUBSTRING 0x00040000 // Index all substrings pieces -#define IFD_DRN 0x00080000 // index DRN value -#define IFD_FIELDID_PAIR 0x00200000 // Data | fieldID pair. -#define IFD_MIN_SPACES 0x00400000 // Removed leading/trailing spaces. - // Combine multiple spaces into 1 space. - // Minimize spaces -#define IFD_NO_SPACE 0x00800000 // Remove all spaces -#define IFD_NO_DASH 0x01000000 // Remove all dashes -#define IFD_NO_UNDERSCORE 0x02000000 // Change underscores to spaces, - // Must be applied before nospace/minspace -#define IFD_ESC_CHAR 0x04000000 // Placehold so that a query can parse the input - // string and find a literal '*' or '\\'. - -/* - Future Options to support (This is here so we don't forget about them.) - ALL_COMBOS - Currently we normalize all field combinations - This option would drop the normalization on context. - NO_COLLATION - drop all of the text collation and just store the - text without the key conversion. - FULLTEXT indexing - - ALLOW_NULL_KEY - allow a null key - ALTERNATE_KEYS - Each compound field piece can have data from multiple fields. -*/ - -#define IFD_IS_POST_TEXT(pIfd) (((pIfd)->uiFlags & IFD_POST) && \ - (IFD_GET_FIELD_TYPE(pIfd) == FLM_TEXT_TYPE)) -#define IFD_DEFAULT_LIMIT 256 -#define IFD_DEFAULT_SUBSTRING_LIMIT 48 - -/**************************************************************************** -Struct: LFILE (Logical File) -Desc: This keeps track of the logical file information for an index or - a container. -****************************************************************************/ -typedef struct LFILE -{ - FLMUINT uiRootBlk; // Address of root block. - FLMUINT uiNextDrn; // Next DRN - only use when root is null - FLMUINT uiBlkAddress; // Block address of LFile entry. - FLMUINT uiOffsetInBlk; // Offset within block of entry. - FLMUINT uiLfNum; // Index number or container number. - FLMUINT uiLfType; // Type of logical file. */ - FLMBOOL bMakeFieldIdTable; // Boolean that indicates whether or not - // for this container when we create - // records in cache we should create a - // field id table for the level-1 fields. - IXD * pIxd; // If an index, points to the IXD. - -} LFILE; - -/************************************************************************** -Struct: FDICT (Dictionary Header Structure) -Desc: This structure is a header for a FLAIM dictionary. All of - the information in this structure is static. -**************************************************************************/ -typedef struct FDict -{ - FDICT_p pNext; // Pointer to next FDICT structure in the list, - // if any. All versions of a dictionary that - // are currently in use are linked together. - // Usually, there will be only one local - // dictionary in the list. - FDICT_p pPrev; // Previous FDICT structure in the list. - FFILE * pFile; // File this dictionary is associated with. - // A null value means it is not yet linked - // to a file. - FLMUINT uiDictSeq; // This is the sequence number of the dictionary - - // Local Dictionary Tables. - - LFILE * pLFileTbl; // Logical file (index or container) - FLMUINT uiLFileCnt; -#define LFILE_DATA_CONTAINER_OFFSET 0 -#define LFILE_DICT_CONTAINER_OFFSET 1 -#define LFILE_DICT_INDEX_OFFSET 2 -#define LFILE_TRACKER_CONTAINER_OFFSET 3 - - ITT * pIttTbl; - FLMUINT uiIttCnt; - - IXD * pIxdTbl; - FLMUINT uiIxdCnt; - - IFD * pIfdTbl; - FLMUINT uiIfdCnt; - - FLMUINT * pFldPathsTbl; - FLMUINT uiFldPathsCnt; - - FLMUINT uiUseCount; // Number of FDB structures currently - // pointing to this dictionary. -} FDICT; - -/**************************************************************************** -Struct: CDL (Compound Data List) -Desc: This is a temporary structure that is used when building compound - keys. -****************************************************************************/ -typedef struct Cdl -{ - void * pField; // Field to be included in a compound key - void * pRootContext; // Points to root context of field path - CDL_p pNext; // Pointer to the next CDL entry. -} CDL; - - -/**************************************************************************** -Struct: CP_INFO (Checkpoint Information( Desc: Structure used to pass information to the checkpoint thread for 3.x databases. ****************************************************************************/ -typedef struct CP_Info +typedef struct CP_INFO { FFILE * pFile; F_SuperFileHdl * pSFileHdl; @@ -2005,10 +1764,9 @@ typedef struct CP_Info } CP_INFO; /**************************************************************************** -Struct: DIN_STATE Desc: State information for parsing forward/back in reference set lists. ****************************************************************************/ -typedef struct Din_State +typedef struct DIN_STATE { FLMUINT uiOffset; FLMUINT uiOnes; @@ -2027,10 +1785,9 @@ typedef struct Din_State #define MAX_KEY_SIZ 640 /**************************************************************************** -Struct: BTSK (B-Tree State Information) Desc: State information for parsing forward/back in reference set lists. ****************************************************************************/ -typedef struct Btsk +typedef struct BTSK { FLMBYTE * pBlk; // Points to the cache block buffer FLMBYTE * pKeyBuf; // Points to a key buffer - near ptr @@ -2052,7 +1809,6 @@ typedef struct Btsk } BTSK; /**************************************************************************** -Struct: FBAK (Backup Handle) Desc: State information for performing a backup ****************************************************************************/ typedef struct FBak @@ -2077,7 +1833,10 @@ typedef struct FBak FLMBYTE ucDbHeader[ F_TRANS_HEADER_SIZE]; } FBak; -typedef struct +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct BCD_TYPE { const FLMBYTE * pucPtr; FLMUINT uiNibCnt; @@ -2086,6 +1845,9 @@ typedef struct FLMBYTE ucNumBuf[ F_MAX_NUM_BUF]; } BCD_TYPE; +/**************************************************************************** +Desc: +****************************************************************************/ typedef struct GED_STREAM { F_FileHdl * pFileHdl; @@ -2096,18 +1858,24 @@ typedef struct GED_STREAM char * pLast; FLMINT errorIO; FLMINT thisC; -} GED_STREAM, * GED_STREAM_p; +} GED_STREAM; #define MAX_COMPOUND_PIECES 32 -typedef struct FLD_PATH_CONTEXT +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct FLD_CONTEXT { void * pParentAnchor; void * rootContexts[ MAX_COMPOUND_PIECES]; void * leafFlds[ MAX_COMPOUND_PIECES]; } FLD_CONTEXT; -typedef struct Exp_Imp_Info +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct EXP_IMP_INFO { F_FileHdl * pFileHdl; FLMBYTE * pBuf; @@ -2117,24 +1885,32 @@ typedef struct Exp_Imp_Info FLMUINT uiFilePos; FLMBOOL bDictRecords; FLMBOOL bBufDirty; -} EXP_IMP_INFO, * EXP_IMP_INFO_p; +} EXP_IMP_INFO; -// The ND2BF structure is used to convert a NODE into a -// buffer and is used within GedNodeToBuf. +/**************************************************************************** +Desc: The ND2BF structure is used to convert a NODE into a + buffer and is used within GedNodeToBuf. +****************************************************************************/ typedef struct ND2BF { FLMBYTE * buffer; FLMINT iLimit; F_NameTable * pNameTable; -} ND2BF, * ND2BF_p; +} ND2BF; -typedef struct QueryHdrTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct QUERY_HDR { HFCURSOR hCursor; - QUERY_HDR_p pNext; - QUERY_HDR_p pPrev; + QUERY_HDR * pNext; + QUERY_HDR * pPrev; } QUERY_HDR; +/**************************************************************************** +Desc: +****************************************************************************/ typedef enum { HASH_SESSION_OBJ = 0, @@ -2339,7 +2115,7 @@ private: FLMUINT m_uiThreadId; FLMUINT m_uiThreadLockCount; F_MUTEX m_hMutex; - FNOTIFY_p m_pNotifyList; + FNOTIFY * m_pNotifyList; F_NameTable * m_pNameTable; FLMUINT m_uiDictSeqNum; F_XMLImport * m_pXmlImport; diff --git a/flaim/src/fsuperfl.cpp b/flaim/src/fsuperfl.cpp index f32f456..fa588ad 100644 --- a/flaim/src/fsuperfl.cpp +++ b/flaim/src/fsuperfl.cpp @@ -960,7 +960,7 @@ RCODE F_SuperFileHdl::GetFilePath( goto Exit; } - if ((m_uiDbVersion >= FLM_VER_4_3 && + if ((m_uiDbVersion >= FLM_FILE_FORMAT_VER_4_3 && uiFileNumber <= MAX_DATA_FILE_NUM_VER43) || uiFileNumber <= MAX_DATA_FILE_NUM_VER40) { @@ -1209,7 +1209,7 @@ void bldSuperFileExtension( flmAssert( uiDbVersion); // Make sure the database version is valid - if (uiDbVersion >= FLM_VER_4_3) + if (uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { if (uiFileNum <= MAX_DATA_FILE_NUM_VER43 - 1536) { diff --git a/flaim/src/fsuperfl.h b/flaim/src/fsuperfl.h index 70f162a..2a2173a 100644 --- a/flaim/src/fsuperfl.h +++ b/flaim/src/fsuperfl.h @@ -32,12 +32,12 @@ #define MAX_CHECKED_OUT_FILE_HDLS 8 class F_SuperFileHdl; -typedef F_SuperFileHdl * F_SuperFileHdl_p; - class F_FileIdList; -typedef F_FileIdList * F_FileIdList_p; -typedef struct CheckedOutFileHdlTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct CHECKED_OUT_FILE_HDL { F_FileHdlImp * pFileHdl; FLMUINT uiFileNumber; diff --git a/flaim/src/fsv.h b/flaim/src/fsv.h index 6e93d27..57501b4 100644 --- a/flaim/src/fsv.h +++ b/flaim/src/fsv.h @@ -30,6 +30,7 @@ // IMPORTANT NOTE: No other include files should follow this one except // for fpackoff.h +#define FSV_MAX_TCP_HANDLERS 64 #define FSV_LOG_BUFFER_SIZE 256 // Server defaults @@ -50,13 +51,12 @@ #define FSV_OBJECT_ROPS 0x0007 #define FSV_OBJECT_POOL 0x0008 -typedef struct +typedef struct FSV_RECORD_ID { FLMUINT uiDatabaseId; FLMUINT uiStore; FLMUINT uiContainer; FLMUINT uiDrn; - } FSV_RECORD_ID; #ifdef FLM_NLM @@ -256,15 +256,8 @@ private: #define MAX_SESN_ITERATORS 10 HFCURSOR m_IteratorList[ MAX_SESN_ITERATORS]; POOL m_wireScratchPool; - - /* - Metchods - */ - }; - - /**************************************************************************** Server Wire Class @@ -550,7 +543,7 @@ RCODE fsvGetStreamedResponse( FLMBOOL * pbLastPacket); RCODE fsvStreamLoopback( - FCS_BIOS_p pStream, + FCS_BIOS * pStream, FLMUINT uiEvent, void * UserData); diff --git a/flaim/src/fsv_glob.cpp b/flaim/src/fsv_glob.cpp deleted file mode 100644 index 8105af8..0000000 --- a/flaim/src/fsv_glob.cpp +++ /dev/null @@ -1,147 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Server global context. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_glob.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSV_SCTX * gv_pGlobalContext = NULL; - -/**************************************************************************** -Desc: Initializes the server's global context. -*****************************************************************************/ -RCODE fsvInitGlobalContext( - FLMUINT uiMaxSessions, - const char * pszServerBasePath, - FSV_LOG_FUNC pLogFunc) -{ - RCODE rc = FERR_OK; - FSV_SCTX * pTmpContext = NULL; - - if( gv_pGlobalContext) - { - // Context already initialized - goto Exit; - } - - if( (pTmpContext = f_new FSV_SCTX) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = pTmpContext->Setup( uiMaxSessions, - pszServerBasePath, pLogFunc))) - { - goto Exit; - } - -Exit: - - if( RC_BAD( rc)) - { - if( pTmpContext) - { - pTmpContext->Release(); - } - } - else if( pTmpContext) - { - gv_pGlobalContext = pTmpContext; - } - - return( rc); - -} - - -/**************************************************************************** -Desc: Frees any resources allocated to the global context. -*****************************************************************************/ -void fsvFreeGlobalContext( void) -{ - if( gv_pGlobalContext) - { - gv_pGlobalContext->Release(); - gv_pGlobalContext = NULL; - } -} - - -/**************************************************************************** -Desc: Sets the server's base (relative) path -*****************************************************************************/ -RCODE fsvSetBasePath( - const char * pszServerBasePath) -{ - RCODE rc = FERR_OK; - - if( !gv_pGlobalContext) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = gv_pGlobalContext->SetBasePath( pszServerBasePath))) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Sets the server's temporary directory -*****************************************************************************/ -RCODE fsvSetTempDir( - const char * pszTempDir) -{ - RCODE rc = FERR_OK; - - if( !gv_pGlobalContext) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = gv_pGlobalContext->SetTempDir( pszTempDir))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Returns a pointer to the server's global context object. -*****************************************************************************/ -RCODE fsvGetGlobalContext( - FSV_SCTX ** ppGlobalContext) -{ - *ppGlobalContext = gv_pGlobalContext; - return( FERR_OK); -} diff --git a/flaim/src/fsv_hdlr.cpp b/flaim/src/fsv_hdlr.cpp deleted file mode 100644 index 2f38edd..0000000 --- a/flaim/src/fsv_hdlr.cpp +++ /dev/null @@ -1,4243 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Routines needed to service client requests made to the server. -// Tabs: 3 -// -// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_hdlr.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE fsvIteratorParse( - FSV_WIRE * pWire, - POOL * pPool); - -FSTATIC RCODE fsvIteratorWhereParse( - FSV_WIRE * pWire, - POOL * pPool); - -FSTATIC RCODE fsvIteratorFromParse( - FSV_WIRE * pWire, - POOL * pPool); - -FSTATIC RCODE fsvIteratorSelectParse( - FSV_WIRE * pWire, - POOL * pPool); - -FSTATIC RCODE fsvDbGetBlocks( - HFDB hDb, - FLMUINT uiAddress, - FLMUINT uiMinTransId, - FLMUINT * puiCount, - FLMUINT * puiBlocksExamined, - FLMUINT * puiNextBlkAddr, - FLMUINT uiFlags, - POOL * pPool, - FLMBYTE ** ppBlocks, - FLMUINT * puiBytes); - -FSTATIC RCODE fsvGetHandles( - FSV_WIRE * pWire); - -/* -Function / Method Implementations -*/ - -/**************************************************************************** -Desc: This is the function that processes FLAIM requests. -*****************************************************************************/ -RCODE fsvProcessRequest( - FCS_DIS * pDataIStream, - FCS_DOS * pDataOStream, - POOL * pScratchPool, - FLMUINT * puiSessionIdRV) -{ - void * pvMark = NULL; - FSV_WIRE Wire( pDataIStream, pDataOStream); - RCODE rc = FERR_OK; - - /* - Set the temporary pool - */ - - if( pScratchPool) - { - pvMark = GedPoolMark( pScratchPool); - Wire.setPool( pScratchPool); - } - - /* - Read the request - */ - - if( RC_BAD( rc = Wire.read())) - { - goto Exit; - } - - /* - Close the input stream. - */ - - pDataIStream->close(); - Wire.setDIStream( NULL); - - /* - Get any required handles. - */ - - if( RC_BAD( rc = fsvGetHandles( &Wire))) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"Error calling fsvGetHandles", rc, FSV_LOG_DEBUG); -#endif - goto Exit; - } - - /* - Call the appropriate handler function. - */ - - switch( Wire.getClass()) - { - case FCS_OPCLASS_GLOBAL: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Global", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassGlobal( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_SESSION: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Session", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassSession( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_DATABASE: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Database", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassDatabase( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_TRANS: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Transaction", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassTransaction( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_RECORD: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Record", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassRecord( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_ITERATOR: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Iterator", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassIterator( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_BLOB: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: BLOB", 0, FSV_LOG_DEBUG); -#endif - rc = RC_SET( FERR_NOT_IMPLEMENTED); - break; - } - - case FCS_OPCLASS_DIAG: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Diagnostic", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassDiag( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_FILE: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: File System", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassFile( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_ADMIN: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Admin", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassAdmin( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_INDEX: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Index", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassIndex( &Wire))) - { - goto Exit; - } - break; - } - - case FCS_OPCLASS_MISC: - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"OpClass: Misc.", 0, FSV_LOG_DEBUG); -#endif - if( RC_BAD( rc = fsvOpClassMisc( &Wire))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - - if( puiSessionIdRV) - { - // Set the session ID so that the calling routine has - // the option of performing cleanup on an error - *puiSessionIdRV = Wire.getSessionId(); - } - -Exit: - - if( RC_BAD( rc)) - { - /* - If the input stream is still open, the handler never - send any data to the client. Close the input stream and - try to send the error code to the client. - */ - - if( pDataIStream->isOpen()) - { - (void)pDataIStream->close(); - Wire.setDIStream( NULL); - } - - if( RC_OK( Wire.sendOpcode( Wire.getClass(), Wire.getOp()))) - { - if( RC_OK( Wire.sendRc( rc))) - { - if( RC_OK( Wire.sendTerminate())) - { - pDataOStream->close(); - } - } - } - } - else - { - pDataOStream->close(); - } - - if( pScratchPool) - { - GedPoolReset( pScratchPool, pvMark); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a diagnostic operation -*****************************************************************************/ -RCODE fsvOpClassDiag( - FSV_WIRE * pWire) -{ - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Service the request. - */ - - switch( pWire->getOp()) - { - case FCS_OP_DIAG_HTD_ECHO: - { - /* - Simply echo the record back to the client. This - is done below when the response is sent to the client. - */ - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_DIAG, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - switch( pWire->getOp()) - { - case FCS_OP_DIAG_HTD_ECHO: - { - if( pWire->getRecord() != NULL) - { - if( RC_BAD( rc = pWire->sendRecord( - WIRE_VALUE_HTD, pWire->getRecord()))) - { - goto Exit; - } - } - break; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a file system operation -*****************************************************************************/ -RCODE fsvOpClassFile( - FSV_WIRE * pWire) -{ - RCODE rc = FERR_OK; - RCODE opRc = FERR_OK; - FSV_SCTX * pServerContext = NULL; - FLMUNICODE * puzSourcePath; - char szSourcePath[ F_PATH_MAX_SIZE]; - - /* - Set up local variables. - */ - - if( RC_BAD( opRc = fsvGetGlobalContext( &pServerContext))) - { - goto OP_EXIT; - } - - puzSourcePath = pWire->getFilePath(); - if( puzSourcePath) - { - /* - Convert the UNICODE URL to a server path. - */ - - if( RC_BAD( rc = pServerContext->BuildFilePath( - puzSourcePath, szSourcePath))) - { - goto Exit; - } - } - - /* - Service the request. - */ - - switch( pWire->getOp()) - { - case FCS_OP_FILE_EXISTS: - { - if( !puzSourcePath) - { - opRc = RC_SET( FERR_SYNTAX); - goto OP_EXIT; - } - - if( RC_BAD( opRc = gv_FlmSysData.pFileSystem->Exists( szSourcePath))) - { - goto OP_EXIT; - } - - break; - } - - case FCS_OP_FILE_DELETE: - { - if( !puzSourcePath) - { - opRc = RC_SET( FERR_SYNTAX); - goto OP_EXIT; - } - - if( RC_BAD( opRc = - gv_FlmSysData.pFileSystem->Delete( szSourcePath))) - { - goto OP_EXIT; - } - - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_FILE, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Performs an administrative operation -*****************************************************************************/ -RCODE fsvOpClassAdmin( - FSV_WIRE * pWire) -{ - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Service the request. - */ - -// switch( pWire->getOp()) -// { -// default: -// { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; -// } -// } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_ADMIN, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a global operation -*****************************************************************************/ -RCODE fsvOpClassGlobal( - FSV_WIRE * pWire) -{ - FSV_SCTX * pServerContext; - NODE * pTree = NULL; - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Service the request. - */ - - if( RC_BAD( rc = fsvGetGlobalContext( &pServerContext))) - { - goto Exit; - } - - switch( pWire->getOp()) - { - case FCS_OP_GLOBAL_STATS_START: - { - if( RC_BAD( opRc = FlmConfig( FLM_START_STATS, 0, 0))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GLOBAL_STATS_STOP: - { - if( RC_BAD( opRc = FlmConfig( FLM_STOP_STATS, 0, 0))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GLOBAL_STATS_RESET: - { - if( RC_BAD( opRc = FlmConfig( FLM_RESET_STATS, 0, 0))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GLOBAL_MEM_INFO_GET: - { - FLM_MEM_INFO memInfo; - - FlmGetMemoryInfo( &memInfo); - if( RC_BAD( opRc = fcsBuildMemInfo( &memInfo, - pWire->getPool(), &pTree))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GLOBAL_GET_THREAD_INFO: - { - if( RC_BAD( opRc = fcsBuildThreadInfo( - pWire->getPool(), &pTree))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_GLOBAL, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - if( pTree) - { - if( RC_BAD( rc = pWire->sendHTD( WIRE_VALUE_HTD, pTree))) - { - goto Exit; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a session operation -*****************************************************************************/ -RCODE fsvOpClassSession( - FSV_WIRE * pWire) -{ - FLMUINT uiSessionIdRV; - FSV_SCTX * pServerContext; - FSV_SESN * pSession = NULL; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - -#ifdef FSV_LOGGING - szLogBuf[ 0] = '\0'; -#endif - - /* - Service the request. - */ - - if( RC_BAD( opRc = fsvGetGlobalContext( &pServerContext))) - { - goto OP_EXIT; - } - - switch( pWire->getOp()) - { - case FCS_OP_SESSION_OPEN: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "SessionOpen: CV = %8.8X, FL = %8.8X", - (unsigned)pWire->getClientVersion(), - (unsigned)pWire->getFlags()); -#endif - - /* - Create a new session. - */ - - if( RC_BAD( opRc = pServerContext->OpenSession( - pWire->getClientVersion(), pWire->getFlags(), - &uiSessionIdRV, &pSession))) - { - goto OP_EXIT; - } - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "SessionOpen: ID = %8.8X, CV = %8.8X, FL = %8.8X", - (unsigned)uiSessionIdRV, - (unsigned)pWire->getClientVersion(), - (unsigned)pWire->getFlags()); -#endif - - break; - } - - case FCS_OP_SESSION_CLOSE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "SessionClose: ID = %8.8X", - (unsigned)pWire->getSessionId()); -#endif - - /* - Close the session. - */ - - if( RC_BAD( opRc = - pServerContext->CloseSession( pWire->getSessionId()))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_SESSION, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - if( pWire->getOp() == FCS_OP_SESSION_OPEN) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_SESSION_ID, uiSessionIdRV))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_SESSION_COOKIE, - pSession->getCookie()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_FLAGS, - FCS_SESSION_GEDCOM_SUPPORT))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_FLAIM_VERSION, - FLM_CURRENT_VERSION_NUM))) - { - goto Exit; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a record or DRN operation -*****************************************************************************/ -RCODE fsvOpClassRecord( - FSV_WIRE * pWire) -{ - FSV_SESN * pSession; - HFDB hDb; - FLMUINT uiContainer; - FLMUINT uiIndex; - FLMUINT uiAutoTrans; - FLMUINT uiDrn; - FLMUINT uiFlags; - FlmRecord * pRecord = NULL; - FlmRecord * pRecordRV = NULL; - FLMUINT uiDrnRV = 0; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - -#ifdef FSV_LOGGING - szLogBuf[ 0] = 0; -#endif - - /* - Get a pointer to the session object. - */ - - if( (pSession = pWire->getSession()) == NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - /* - Get the database handle. This is needed by all of the - record operations. - */ - - if( (hDb = (HFDB)pWire->getFDB()) == HFDB_NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - /* - Initialize local variables. - */ - - uiContainer = pWire->getContainerId(); - uiIndex = pWire->getIndexId(); - uiDrn = pWire->getDrn(); - uiAutoTrans = pWire->getAutoTrans(); - uiFlags = pWire->getFlags(); - pRecord = pWire->getRecord(); - - /* - Perform the operation. - */ - - switch( pWire->getOp()) - { - case FCS_OP_RECORD_RETRIEVE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "RecRtrv: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrn); -#endif - if( !uiFlags) - { - uiFlags = FO_EXACT; - } - - if( pWire->getBoolean()) - { - /* - Fetch the record - */ - - if( RC_BAD( opRc = FlmRecordRetrieve( hDb, - uiContainer, uiDrn, uiFlags, &pRecordRV, &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - /* - Just get the DRN - */ - - if( RC_BAD( opRc = FlmRecordRetrieve( hDb, - uiContainer, uiDrn, uiFlags, NULL, &uiDrnRV))) - { - goto OP_EXIT; - } - } - break; - } - - case FCS_OP_RECORD_ADD: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "RecAdd: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrn); -#endif - - uiDrnRV = uiDrn; - if( RC_BAD( opRc = FlmRecordAdd( hDb, - uiContainer, - &uiDrnRV, - pRecord, - uiAutoTrans))) - { - goto OP_EXIT; - } - -#ifdef FSV_LOGGING - /* - Need to change the log buffer after the operation so that - it correctly represents the outcome of the operation. - */ - - f_sprintf( szLogBuf, - "RecAdd: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrnRV); -#endif - - break; - } - - case FCS_OP_RECORD_MODIFY: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "RecMod: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrn); -#endif - - if( RC_BAD( opRc = FlmRecordModify( hDb, - uiContainer, - uiDrn, - pRecord, - uiAutoTrans))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_RECORD_DELETE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "RecDel: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrn); -#endif - - if( RC_BAD( opRc = FlmRecordDelete( hDb, - uiContainer, - uiDrn, - uiAutoTrans))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_RESERVE_NEXT_DRN: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "ResDRN: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrn); -#endif - - uiDrnRV = uiDrn; - if( RC_BAD( opRc = FlmReserveNextDrn( hDb, - uiContainer, - &uiDrnRV))) - { - goto OP_EXIT; - } - -#ifdef FSV_LOGGING - /* - Need to change the log buffer after the operation so that - it correctly represents the outcome of the operation. - */ - - f_sprintf( szLogBuf, - "RecAdd: CO = %4.4X, DRN = %8.8X", - (unsigned)uiContainer, (unsigned)uiDrnRV); -#endif - - break; - } - - case FCS_OP_KEY_RETRIEVE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "KeyRtrv: IX=%04X, CO=%04X, DRN=%08X", - (unsigned)uiIndex, (unsigned)uiContainer, (unsigned)uiDrn); -#endif - - if (pSession->getClientVersion() >= FCS_VERSION_1_1_1) - { - if( RC_BAD( opRc = FlmKeyRetrieve( hDb, - uiIndex, - uiContainer, - pRecord, - uiDrn, - uiFlags, - &pRecordRV, - &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - FLMUINT uiKeyContainer = 0; - - if (pRecord) - { - uiKeyContainer = pRecord->getContainerID(); - } - - // Older clients sent index # in the container tag. - - if( RC_BAD( opRc = FlmKeyRetrieve( hDb, - uiContainer, - uiKeyContainer, - pRecord, - uiDrn, - uiFlags, - &pRecordRV, - &uiDrnRV))) - { - goto OP_EXIT; - } - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_RECORD, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - if( pRecordRV) - { - if( RC_BAD( rc = pWire->sendRecord( WIRE_VALUE_RECORD, pRecordRV))) - { - goto Exit; - } - } - - if( uiDrnRV) - { - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_DRN, uiDrnRV))) - { - goto Exit; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - if( pRecordRV) - { - pRecordRV->Release(); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a database operation. -*****************************************************************************/ -RCODE fsvOpClassDatabase( - FSV_WIRE * pWire) -{ - RCODE rc = FERR_OK; - RCODE opRc = FERR_OK; - FSV_SESN * pSession; - HFDB hDb = HFDB_NULL; - CREATE_OPTS CreateOptsRV; - FLMUINT uiBlockCountRV = 0; - FLMUINT uiBlocksExaminedRV = 0; - FLMUINT uiBlockAddrRV = 0; - FLMUINT uiTransIdRV; - FLMUINT64 ui64NumValue1RV = 0; - FLMUINT64 ui64NumValue2RV = 0; - FLMUINT64 ui64NumValue3RV = 0; - FLMBOOL bBoolValueRV = FALSE; - FLMUINT uiItemIdRV = 0; - char szItemName[ 64]; - NODE * pHTDRV = NULL; - char szPathRV[ F_PATH_MAX_SIZE]; - F_NameTable nameTable; - FLMBOOL bHaveCreateOptsVal = FALSE; - FLMBOOL bHavePathValue = FALSE; - FLMBYTE * pBinary = NULL; - FLMUINT uiBinSize = 0; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - -#ifdef FSV_LOGGING - szLogBuf[ 0] = 0; -#endif - szItemName[ 0] = 0; - - if( (pSession = pWire->getSession()) == NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - if( pWire->getOp() != FCS_OP_DATABASE_OPEN && - pWire->getOp() != FCS_OP_DATABASE_CREATE) - { - /* - Get the database handle for all database operations other - than open and create. - */ - - if( (hDb = (HFDB)pWire->getFDB()) == HFDB_NULL) - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "Invalid database handle."); -#endif - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - } - - switch( pWire->getOp()) - { - case FCS_OP_DATABASE_OPEN: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DBOpen"); -#endif - - if( RC_BAD( opRc = pSession->OpenDatabase( - pWire->getFilePath(), - pWire->getFilePath3(), - pWire->getFilePath2(), - pWire->getFlags()))) - { - goto OP_EXIT; - } - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DBOpen"); -#endif - break; - } - - case FCS_OP_DATABASE_CREATE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DBCreate"); -#endif - CREATE_OPTS createOpts; - pWire->copyCreateOpts( &createOpts); - - if( RC_BAD( opRc = pSession->CreateDatabase( - pWire->getFilePath(), - pWire->getFilePath3(), - pWire->getFilePath2(), - pWire->getDictPath(), - pWire->getDictBuffer(), - &createOpts))) - { - goto OP_EXIT; - } - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DBCreate"); -#endif - break; - } - - case FCS_OP_DATABASE_CLOSE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DBClose"); -#endif - - if( RC_BAD( opRc = pSession->CloseDatabase())) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DB_REDUCE_SIZE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "DbReduce: BL = %8.8X", (unsigned)pWire->getCount()); -#endif - if( RC_BAD( opRc = FlmDbReduceSize( - hDb, - (FLMUINT)pWire->getCount(), - &uiBlockCountRV))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GET_ITEM_NAME: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "GetItemName: ID = %4.4X", (unsigned)pWire->getItemId()); -#endif - - if( RC_BAD( opRc = FlmGetItemName( hDb, - pWire->getItemId(), sizeof( szItemName), szItemName))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GET_NAME_TABLE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "GetNameTable"); -#endif - if( RC_BAD( rc = nameTable.setupFromDb( hDb))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GET_COMMIT_CNT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbGetCommitCnt"); -#endif - if( RC_BAD( opRc = FlmDbGetCommitCnt( - hDb, - &uiBlockCountRV))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_GET_TRANS_ID: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbGetTransId"); -#endif - if( RC_BAD( opRc = FlmDbGetTransId( - hDb, &uiTransIdRV))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DATABASE_GET_CONFIG: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "DBGetConfig: TY = %8.8X", (unsigned)pWire->getType()); -#endif - switch( (eDbGetConfigType)pWire->getType()) - { - case FDB_GET_VERSION: - - // Doing via create opts to maintain backward compatibility. - - f_memset( &CreateOptsRV, 0, sizeof( CreateOptsRV)); - if( RC_BAD( opRc = FlmDbGetConfig( hDb, - FDB_GET_VERSION, - (void *)&CreateOptsRV.uiVersionNum))) - { - goto OP_EXIT; - } - bHaveCreateOptsVal = TRUE; - break; - case FDB_GET_BLKSIZ: - - // Doing via create opts to maintain backward compatibility. - - f_memset( &CreateOptsRV, 0, sizeof( CreateOptsRV)); - if( RC_BAD( opRc = FlmDbGetConfig( hDb, - FDB_GET_BLKSIZ, - (void *)&CreateOptsRV.uiBlockSize))) - { - goto OP_EXIT; - } - bHaveCreateOptsVal = TRUE; - break; - case FDB_GET_DEFAULT_LANG: - - // Doing via create opts to maintain backward compatibility. - - f_memset( &CreateOptsRV, 0, sizeof( CreateOptsRV)); - if( RC_BAD( opRc = FlmDbGetConfig( hDb, - FDB_GET_DEFAULT_LANG, - (void *)&CreateOptsRV.uiDefaultLanguage))) - { - goto OP_EXIT; - } - bHaveCreateOptsVal = TRUE; - break; - - case FDB_GET_TRANS_ID: - case FDB_GET_RFL_FILE_NUM: - case FDB_GET_RFL_HIGHEST_NU: - case FDB_GET_LAST_BACKUP_TRANS_ID: - case FDB_GET_BLOCKS_CHANGED_SINCE_BACKUP: - case FDB_GET_FILE_EXTEND_SIZE: - case FDB_GET_APP_DATA: - { - FLMUINT uiTmpValue; - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, (eDbGetConfigType)pWire->getType(), (void *)&uiTmpValue))) - { - goto OP_EXIT; - } - ui64NumValue1RV = (FLMUINT64)uiTmpValue; - break; - } - case FDB_GET_RFL_FILE_SIZE_LIMITS: - { - FLMUINT uiTmpValue1; - FLMUINT uiTmpValue2; - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_RFL_FILE_SIZE_LIMITS, - (void *)&uiTmpValue1, - (void *)&uiTmpValue2))) - { - goto OP_EXIT; - } - ui64NumValue1RV = (FLMUINT64)uiTmpValue1; - ui64NumValue2RV = (FLMUINT64)uiTmpValue2; - break; - } - - case FDB_GET_RFL_KEEP_FLAG: - case FDB_GET_AUTO_TURN_OFF_KEEP_RFL_FLAG: - case FDB_GET_KEEP_ABORTED_TRANS_IN_RFL_FLAG: - { - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, (eDbGetConfigType)pWire->getType(), (void *)&bBoolValueRV))) - { - goto OP_EXIT; - } - break; - } - - case FDB_GET_PATH: - { - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_PATH, - (void *)szPathRV))) - { - goto OP_EXIT; - } - bHavePathValue = TRUE; - break; - } - - case FDB_GET_CHECKPOINT_INFO: - { - CHECKPOINT_INFO checkpointInfo; - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_CHECKPOINT_INFO, - (void *)&checkpointInfo))) - { - goto OP_EXIT; - } - - if( RC_BAD( opRc = fcsBuildCheckpointInfo( - &checkpointInfo, pWire->getPool(), &pHTDRV))) - { - goto OP_EXIT; - } - break; - } - - case FDB_GET_LOCK_HOLDER: - { - LOCK_USER lockUser; - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_LOCK_HOLDER, - (void *)&lockUser))) - { - goto OP_EXIT; - } - - if( RC_BAD( opRc = fcsBuildLockUser( - &lockUser, FALSE, pWire->getPool(), &pHTDRV))) - { - goto OP_EXIT; - } - break; - } - - case FDB_GET_LOCK_WAITERS: - { - LOCK_USER * pLockUser = NULL; - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_LOCK_WAITERS, - (void *)&pLockUser))) - { - if( pLockUser) - { - FlmFreeMem( &pLockUser); - } - goto OP_EXIT; - } - - if( RC_BAD( opRc = fcsBuildLockUser( - pLockUser, TRUE, pWire->getPool(), &pHTDRV))) - { - if( pLockUser) - { - FlmFreeMem( &pLockUser); - } - goto OP_EXIT; - } - - if( pLockUser) - { - FlmFreeMem( &pLockUser); - } - break; - } - - case FDB_GET_RFL_DIR: - { - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_RFL_DIR, - (void *)szPathRV))) - { - goto OP_EXIT; - } - bHavePathValue = TRUE; - break; - } - - case FDB_GET_SERIAL_NUMBER: - { - uiBinSize = F_SERIAL_NUM_SIZE; - - pBinary = (FLMBYTE *)GedPoolAlloc( pWire->getPool(), - uiBinSize); - - if( !pBinary) - { - opRc = RC_SET( FERR_MEM); - goto OP_EXIT; - } - - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_SERIAL_NUMBER, - (void *)pBinary))) - { - goto OP_EXIT; - } - break; - } - - case FDB_GET_SIZES: - { - if( RC_BAD( opRc = FlmDbGetConfig( - hDb, FDB_GET_SIZES, - (void *)&ui64NumValue1RV, - (void *)&ui64NumValue2RV, - (void *)&ui64NumValue3RV))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - - break; - } - - case FCS_OP_DATABASE_CONFIG: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "DBConfig: TY = %8.8X", (unsigned)pWire->getType()); -#endif - switch( (eDbConfigType)pWire->getType()) - { - case FDB_SET_APP_VERSION: - case FDB_RFL_KEEP_FILES: - case FDB_RFL_ROLL_TO_NEXT_FILE: - case FDB_KEEP_ABORTED_TRANS_IN_RFL: - case FDB_AUTO_TURN_OFF_KEEP_RFL: - case FDB_SET_APP_DATA: - if( RC_BAD( opRc = FlmDbConfig( hDb, (eDbConfigType)pWire->getType(), - (void *)((FLMUINT)pWire->getNumber2()), - (void *)((FLMUINT)pWire->getNumber3())))) - { - goto OP_EXIT; - } - break; - case FDB_RFL_FILE_LIMITS: - case FDB_FILE_EXTEND_SIZE: - case FDB_ENABLE_FIELD_ID_TABLE: - if( RC_BAD( opRc = FlmDbConfig( hDb, (eDbConfigType)pWire->getType(), - (void *)((FLMUINT)pWire->getNumber1()), - (void *)((FLMUINT)pWire->getNumber2())))) - { - goto OP_EXIT; - } - break; - - case FDB_RFL_DIR: - { - char * pszPath; - POOL * pPool = pWire->getPool(); - void * pvMark = GedPoolMark( pPool); - - if( RC_BAD( rc = fcsConvertUnicodeToNative( pPool, - pWire->getFilePath(), &pszPath))) - { - goto Exit; - } - - if( RC_BAD( opRc = FlmDbConfig( hDb, (eDbConfigType)pWire->getType(), - (void *)pszPath, (void *)((FLMUINT)pWire->getNumber3())))) - { - goto OP_EXIT; - } - - GedPoolReset( pPool, pvMark); - break; - } - - default: - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - - break; - } - - case FCS_OP_DATABASE_LOCK: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbLock"); -#endif - if( RC_BAD( opRc = FlmDbLock( - hDb, - (FLOCK_TYPE)(FLMUINT)pWire->getNumber1(), - (FLMINT)pWire->getSignedValue(), - (FLMUINT)pWire->getFlags()))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DATABASE_UNLOCK: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbUnlock"); -#endif - if( RC_BAD( opRc = FlmDbUnlock( hDb))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DATABASE_GET_BLOCK: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbGetBlock"); -#endif - uiBlockCountRV = (FLMUINT)pWire->getCount(); - if( RC_BAD( opRc = fsvDbGetBlocks( hDb, pWire->getAddress(), - pWire->getTransId(), - &uiBlockCountRV, &uiBlocksExaminedRV, &uiBlockAddrRV, - pWire->getFlags(), pWire->getPool(), &pBinary, &uiBinSize))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DATABASE_CHECKPOINT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "DbCheckpoint"); -#endif - if( RC_BAD( opRc = FlmDbCheckpoint( - hDb, - pWire->getFlags() /* timeout */))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_DB_SET_BACKUP_FLAG: - { - FLMBOOL bNewState = pWire->getBoolean(); - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "SetBackupFlag"); -#endif - if( !IsInCSMode( hDb)) - { - FDB * pDb = (FDB *)hDb; - - f_mutexLock( gv_FlmSysData.hShareMutex); - if( pDb->pFile->bBackupActive && bNewState) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - opRc = RC_SET( FERR_BACKUP_ACTIVE); - goto OP_EXIT; - } - pDb->pFile->bBackupActive = bNewState; - f_mutexUnlock( gv_FlmSysData.hShareMutex); - } - else - { - if( RC_BAD( opRc = fcsSetBackupActiveFlag( - hDb, bNewState))) - { - goto OP_EXIT; - } - } - - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( - FCS_OPCLASS_DATABASE, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - switch( pWire->getOp()) - { - case FCS_OP_DB_REDUCE_SIZE: - case FCS_OP_GET_COMMIT_CNT: - { - /* - Return a count - */ - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_COUNT, - uiBlockCountRV))) - { - goto Exit; - } - break; - } - - case FCS_OP_GET_NAME_TABLE: - { - /* - Return the name table. - */ - - if( RC_OK( opRc)) - { - if( RC_BAD( rc = pWire->sendNameTable( - WIRE_VALUE_NAME_TABLE, &nameTable))) - { - goto Exit; - } - } - break; - } - - case FCS_OP_GET_ITEM_NAME: - { - FLMUNICODE * puzItemNameRV; - - if( RC_OK( opRc)) - { - if( szItemName[ 0]) - { - if( RC_BAD( rc = fcsConvertNativeToUnicode( - pWire->getPool(), szItemName, &puzItemNameRV))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendString( - WIRE_VALUE_ITEM_NAME, puzItemNameRV))) - { - goto Exit; - } - } - } - break; - } - - case FCS_OP_GET_ITEM_ID: - { - if( uiItemIdRV) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_ITEM_ID, uiItemIdRV))) - { - goto Exit; - } - } - break; - } - - case FCS_OP_GET_TRANS_ID: - { - /* - Return the transaction id for the database. - */ - - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_TRANSACTION_ID, uiTransIdRV))) - { - goto Exit; - } - break; - } - - case FCS_OP_DATABASE_GET_BLOCK: - { - /* - Return the requested block - */ - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_COUNT, - uiBlockCountRV))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_NUMBER2, - uiBlocksExaminedRV))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_ADDRESS, - uiBlockAddrRV))) - { - goto Exit; - } - - if( uiBlockCountRV) - { - if( RC_BAD( rc = pWire->sendBinary( - WIRE_VALUE_BLOCK, pBinary, uiBinSize))) - { - goto Exit; - } - } - - break; - } - - case FCS_OP_DATABASE_GET_CONFIG: - { - switch( pWire->getType()) - { - case FDB_GET_SERIAL_NUMBER: - if( RC_BAD( rc = pWire->sendBinary( - WIRE_VALUE_SERIAL_NUM, pBinary, uiBinSize))) - { - goto Exit; - } - break; - default: - break; - } - break; - } - } - - if( bHaveCreateOptsVal) - { - if( RC_BAD( rc = pWire->sendCreateOpts( - WIRE_VALUE_CREATE_OPTS, &CreateOptsRV))) - { - goto Exit; - } - } - - if( ui64NumValue1RV) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_NUMBER1, ui64NumValue1RV))) - { - goto Exit; - } - } - - if( ui64NumValue2RV) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_NUMBER2, ui64NumValue2RV))) - { - goto Exit; - } - } - - if( ui64NumValue3RV) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_NUMBER3, ui64NumValue3RV))) - { - goto Exit; - } - } - - if( bBoolValueRV) - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_BOOLEAN, bBoolValueRV))) - { - goto Exit; - } - } - - if( bHavePathValue) - { - FLMUNICODE * puzPath; - - if( RC_BAD( rc = fcsConvertNativeToUnicode( pWire->getPool(), - szPathRV, &puzPath))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendString( - WIRE_VALUE_FILE_PATH, puzPath))) - { - goto Exit; - } - } - - if( pHTDRV) - { - if( RC_BAD( rc = pWire->sendHTD( WIRE_VALUE_HTD, pHTDRV))) - { - goto Exit; - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - return( rc); -} - - -/**************************************************************************** -Desc: Performs an iterator (cursor) operation -*****************************************************************************/ -RCODE fsvOpClassIterator( - FSV_WIRE * pWire) -{ - RCODE rc = FERR_OK; - RCODE opRc = FERR_OK; - FSV_SESN * pSession = NULL; - HFCURSOR hIterator = HFCURSOR_NULL; - FLMBOOL bDoDrnOp = FALSE; - FlmRecord * pRecordRV = NULL; - FlmRecord * pTmpRecord = NULL; - FLMUINT uiIteratorIdRV = FCS_INVALID_ID; - FLMUINT uiCountRV = 0; - FLMUINT uiDrnRV = 0; - FLMBOOL bFlag = FALSE; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - -#ifdef FSV_LOGGING - szLogBuf[ 0] = 0; -#endif - - /* - Get a pointer to the session object. - */ - - if( (pSession = pWire->getSession()) == NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - /* - Get the iterator handle. - */ - - if( (hIterator = pWire->getIteratorHandle()) == HFDB_NULL) - { - if( pWire->getOp() != FCS_OP_ITERATOR_INIT) - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "Invalid iterator handle."); -#endif - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - } - - /* - Examine the wire flags for the operation. - */ - - bDoDrnOp = (FLMBOOL)((pWire->getFlags() & FCS_ITERATOR_DRN_FLAG) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE); - - /* - Perform the requested operation. - */ - - switch( pWire->getOp()) - { - case FCS_OP_ITERATOR_INIT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorInit"); -#endif - - /* - Build the query. - */ - - if( RC_BAD( opRc = fsvIteratorParse( pWire, pWire->getPool()))) - { - goto OP_EXIT; - } - uiIteratorIdRV = pWire->getIteratorId(); - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorInit: ID = %8.8X", - (unsigned)uiIteratorIdRV); -#endif - break; - } - - case FCS_OP_ITERATOR_FREE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorFree: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - /* - Free the iterator. - */ - - if( RC_BAD( opRc = pSession->FreeIterator( pWire->getIteratorId()))) - { - goto OP_EXIT; - } - - break; - } - - case FCS_OP_ITERATOR_FIRST: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorFirst: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - - /* - Retrieve the first record (or DRN) in the result set. - */ - - if( bDoDrnOp) - { - if( RC_BAD( opRc = FlmCursorFirstDRN( hIterator, &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - if( RC_BAD( opRc = FlmCursorFirst( hIterator, &pRecordRV))) - { - goto OP_EXIT; - } - } - break; - } - - case FCS_OP_ITERATOR_LAST: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorLast: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - - /* - Retrieve the last record (or DRN) in the result set. - */ - - if( bDoDrnOp) - { - if( RC_BAD( opRc = FlmCursorLastDRN( hIterator, &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - if( RC_BAD( opRc = FlmCursorLast( hIterator, &pRecordRV))) - { - goto OP_EXIT; - } - } - break; - } - - case FCS_OP_ITERATOR_NEXT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorNext: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - - /* - Retrieve the next record (or DRN) in the result set. - */ - - if( bDoDrnOp) - { - if( RC_BAD( opRc = FlmCursorNextDRN( hIterator, &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - if( RC_BAD( opRc = FlmCursorNext( hIterator, &pRecordRV))) - { - goto OP_EXIT; - } - } - break; - } - - case FCS_OP_ITERATOR_PREV: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorPrev: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - - /* - Retrieve the previous record (or DRN) in the result set. - */ - - if( bDoDrnOp) - { - if( RC_BAD( opRc = FlmCursorPrevDRN( hIterator, &uiDrnRV))) - { - goto OP_EXIT; - } - } - else - { - if( RC_BAD( opRc = FlmCursorPrev( hIterator, &pRecordRV))) - { - goto OP_EXIT; - } - } - break; - } - - case FCS_OP_ITERATOR_COUNT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorCount: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - - /* - Count the number of records in the result set. - */ - - if( RC_BAD( opRc = FlmCursorRecCount( hIterator, &uiCountRV))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_ITERATOR_TEST_REC: - { - if ((pTmpRecord = pWire->getRecord()) != NULL) - { - pTmpRecord->AddRef(); - -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorTestRec: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - if( RC_BAD( opRc = FlmCursorTestRec( hIterator, pTmpRecord, &bFlag))) - { - goto OP_EXIT; - } - pTmpRecord->Release(); - pTmpRecord = NULL; - } - else - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "IteratorTestDRN: ID = %8.8X", - (unsigned)pWire->getIteratorId()); -#endif - if( RC_BAD( opRc = FlmCursorTestDRN( hIterator, pWire->getDrn(), - &bFlag))) - { - goto OP_EXIT; - } - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_ITERATOR, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - if( pRecordRV) - { - /* - Send the retrieved record. - */ - - if( RC_BAD( rc = pWire->sendRecord( WIRE_VALUE_RECORD, pRecordRV))) - { - goto Exit; - } - } - - if( uiDrnRV) - { - /* - Send the record's DRN. - */ - - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_DRN, uiDrnRV))) - { - goto Exit; - } - } - - if( uiCountRV) - { - /* - Send the record count. - */ - - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_RECORD_COUNT, uiCountRV))) - { - goto Exit; - } - } - - if( uiIteratorIdRV != FCS_INVALID_ID) - { - /* - Send the iterator's ID. - */ - - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_ITERATOR_ID, uiIteratorIdRV))) - { - goto Exit; - } - } - - if (bFlag) - { - if( RC_BAD( rc = pWire->sendNumber( WIRE_VALUE_BOOLEAN, bFlag))) - { - goto Exit; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - if( pRecordRV) - { - pRecordRV->Release(); - } - - if( pTmpRecord) - { - pTmpRecord->Release(); - pTmpRecord = NULL; - } - - return( rc); -} - -/**************************************************************************** -Desc: Performs a transaction operation -*****************************************************************************/ -RCODE fsvOpClassTransaction( - FSV_WIRE * pWire) -{ - RCODE rc = FERR_OK; - RCODE opRc = FERR_OK; - FSV_SESN * pSession; - HFDB hDb; - FLMUINT uiTransTypeRV; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - FLMBYTE * pBlock = NULL; - FLMUINT uiBlockSize = 0; - FLMUINT uiFlmTransFlags = 0; - -#ifdef FSV_LOGGING - szLogBuf[ 0] = 0; -#endif - - /* - Get a pointer to the session object. - */ - - if( (pSession = pWire->getSession()) == NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - /* - Get a handle to the database in case this is a - database transaction operation - */ - - hDb = (HFDB)pWire->getFDB(); - - /* - Perform the requested operation. - */ - - switch( pWire->getOp()) - { - case FCS_OP_TRANSACTION_BEGIN: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "TransBegin: TT = %8.8X", (unsigned)pWire->getTransType()); -#endif - /* - Start a database transaction. - */ - - if( pWire->getFlags() & FCS_TRANS_FLAG_GET_HEADER) - { - uiBlockSize = 2048; - if( (pBlock = (FLMBYTE *)GedPoolAlloc( - pWire->getPool(), uiBlockSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto OP_EXIT; - } - } - - if( pWire->getFlags() & FCS_TRANS_FLAG_DONT_KILL) - { - uiFlmTransFlags |= FLM_DONT_KILL_TRANS; - } - - if( pWire->getFlags() & FCS_TRANS_FLAG_DONT_POISON) - { - uiFlmTransFlags |= FLM_DONT_POISON_CACHE; - } - - if( RC_BAD( opRc = FlmDbTransBegin( hDb, - pWire->getTransType() | uiFlmTransFlags, - pWire->getMaxLockWait(), pBlock))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_TRANSACTION_COMMIT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "TransCommit"); -#endif - /* - Commit a database transaction. - */ - - if( RC_BAD( opRc = FlmDbTransCommit( hDb))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_TRANSACTION_COMMIT_EX: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "TransCommitEx"); -#endif - /* - Commit a database transaction. - */ - - if( RC_BAD( opRc = fsvDbTransCommitEx( hDb, pWire))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_TRANSACTION_ABORT: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "TransAbort"); -#endif - /* - Abort a database transaction. - */ - - if( RC_BAD( opRc = FlmDbTransAbort( hDb))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_TRANSACTION_GET_TYPE: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "GetTransType"); -#endif - /* - Get the database transaction type. - */ - - if( RC_BAD( opRc = FlmDbGetTransType( hDb, &uiTransTypeRV))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( - FCS_OPCLASS_TRANS, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( pBlock) - { - if( RC_BAD( rc = pWire->sendBinary( - WIRE_VALUE_BLOCK, pBlock, uiBlockSize))) - { - goto Exit; - } - } - - if( RC_OK( opRc)) - { - switch( pWire->getOp()) - { - case FCS_OP_TRANSACTION_GET_TYPE: - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_TRANSACTION_TYPE, uiTransTypeRV))) - { - goto Exit; - } - break; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a maintenance operation. -*****************************************************************************/ -RCODE fsvOpClassMaintenance( - FSV_WIRE * pWire) -{ - FSV_SESN * pSession; - HFDB hDb; - POOL pool; -#ifdef FSV_LOGGING - char szLogBuf[ FSV_LOG_BUFFER_SIZE]; -#endif - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Initialize a temporary pool. - */ - - GedPoolInit( &pool, 1024); - - /* - Initialize local variables. - */ - -#ifdef FSV_LOGGING - szLogBuf[ 0] = '\0'; -#endif - - /* - Service the request. - */ - - if( (pSession = pWire->getSession()) == NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - if( (hDb = (HFDB)pWire->getFDB()) == HFDB_NULL) - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, - "Invalid database handle."); -#endif - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - switch( pWire->getOp()) - { - case FCS_OP_CHECK: - { -#ifdef FSV_LOGGING - f_sprintf( szLogBuf, "Check"); -#endif - - if( RC_BAD( opRc = FlmDbCheck( hDb, NULL, NULL, NULL, - pWire->getFlags(), &pool, NULL, NULL, 0))) - { - goto OP_EXIT; - } - - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( - FCS_OPCLASS_MAINTENANCE, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - switch( pWire->getOp()) - { - case FCS_OP_CHECK: - { - break; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, szLogBuf, opRc ? opRc : rc, FSV_LOG_EVENT); -#endif - - return( rc); -} - - -/**************************************************************************** -Desc: Performs an index operation -*****************************************************************************/ -RCODE fsvOpClassIndex( - FSV_WIRE * pWire) -{ - HFDB hDb = HFDB_NULL; - FLMUINT uiIndex; - FINDEX_STATUS indexStatus; - POOL * pTmpPool = pWire->getPool(); - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Get the database handle. This is needed by all of the - index operations. - */ - - if( (hDb = (HFDB)pWire->getFDB()) == HFDB_NULL) - { - opRc = RC_SET( FERR_BAD_HDL); - goto OP_EXIT; - } - - /* - Initialize local variables. - */ - - uiIndex = pWire->getIndexId(); - - /* - Service the request. - */ - - switch( pWire->getOp()) - { - case FCS_OP_INDEX_GET_STATUS: - { - if( RC_BAD( opRc = FlmIndexStatus( hDb, uiIndex, &indexStatus))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_INDEX_GET_NEXT: - { - if( RC_BAD( opRc = FlmIndexGetNext( hDb, &uiIndex))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_INDEX_SUSPEND: - { - if( RC_BAD( opRc = FlmIndexSuspend( hDb, uiIndex))) - { - goto OP_EXIT; - } - break; - } - - case FCS_OP_INDEX_RESUME: - { - if( RC_BAD( opRc = FlmIndexResume( hDb, uiIndex))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_INDEX, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - switch( pWire->getOp()) - { - case FCS_OP_INDEX_GET_STATUS: - { - NODE * pStatusTree; - - if( RC_BAD( fcsBuildIndexStatus( &indexStatus, - pTmpPool, &pStatusTree))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendHTD( WIRE_VALUE_HTD, pStatusTree))) - { - goto Exit; - } - break; - } - - case FCS_OP_INDEX_GET_NEXT: - { - if( RC_BAD( rc = pWire->sendNumber( - WIRE_VALUE_INDEX_ID, uiIndex))) - { - goto Exit; - } - break; - } - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Performs a misc. operation -*****************************************************************************/ -RCODE fsvOpClassMisc( - FSV_WIRE * pWire) -{ - FLMBYTE ucSerialNum[ F_SERIAL_NUM_SIZE]; - RCODE opRc = FERR_OK; - RCODE rc = FERR_OK; - - /* - Service the request. - */ - - switch( pWire->getOp()) - { - case FCS_OP_CREATE_SERIAL_NUM: - { - if( RC_BAD( opRc = f_createSerialNumber( ucSerialNum))) - { - goto OP_EXIT; - } - break; - } - - default: - { - opRc = RC_SET( FERR_NOT_IMPLEMENTED); - goto OP_EXIT; - } - } - - -OP_EXIT: - - /* - Send the server's response. - */ - - if( RC_BAD( rc = pWire->sendOpcode( FCS_OPCLASS_MISC, pWire->getOp()))) - { - goto Exit; - } - - if( RC_BAD( rc = pWire->sendRc( opRc))) - { - goto Exit; - } - - if( RC_OK( opRc)) - { - if( pWire->getOp() == FCS_OP_CREATE_SERIAL_NUM) - { - if( RC_BAD( rc = pWire->sendBinary( - WIRE_VALUE_SERIAL_NUM, - ucSerialNum, F_SERIAL_NUM_SIZE))) - { - goto Exit; - } - } - else - { - flmAssert( rc == FERR_NOT_IMPLEMENTED); - } - } - - if( RC_BAD( rc = pWire->sendTerminate())) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Configures an iterator based on from, where, select, and config - clauses provided by the client. -*****************************************************************************/ -FSTATIC RCODE fsvIteratorParse( - FSV_WIRE * pWire, - POOL * pPool) -{ - RCODE rc = FERR_OK; - - /* - Parse the "from" clause. This contains record source information. - */ - - if( pWire->getIteratorFrom()) - { - if( RC_BAD( rc = fsvIteratorFromParse( pWire, pPool))) - { - goto Exit; - } - } - if (pWire->getIteratorHandle() == HFCURSOR_NULL) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Parse the "where" clause. This contains the criteria. - */ - - if( pWire->getIteratorWhere()) - { - if( RC_BAD( rc = fsvIteratorWhereParse( pWire, pPool))) - { - goto Exit; - } - } - - /* - Parse the "select" clause. This contains customized view information. - */ - - if( pWire->getIteratorSelect()) - { - if( RC_BAD( rc = fsvIteratorSelectParse( pWire, pPool))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Adds selection criteria to an iterator. -*****************************************************************************/ -FSTATIC RCODE fsvIteratorWhereParse( - FSV_WIRE * pWire, - POOL * pPool) -{ - HFCURSOR hIterator = pWire->getIteratorHandle(); - NODE * pWhere = pWire->getIteratorWhere(); - NODE * pCurNode; - NODE * pTmpNode; - void * pPoolMark; - FLMUINT uiTag; - RCODE rc = FERR_OK; - - /* - If no "where" clause, jump to exit. - */ - - if( !pWhere) - { - goto Exit; - } - - /* - Process each component of the "where" clause. - */ - - pCurNode = GedChild( pWhere); - while( pCurNode) - { - uiTag = GedTagNum( pCurNode); - switch( uiTag) - { - case FCS_ITERATOR_MODE: - { - FLMUINT uiFlags = 0; - - /* - Set the iterator's mode flags - */ - - if( RC_BAD( rc = GedGetUINT( pCurNode, &uiFlags))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorSetMode( hIterator, uiFlags))) - { - goto Exit; - } - break; - } - - /* - Add an attribute to the criteria. - */ - - case FCS_ITERATOR_ATTRIBUTE: - { - FLMUINT uiAttrId; - - /* - Get the attribute ID. - */ - - if( RC_BAD( rc = GedGetUINT( pCurNode, &uiAttrId))) - { - goto Exit; - } - - /* - Add the attribute. - */ - - if( uiTag == FCS_ITERATOR_ATTRIBUTE) - { - if( RC_BAD( rc = FlmCursorAddField( hIterator, - uiAttrId, 0))) - { - goto Exit; - } - } - else - { - /* - Sanity check. - */ - - flmAssert( 0); - } - break; - } - - /* - Add an attribute path to the criteria. - */ - - case FCS_ITERATOR_ATTRIBUTE_PATH: - { - FLMUINT puiPath[ FCS_ITERATOR_MAX_PATH + 1]; - FLMUINT uiAttrId; - FLMUINT uiPathPos = 0; - FLMUINT uiStartLevel; - - if( (pTmpNode = GedFind( GED_TREE, pCurNode, - FCS_ITERATOR_ATTRIBUTE, 1)) != NULL) - { - /* - Build the attribute path. - */ - - uiStartLevel = GedNodeLevel( pTmpNode); - while( pTmpNode && GedNodeLevel( pTmpNode) >= uiStartLevel) - { - if( GedNodeLevel( pTmpNode) == uiStartLevel && - GedTagNum( pTmpNode) == FCS_ITERATOR_ATTRIBUTE) - { - if( RC_BAD( rc = GedGetUINT( pTmpNode, &uiAttrId))) - { - goto Exit; - } - - puiPath[ uiPathPos++] = uiAttrId; - if( uiPathPos > FCS_ITERATOR_MAX_PATH) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - pTmpNode = pTmpNode->next; - } - puiPath[ uiPathPos] = 0; - } - - /* - Add the attribute path. - */ - - if( RC_BAD( rc = FlmCursorAddFieldPath( hIterator, - puiPath, 0))) - { - goto Exit; - } - - break; - } - - /* - Add a numeric value to the criteria. - */ - - case FCS_ITERATOR_NUMBER_VALUE: - case FCS_ITERATOR_REC_PTR_VALUE: - { - /* - To save conversion time, cheat to determine if - the number is negative. - */ - - FLMBYTE * pucValue = (FLMBYTE *)GedValPtr( pCurNode); - FLMBOOL bNegative = ((*pucValue & 0xF0) == 0xB0) - ? (FLMBOOL)TRUE - : (FLMBOOL)FALSE; - - if( bNegative) - { - FLMINT32 i32Value; - - if( uiTag == FCS_ITERATOR_REC_PTR_VALUE) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - if( RC_BAD( rc = GedGetINT32( pCurNode, &i32Value))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_INT32_VAL, &i32Value, 0))) - { - goto Exit; - } - } - else - { - FLMUINT32 ui32Value; - FLMUINT uiValue; - - if( RC_BAD( rc = GedGetUINT32( pCurNode, &ui32Value))) - { - goto Exit; - } - - if( uiTag == FCS_ITERATOR_NUMBER_VALUE) - { - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_UINT32_VAL, &ui32Value, 0))) - { - goto Exit; - } - } - else if( uiTag == FCS_ITERATOR_REC_PTR_VALUE) - { - uiValue = ui32Value; - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_REC_PTR_VAL, &uiValue, 0))) - { - goto Exit; - } - } - else - { - /* - Sanity check. - */ - - flmAssert( 0); - } - } - break; - } - - /* - Add a binary value to the criteria. - */ - - case FCS_ITERATOR_BINARY_VALUE: - { - FLMBYTE * pucValue = (FLMBYTE *)GedValPtr( pCurNode); - FLMUINT uiValLen = GedValLen( pCurNode); - - if( GedValType( pCurNode) != FLM_BINARY_TYPE) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_BINARY_VAL, pucValue, uiValLen))) - { - goto Exit; - } - break; - } - - /* - Add a UNICODE string value to the criteria. - */ - - case FCS_ITERATOR_UNICODE_VALUE: - { - FLMUINT uiLen; - FLMUNICODE * puzBuf; - - /* - Mark the pool. - */ - - pPoolMark = GedPoolMark( pPool); - - /* - Determine the length of the string. - */ - - if( RC_BAD( rc = GedGetUNICODE( pCurNode, NULL, &uiLen))) - { - goto Exit; - } - - /* - Allocate a temporary buffer. - */ - - uiLen += 2; - if( (puzBuf = (FLMUNICODE *)GedPoolAlloc( pPool, uiLen)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Extract the string and add it to the criteria. - */ - - if( RC_BAD( rc = GedGetUNICODE( pCurNode, puzBuf, &uiLen))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_UNICODE_VAL, puzBuf, 0))) - { - goto Exit; - } - - GedPoolReset( pPool, pPoolMark); - break; - } - - /* - Add a NATIVE, WP60, or Word String value to the criteria. - */ - - case FCS_ITERATOR_NATIVE_VALUE: - case FCS_ITERATOR_WP60_VALUE: - case FCS_ITERATOR_WDSTR_VALUE: - { - FLMUINT uiLen; - FLMBYTE * pucBuf; - - /* - Mark the pool. - */ - - pPoolMark = GedPoolMark( pPool); - - /* - Determine the length of the string. - */ - - if( uiTag == FCS_ITERATOR_NATIVE_VALUE) - { - if( RC_BAD( rc = GedGetNATIVE( pCurNode, NULL, &uiLen))) - { - goto Exit; - } - } - else - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - /* - Allocate a temporary buffer. - */ - - uiLen += 2; - if( (pucBuf = (FLMBYTE *)GedPoolAlloc( pPool, uiLen)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Extract the string and add it to the criteria. - */ - - if( uiTag == FCS_ITERATOR_NATIVE_VALUE) - { - if( RC_BAD( rc = GedGetNATIVE( pCurNode, (char *)pucBuf, &uiLen))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_STRING_VAL, pucBuf, 0))) - { - goto Exit; - } - } - - GedPoolReset( pPool, pPoolMark); - break; - } - - /* - Add a native (internal) text value - */ - - case FCS_ITERATOR_FLM_TEXT_VALUE: - { - if( RC_BAD( rc = FlmCursorAddValue( hIterator, - FLM_TEXT_VAL, GedValPtr( pCurNode), - GedValLen( pCurNode)))) - { - goto Exit; - } - break; - } - - /* - Add an operator to the criteria. - */ - - case FCS_ITERATOR_OPERATOR: - { - FLMUINT uiOp; - QTYPES eTranslatedOp; - - /* - Get the C/S operator ID. - */ - - if( RC_BAD( rc = GedGetUINT( pCurNode, &uiOp))) - { - goto Exit; - } - - if( !uiOp || - ((uiOp - FCS_ITERATOR_OP_START) >= FCS_ITERATOR_OP_END)) - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - - /* - Translate the C/S ID to a FLAIM operator ID. - */ - - if( RC_BAD( rc = fcsTranslateQCSToQFlmOp( - uiOp, &eTranslatedOp))) - { - goto Exit; - } - - /* - Add the operator to the criteria. - */ - - if( RC_BAD( rc = FlmCursorAddOp( hIterator, eTranslatedOp))) - { - goto Exit; - } - - break; - } - - default: - { - rc = RC_SET( FERR_SYNTAX); - goto Exit; - } - } - pCurNode = GedSibNext( pCurNode); - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Adds source information to an iterator. -*****************************************************************************/ -FSTATIC RCODE fsvIteratorFromParse( - FSV_WIRE * pWire, - POOL * pPool) -{ - HFDB hDb = HFDB_NULL; - HFCURSOR hIterator = pWire->getIteratorHandle(); - FLMUINT uiIteratorId = FCS_INVALID_ID; - NODE * pFrom = pWire->getIteratorFrom(); - NODE * pCurNode; - NODE * pCSAttrNode; - NODE * pTmpNode; - RCODE rc = FERR_OK; - - F_UNREFERENCED_PARM( pPool); - - /* - If no "from" clause, jump to exit. - */ - - if( !pFrom) - { - goto Exit; - } - - /* - Process each component of the "from" clause. - */ - - if (hIterator == HFCURSOR_NULL) - { - FSV_SESN * pSession; - FLMUINT uiContainerId = FLM_DATA_CONTAINER; - FLMUINT uiPath [4]; - - uiPath [0] = FCS_ITERATOR_FROM; - uiPath [1] = FCS_ITERATOR_CANDIDATE_SET; - uiPath [2] = FCS_ITERATOR_RECORD_SOURCE; - uiPath [3] = 0; - if ((pCSAttrNode = GedPathFind( GED_TREE, pFrom, uiPath, 1)) == NULL) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Get the database handle. - */ - - if( (pSession = pWire->getSession()) == NULL) - { - rc = RC_SET( FERR_BAD_HDL); - goto Exit; - } - hDb = pSession->GetDatabase(); - - /* - Get the container ID. A default value of - FLM_DATA_CONTAINER will be used if a container ID - is not found. - */ - - if( (pTmpNode = GedFind( GED_TREE, pCSAttrNode, - FCS_ITERATOR_CONTAINER_ID, 1)) != NULL) - { - if( RC_BAD( rc = GedGetUINT( pTmpNode, - &uiContainerId))) - { - goto Exit; - } - } - - /* - Initialize the cursor when we get the source - only one - source is allowed. - */ - - if( RC_BAD( rc = pSession->InitializeIterator( - &uiIteratorId, hDb, uiContainerId, &hIterator))) - { - goto Exit; - } - - /* - Set the iterator handle and ID so they will be available - for the parser to use. - */ - - pWire->setIteratorId( uiIteratorId); - pWire->setIteratorHandle( hIterator); - } - - pCurNode = GedChild( pFrom); - while( pCurNode) - { - switch( GedTagNum( pCurNode)) - { - - case FCS_ITERATOR_CANDIDATE_SET: - { - /* - Process record sources and indexes. - */ - - pCSAttrNode = GedChild( pCurNode); - while( pCSAttrNode) - { - switch( GedTagNum( pCSAttrNode)) - { - /* - Define a record source. - */ - - case FCS_ITERATOR_RECORD_SOURCE: - { - // Handled above. - break; - } - - /* - Specify a FLAIM index. - */ - - case FCS_ITERATOR_FLAIM_INDEX: - { - FLMUINT uiIndexId; - - /* - Get the index ID. - */ - - if( RC_BAD( rc = GedGetUINT( pCSAttrNode, &uiIndexId))) - { - goto Exit; - } - - /* - Add the index. - */ - - if( RC_BAD( rc = FlmCursorConfig( hIterator, - FCURSOR_SET_FLM_IX, (void *)uiIndexId, - (void *)0))) - { - goto Exit; - } - - break; - } - - /* - Set the record type. - */ - - case FCS_ITERATOR_RECORD_TYPE: - { - FLMUINT uiRecordType; - - /* - Get the record type. - */ - - if( RC_BAD( rc = GedGetUINT( pCSAttrNode, &uiRecordType))) - { - goto Exit; - } - - /* - Add the record type. - */ - - if( RC_BAD( rc = FlmCursorConfig( hIterator, - FCURSOR_SET_REC_TYPE, (void *)uiRecordType, - (void *)0))) - { - goto Exit; - } - break; - } - - case FCS_ITERATOR_OK_TO_RETURN_KEYS: - { - FLMUINT uiOkToReturnKeys; - - if( RC_BAD( rc = GedGetUINT( pCSAttrNode, &uiOkToReturnKeys))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorConfig( hIterator, - FCURSOR_RETURN_KEYS_OK, - (void *)(uiOkToReturnKeys ? - (FLMBOOL)TRUE : (FLMBOOL)FALSE), NULL))) - { - goto Exit; - } - break; - } - } - pCSAttrNode = GedSibNext( pCSAttrNode); - } - break; - } - - case FCS_ITERATOR_MODE: - { - FLMUINT uiFlags; - - /* - Get the mode flags. - */ - - if( RC_BAD( rc = GedGetUINT( pCurNode, &uiFlags))) - { - goto Exit; - } - - if( RC_BAD( rc = FlmCursorSetMode( hIterator, uiFlags))) - { - goto Exit; - } - break; - } - } - pCurNode = GedSibNext( pCurNode); - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Adds a view to an iterator -*****************************************************************************/ -FSTATIC RCODE fsvIteratorSelectParse( - FSV_WIRE * pWire, - POOL * pPool) -{ - NODE * pSelect = pWire->getIteratorSelect(); - NODE * pCurNode; - NODE * pView = NULL; - FLMBOOL bNullViewNotRec = FALSE; - RCODE rc = FERR_OK; - - F_UNREFERENCED_PARM( pPool); - - /* - If no "select" clause, jump to exit. - */ - - if( !pSelect) - { - goto Exit; - } - - pCurNode = GedChild( pSelect); - while( pCurNode) - { - switch( GedTagNum( pCurNode)) - { - case FCS_ITERATOR_VIEW_TREE: - { - pView = GedChild( pCurNode); - break; - } - - case FCS_ITERATOR_NULL_VIEW_NOT_REC: - { - bNullViewNotRec = TRUE; - break; - } - } - pCurNode = GedSibNext( pCurNode); - } - - /* - Set the view record, if any (not supported). - */ - - if( GedChild( pCurNode)) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Reads blocks from the database -*****************************************************************************/ -FSTATIC RCODE fsvDbGetBlocks( - HFDB hDb, - FLMUINT uiAddress, - FLMUINT uiMinTransId, - FLMUINT * puiCount, - FLMUINT * puiBlocksExamined, - FLMUINT * puiNextBlkAddr, - FLMUINT uiFlags, - POOL * pPool, - FLMBYTE ** ppBlocks, - FLMUINT * puiBytes) -{ - FDB * pDb = (FDB *)hDb; - FLMBOOL bDbInitialized = FALSE; - FLMBOOL bTransStarted = FALSE; - FLMUINT uiLoop; - FLMUINT uiCount = *puiCount; - SCACHE * pSCache = NULL; - FLMUINT uiBlockSize; - FLMUINT uiMaxFileSize; - RCODE rc = FERR_OK; - - *ppBlocks = NULL; - *puiCount = 0; - *puiBlocksExamined = 0; - *puiBytes = 0; - - if( IsInCSMode( hDb)) - { - fdbInitCS( pDb); - bDbInitialized = TRUE; - - CS_CONTEXT_p pCSContext = pDb->pCSContext; - FCL_WIRE Wire( pCSContext, pDb); - - if( !pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendOp( - FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_GET_BLOCK))) - { - goto Exit; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_ADDRESS, - uiAddress))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_TRANSACTION_ID, - uiMinTransId))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_COUNT, - uiCount))) - { - goto Transmission_Error; - } - - if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, - uiFlags))) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.sendTerminate())) - { - goto Transmission_Error; - } - - /* Read the response. */ - - if (RC_BAD( rc = Wire.read())) - { - goto Transmission_Error; - } - - if( RC_BAD( rc = Wire.getRCode())) - { - if( rc != FERR_IO_END_OF_FILE) - { - goto Exit; - } - } - - *puiBlocksExamined = (FLMUINT)Wire.getNumber2(); - *puiCount = (FLMUINT)Wire.getCount(); - *puiNextBlkAddr = Wire.getAddress(); - - if( *puiCount) - { - *puiBytes = Wire.getBlockSize(); - if( (*ppBlocks = (FLMBYTE *)GedPoolAlloc( pPool, *puiBytes)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - f_memcpy( *ppBlocks, Wire.getBlock(), *puiBytes); - } - goto Exit; - -Transmission_Error: - pCSContext->bConnectionGood = FALSE; - goto Exit; - } - - if( !uiCount) - { - uiCount = 1; - } - - uiBlockSize = pDb->pFile->FileHdr.uiBlockSize; - uiMaxFileSize = pDb->pFile->uiMaxFileSize; - bDbInitialized = TRUE; - if ( RC_BAD( rc = fdbInit( pDb, FLM_READ_TRANS, - FDB_TRANS_GOING_OK, 0, &bTransStarted))) - { - goto Exit; - } - - if( (*ppBlocks = (FLMBYTE *)GedPoolAlloc( pPool, - uiBlockSize * uiCount)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Read uiCount blocks from the database starting at - uiAddress. If none of the blocks meet the min trans - ID criteria, we will not return any blocks to the reader. - */ - - *puiNextBlkAddr = BT_END; - for( uiLoop = 0; uiLoop < uiCount; uiLoop++) - { - if( !FSAddrIsBelow( FSBlkAddress( - FSGetFileNumber( uiAddress), FSGetFileOffset( uiAddress)), - pDb->LogHdr.uiLogicalEOF)) - { - rc = RC_SET( FERR_IO_END_OF_FILE); - goto Exit; - } - - if( RC_BAD( rc = ScaGetBlock( pDb, NULL, BHT_FREE, - uiAddress, NULL, &pSCache))) - { - goto Exit; - } - - if( FB2UD( &pSCache->pucBlk[ BH_TRANS_ID]) >= uiMinTransId) - { - f_memcpy( (*ppBlocks + ((*puiCount) * uiBlockSize)), - pSCache->pucBlk, uiBlockSize); - - (*puiCount)++; - (*puiBytes) += uiBlockSize; - } - (*puiBlocksExamined)++; - - ScaReleaseCache( pSCache, FALSE); - pSCache = NULL; - - uiAddress += uiBlockSize; - if( FSGetFileOffset( uiAddress) >= uiMaxFileSize) - { - uiAddress = FSBlkAddress( FSGetFileNumber( uiAddress) + 1, 0); - } - *puiNextBlkAddr = uiAddress; - } - -Exit: - - if( pSCache) - { - ScaReleaseCache( pSCache, FALSE); - } - - if( bTransStarted) - { - RCODE rc2 = flmAbortDbTrans( pDb); - if ( RC_OK( rc)) - { - rc = rc2; - } - } - - if( bDbInitialized) - { - fdbExit( pDb); - } - - return( rc); -} - -/**************************************************************************** -Desc: Commits a database transaction and updates the log header -*****************************************************************************/ -RCODE fsvDbTransCommitEx( - HFDB hDb, - FSV_WIRE * pWire) -{ - RCODE rc = FERR_OK; - FDB * pDb = (FDB *)hDb; - FLMBOOL bIgnore; - FLMBOOL bForceCheckpoint = FALSE; - FLMBYTE * pucHeader = NULL; - - if( pWire->getFlags() & FCS_TRANS_FORCE_CHECKPOINT) - { - bForceCheckpoint = TRUE; - } - - pucHeader = pWire->getBlock(); - - if( IsInCSMode( hDb)) - { - fdbInitCS( pDb); - FCL_WIRE Wire( pDb->pCSContext, pDb); - - if (!pDb->pCSContext->bConnectionGood) - { - rc = RC_SET( FERR_BAD_SERVER_CONNECTION); - } - else - { - rc = Wire.doTransOp( - FCS_OP_TRANSACTION_COMMIT_EX, 0, 0, 0, - pucHeader, bForceCheckpoint); - } - goto Exit; - } - - if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, - FDB_TRANS_GOING_OK, 0, &bIgnore))) - { - goto Exit; - } - - /* - If there is an invisible transaction going, it should not be - commitable by an application. - */ - - if ((pDb->uiTransType == FLM_NO_TRANS) || - (pDb->uiFlags & FDB_INVISIBLE_TRANS)) - { - rc = RC_SET( FERR_NO_TRANS_ACTIVE); - goto Exit; - } - - /* - See if we have a transaction going which should be aborted. - */ - - if( RC_BAD( pDb->AbortRc)) - { - rc = RC_SET( FERR_ABORT_TRANS); - goto Exit; - } - - /* - Fix up the log header. Currently, only fields directly - related to a backup operation are updated. - */ - - if( pucHeader) - { - FLMBYTE * pLogHdr = &pucHeader[ 16]; - FLMBYTE * pucUncommittedHdr = &pDb->pFile->ucUncommittedLogHdr [0]; - - f_memcpy( &pucUncommittedHdr [LOG_LAST_BACKUP_TRANS_ID], - &pLogHdr[ LOG_LAST_BACKUP_TRANS_ID], 4); - - f_memcpy( &pucUncommittedHdr [LOG_BLK_CHG_SINCE_BACKUP], - &pLogHdr[ LOG_BLK_CHG_SINCE_BACKUP], 4); - - f_memcpy( &pucUncommittedHdr [LOG_INC_BACKUP_SEQ_NUM], - &pLogHdr[ LOG_INC_BACKUP_SEQ_NUM], 4); - - f_memcpy( &pucUncommittedHdr [LOG_INC_BACKUP_SERIAL_NUM], - &pLogHdr[ LOG_INC_BACKUP_SERIAL_NUM], F_SERIAL_NUM_SIZE); - } - - /* - Commit the transaction - */ - - rc = flmCommitDbTrans( pDb, 0, bForceCheckpoint); - -Exit: - - flmExit( FLM_DB_TRANS_COMMIT, pDb, rc); - return( rc); -} - -/**************************************************************************** -Desc: Looks up session, database, and iterator handles. -*****************************************************************************/ -FSTATIC RCODE fsvGetHandles( - FSV_WIRE * pWire) -{ - FSV_SCTX * pServerContext = NULL; - FSV_SESN * pSession = NULL; - HFCURSOR hIterator = HFCURSOR_NULL; - RCODE rc = FERR_OK; - - if( RC_BAD( rc = fsvGetGlobalContext( &pServerContext))) - { - goto Exit; - } - - if( pWire->getSessionId() != FCS_INVALID_ID) - { - if( RC_BAD( pServerContext->GetSession( pWire->getSessionId(), - &pSession))) - { - rc = RC_SET( FERR_BAD_HDL); - goto Exit; - } - - if( pSession->getCookie() != pWire->getSessionCookie()) - { - rc = RC_SET( FERR_BAD_HDL); - goto Exit; - } - - pWire->setSession( pSession); - } - - if( pSession) - { - pWire->setFDB( (FDB *)pSession->GetDatabase()); - if( pWire->getIteratorId() != FCS_INVALID_ID) - { - if( RC_BAD( rc = pSession->GetIterator( - pWire->getIteratorId(), &hIterator))) - { - goto Exit; - } - - pWire->setIteratorHandle( hIterator); - } - } - -Exit: - -#ifdef FSV_LOGGING - if( RC_BAD( rc)) - { - fsvLogHandlerMessage( NULL, - (FLMBYTE *)"Error finding requested handles.", rc, FSV_LOG_DEBUG); - } -#endif - - return( rc); -} - - -#ifdef FSV_LOGGING -/****************************************************************************** -Desc: Logs a message -*****************************************************************************/ -void fsvLogHandlerMessage( - FSV_SESN * pSession, - FLMBYTE * pucMsg, - RCODE rc, - FLMUINT uiMsgSeverity) -{ - FSV_SCTX * pServerContext = NULL; - - if( pucMsg && pucMsg[ 0]) - { - if( RC_BAD( fsvGetGlobalContext( &pServerContext))) - { - goto Exit; - } - - pServerContext->LogMessage( pSession, pucMsg, rc, uiMsgSeverity); - } - -Exit: - - return; -} -#endif // FSV_LOGGING - -/**************************************************************************** -Desc: -*****************************************************************************/ -RCODE fsvPostStreamedRequest( - FSV_SESN * pSession, - FLMBYTE * pucPacket, - FLMUINT uiPacketSize, - FLMBOOL bLastPacket, - FCS_BIOS * pSessionResponse) -{ - FLMBOOL bReleaseSession = FALSE; - RCODE rc = FERR_OK; - POOL localPool; - - GedPoolInit( &localPool, 1024); - - if( !pSession && !bLastPacket) - { - /* - If this is a session open request, the request must - be contained in a single packet. - */ - - rc = RC_SET( FERR_ILLEGAL_OP); - goto Exit; - } - - if( !pSession) - { - FCS_BIOS biosInput; - FCS_DIS dataIStream; - FCS_DOS dataOStream; - - if( RC_BAD( rc = dataIStream.setup( &biosInput))) - { - goto Exit; - } - - if( RC_BAD( rc = dataOStream.setup( pSessionResponse))) - { - goto Exit; - } - - if( RC_BAD( rc = biosInput.write( pucPacket, uiPacketSize))) - { - goto Exit; - } - - if( RC_BAD( rc = fsvProcessRequest( &dataIStream, - &dataOStream, &localPool, NULL))) - { - goto Exit; - } - } - else - { - FCS_BIOS * pServerBIStream; - FCS_BIOS * pServerBOStream; - - /* - Need to add a reference to the session object so that if the request closes - the session, the response stream will not be destructed until the response - has been returned to the client. - */ - - pSession->AddRef(); - bReleaseSession = TRUE; - - if( RC_BAD( rc = pSession->GetBIStream( &pServerBIStream))) - { - goto Exit; - } - - if( RC_BAD( rc = pSession->GetBOStream( &pServerBOStream))) - { - goto Exit; - } - - if( RC_BAD( rc = pServerBIStream->write( pucPacket, uiPacketSize))) - { - goto Exit; - } - - if( bLastPacket) - { - FCS_DIS dataIStream; - FCS_DOS dataOStream; - - if( RC_BAD( rc = dataIStream.setup( pServerBIStream))) - { - goto Exit; - } - - if( RC_BAD( rc = dataOStream.setup( pServerBOStream))) - { - goto Exit; - } - - GedPoolReset( pSession->getWireScratchPool(), NULL); - if( RC_BAD( rc = fsvProcessRequest( &dataIStream, &dataOStream, - pSession->getWireScratchPool(), NULL))) - { - goto Exit; - } - } - } - -Exit: - - GedPoolFree( &localPool); - - if( bReleaseSession) - { - pSession->Release(); - } - - return( rc); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -RCODE fsvGetStreamedResponse( - FSV_SESN * pSession, - FLMBYTE * pucPacketBuffer, - FLMUINT uiMaxPacketSize, - FLMUINT * puiPacketSize, - FLMBOOL * pbLastPacket) -{ - FCS_BIOS * pServerBOStream = NULL; - RCODE rc = FERR_OK; - - if( RC_BAD( rc = pSession->GetBOStream( &pServerBOStream))) - { - goto Exit; - } - - if( RC_BAD( rc = pServerBOStream->read( pucPacketBuffer, - uiMaxPacketSize, puiPacketSize))) - { - if( rc == FERR_EOF_HIT) - { - *pbLastPacket = TRUE; - rc = FERR_OK; - } - goto Exit; - } - - if( !pServerBOStream->isDataAvailable()) - { - *pbLastPacket = TRUE; - } - -Exit: - - return( rc); -} diff --git a/flaim/src/fsv_sctx.cpp b/flaim/src/fsv_sctx.cpp deleted file mode 100644 index 242524e..0000000 --- a/flaim/src/fsv_sctx.cpp +++ /dev/null @@ -1,655 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Server context class. -// Tabs: 3 -// -// Copyright (c) 1998-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_sctx.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FSV_SCTX::FSV_SCTX( void) -{ - m_uiSessionToken = 0; - m_uiCacheSize = FSV_DEFAULT_CACHE_SIZE; - m_bSetupCalled = FALSE; - m_paSessions = NULL; - m_hMutex = F_MUTEX_NULL; - m_szServerBasePath[ 0] = '\0'; - m_pLogFunc = NULL; -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -FSV_SCTX::~FSV_SCTX( void) -{ - FLMUINT uiSlot; - - if( m_bSetupCalled) - { - /* - Clean up and free the session table. - */ - - for( uiSlot = 0; uiSlot < m_uiMaxSessions; uiSlot++) - { - if( m_paSessions[ uiSlot] != NULL) - { - m_paSessions[ uiSlot]->Release(); - } - } - - f_free( &m_paSessions); - - /* - Free the session semaphore. - */ - - (void)f_mutexDestroy( &m_hMutex); - } -} - - -/**************************************************************************** -Desc: Configures and initializes the server context. -*****************************************************************************/ -RCODE FSV_SCTX::Setup( - FLMUINT uiMaxSessions, - const char * pszServerBasePath, - FSV_LOG_FUNC pLogFunc) -{ - RCODE rc = FERR_OK; - FLMUINT uiSlot; - - /* - Make sure that setup has not been called. - */ - - flmAssert( m_bSetupCalled == FALSE); - - /* - If zero was passed as the value of uiMaxSessions, - use the default. - */ - - if( !uiMaxSessions) - { - m_uiMaxSessions = FSV_DEFAULT_MAX_CONNECTIONS; - } - else - { - m_uiMaxSessions = uiMaxSessions; - } - - /* - Initialize the session table. - */ - - if( RC_BAD( rc = f_alloc( sizeof( FSV_SESN *) * m_uiMaxSessions, - &m_paSessions))) - { - goto Exit; - } - - for( uiSlot = 0; uiSlot < m_uiMaxSessions; uiSlot++) - { - m_paSessions[ uiSlot] = NULL; - } - - /* - Initialize the context mutex - */ - - if( RC_BAD( rc = f_mutexCreate( &m_hMutex))) - { - goto Exit; - } - - /* - Set the server's home path. - */ - - if( pszServerBasePath) - { - f_strcpy( m_szServerBasePath, pszServerBasePath); - } - else - { - m_szServerBasePath[ 0] = '\0'; - } - - /* - Set the logging function. - */ - - m_pLogFunc = pLogFunc; - - /* - Set the setup flag. - */ - - m_bSetupCalled = TRUE; - -Exit: - - /* - Clean up any allocations if an error was encountered. - */ - - if( RC_BAD( rc)) - { - if( m_paSessions != NULL) - { - f_free( &m_paSessions); - } - - if( m_hMutex != F_MUTEX_NULL) - { - f_mutexDestroy( &m_hMutex); - } - } - - return( rc); -} - - -/**************************************************************************** -Desc: Creates a new session object and adds it to the session table. -*****************************************************************************/ -RCODE FSV_SCTX::OpenSession( - FLMUINT uiVersion, - FLMUINT uiFlags, - FLMUINT * puiIdRV, - FSV_SESN ** ppSessionRV) -{ - FLMUINT uiSlot; - FLMUINT uiCurrTime; - FLMBOOL bLocked = FALSE; - FSV_SESN * pSession = NULL; - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Initialize the Id - */ - - *puiIdRV = 0; - - /* - Create a new session object - */ - - if( (pSession = f_new FSV_SESN) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Allocate the session object - */ - - if( RC_BAD( rc = pSession->Setup( this, uiVersion, uiFlags))) - { - goto Exit; - } - - /* - Lock the context mutex - */ - - f_mutexLock( m_hMutex); - bLocked = TRUE; - - /* - Find an empty slot in the table. - */ - - for( uiSlot = 0; uiSlot < m_uiMaxSessions; uiSlot++) - { - if( !m_paSessions[ uiSlot]) - { - break; - } - } - - if( uiSlot >= m_uiMaxSessions) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Assign the session to the table slot. - */ - - m_paSessions[ uiSlot] = pSession; - - /* - Increment the session token. - */ - - m_uiSessionToken++; - - /* - If the session token is 0xFFFF, reset it to 1. Because FSV_INVALID_ID - is 0xFFFFFFFF, it is important to reset the session token so that - a session will never be assigned an invalid ID. - */ - - if( m_uiSessionToken == 0xFFFF) - { - m_uiSessionToken = 1; - } - - /* - Set the session's ID. - */ - - *puiIdRV = uiSlot | (m_uiSessionToken << 16); - pSession->setId( *puiIdRV); - - /* - Set the session's cookie using the current time. - */ - - f_timeGetSeconds( &uiCurrTime); - pSession->setCookie( uiCurrTime); - - /* - Unlock the context mutex - */ - - f_mutexUnlock( m_hMutex); - bLocked = FALSE; - -Exit: - - if( RC_BAD( rc)) - { - if( pSession) - { - pSession->Release(); - pSession = NULL; - } - } - else - { - if( ppSessionRV) - { - *ppSessionRV = pSession; - } - } - - if( bLocked) - { - f_mutexUnlock( m_hMutex); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Closes a session and removes it from the session table. -*****************************************************************************/ -RCODE FSV_SCTX::CloseSession( - FLMUINT uiId) -{ - FLMUINT uiSlot = (0x0000FFFF & uiId); - FLMBOOL bLocked = FALSE; - FSV_SESN * pSession = NULL; - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Lock the context mutex - */ - - f_mutexLock( m_hMutex); - bLocked = TRUE; - - /* - Make sure that the slot is valid. - */ - - if( uiSlot >= m_uiMaxSessions) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Get a pointer to the table entry. - */ - - if( (pSession = m_paSessions[ uiSlot]) == NULL) - { - // Session already closed - goto Exit; - } - - /* - Verify the session ID. - */ - - if( pSession->getId() != uiId) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Free the session. - */ - - pSession->Release(); - - /* - Reset the table entry. - */ - - m_paSessions[ uiSlot] = NULL; - -Exit: - - if( bLocked) - { - f_mutexUnlock( m_hMutex); - } - - return( rc); -} - - -/**************************************************************************** -Desc: Returns a pointer to a specific session. -*****************************************************************************/ -RCODE FSV_SCTX::GetSession( - FLMUINT uiId, - FSV_SESN ** ppSession) -{ - FLMUINT uiSlot = (0x0000FFFF & uiId); - FLMBOOL bLocked = FALSE; - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Lock the context mutex - */ - - f_mutexLock( m_hMutex); - bLocked = TRUE; - - /* - Make sure that the slot is valid. - */ - - if( uiSlot >= m_uiMaxSessions) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Get a pointer to the entry in the session table. - */ - - if( (*ppSession = m_paSessions[ uiSlot]) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Verify the session ID. - */ - - if( (*ppSession)->getId() != uiId) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - -Exit: - - if( bLocked) - { - f_mutexUnlock( m_hMutex); - } - - return( rc); -} - -/**************************************************************************** -Desc: Sets the server's base (relative) path -*****************************************************************************/ -RCODE FSV_SCTX::SetBasePath( - const char * pszServerBasePath) -{ - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Lock the context mutex - */ - - f_mutexLock( m_hMutex); - - /* - Set the server's base path. - */ - - if( pszServerBasePath) - { - f_strcpy( m_szServerBasePath, pszServerBasePath); - } - else - { - m_szServerBasePath[ 0] = '\0'; - } - - /* - Unlock the context mutex - */ - - f_mutexUnlock( m_hMutex); - return( FERR_OK); -} - - -/**************************************************************************** -Desc: Copies the server's base path into a user-supplied path location -*****************************************************************************/ -RCODE FSV_SCTX::GetBasePath( - char * pszServerBasePath) -{ - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Lock the context mutex - */ - - f_mutexLock( m_hMutex); - - /* - Copy the base path. - */ - - f_strcpy( pszServerBasePath, m_szServerBasePath); - - /* - Unlock the context mutex - */ - - f_mutexUnlock( m_hMutex); - return( FERR_OK); -} - - -/**************************************************************************** -Desc: Builds and IO_PATH given a file's URL. The file must be located on - the server. This routine assumes that the host and port match the - servers host and port. -*****************************************************************************/ -RCODE FSV_SCTX::BuildFilePath( - const FLMUNICODE * puzUrlString, - char * pszFilePathRV) -{ - RCODE rc = FERR_OK; - char szBasePath[ F_PATH_MAX_SIZE]; - FUrl Url; - char * pucAsciiUrl; - const char * pszFile; - POOL tmpPool; - - /* - Initialize a temporary pool. - */ - - GedPoolInit( &tmpPool, 256); - - /* - Attempt to convert the UNICODE URL to a native string - */ - - if( RC_BAD( rc = fcsConvertUnicodeToNative( &tmpPool, - puzUrlString, &pucAsciiUrl))) - { - goto Exit; - } - - /* - Parse the URL. - */ - - if( RC_BAD( rc = Url.SetUrl( pucAsciiUrl))) - { - goto Exit; - } - - pszFile = Url.GetFile(); - - if( Url.GetRelative()) - { - /* - Get the server's base path. - */ - - GetBasePath( szBasePath); - - /* - Build the database path. - */ - - f_strcpy( pszFilePathRV, szBasePath); - if( RC_BAD( rc = f_pathAppend( pszFilePathRV, pszFile))) - { - goto Exit; - } - } - else - { - /* - Absolute path. Use the path "as-is." - */ - - f_strcpy( pszFilePathRV, pszFile); - } - -Exit: - - GedPoolFree( &tmpPool); - return( rc); -} - - -/**************************************************************************** -Desc: Sets the server's temporary directory. -*****************************************************************************/ -RCODE FSV_SCTX::SetTempDir( - const char * pszTempDir) -{ - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Set the temporary directory. There is no need to lock the context semaphore - because the state of the context is not being changed. - */ - - if( RC_BAD( rc = FlmConfig( - FLM_TMPDIR, (void *)pszTempDir, 0))) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/****************************************************************************** -Desc: Logs a message -*****************************************************************************/ -void FSV_SCTX::LogMessage( - FSV_SESN * pSession, - const char * pucMsg, - RCODE rc, - FLMUINT uiMsgSeverity) -{ - if( m_pLogFunc) - { - f_mutexLock( m_hMutex); - m_pLogFunc( pucMsg, rc, uiMsgSeverity, (void *)pSession); - f_mutexUnlock( m_hMutex); - } -} diff --git a/flaim/src/fsv_sesn.cpp b/flaim/src/fsv_sesn.cpp deleted file mode 100644 index 173d5a0..0000000 --- a/flaim/src/fsv_sesn.cpp +++ /dev/null @@ -1,666 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Server session class. -// Tabs: 3 -// -// Copyright (c) 1998-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_sesn.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: -*****************************************************************************/ -FSV_SESN::FSV_SESN( void) -{ - m_pServerContext = NULL; - m_hDb = HFDB_NULL; - m_uiSessionId = FCS_INVALID_ID; - m_uiCookie = 0; - m_uiFlags = 0; - m_pBIStream = NULL; - m_pBOStream = NULL; - m_bSetupCalled = FALSE; - m_uiClientProtocolVersion = 0; - GedPoolInit( &m_wireScratchPool, 2048); -} - - -/**************************************************************************** -Desc: -*****************************************************************************/ -FSV_SESN::~FSV_SESN( void) -{ - FLMUINT uiLoop; - - if( m_bSetupCalled) - { - /* - Free iterator resources. - */ - - for( uiLoop = 0; uiLoop < MAX_SESN_ITERATORS; uiLoop++) - { - if( m_IteratorList[ uiLoop] != HFCURSOR_NULL) - { - (void)FlmCursorFree( &m_IteratorList[ uiLoop]); - } - } - - /* - Close the database - */ - - if( m_hDb != HFDB_NULL) - { - (void)FlmDbClose( &m_hDb); - } - - /* - Free the buffer streams - */ - - if( m_pBIStream) - { - m_pBIStream->Release(); - } - - if( m_pBOStream) - { - m_pBOStream->Release(); - } - } - - GedPoolFree( &m_wireScratchPool); -} - - -/**************************************************************************** -Desc: Configures and initializes the session. -*****************************************************************************/ -RCODE FSV_SESN::Setup( - FSV_SCTX * pServerContext, - FLMUINT uiVersion, - FLMUINT uiFlags) -{ - FLMUINT uiLoop; - RCODE rc = FERR_OK; - - /* - Make sure that setup has not been called. - */ - - flmAssert( m_bSetupCalled == FALSE); - - /* - Verify that the requested version is supported. - */ - - if( uiVersion > FCS_VERSION_1_1_1) - { - rc = RC_SET( FERR_UNSUPPORTED_VERSION); - goto Exit; - } - m_uiClientProtocolVersion = uiVersion; - - - /* - Set the server context. - */ - - m_pServerContext = pServerContext; - - /* - Initialize the iterator list - */ - - for( uiLoop = 0; uiLoop < MAX_SESN_ITERATORS; uiLoop++) - { - m_IteratorList[ uiLoop] = HFCURSOR_NULL; - } - - m_bSetupCalled = TRUE; - m_uiFlags = uiFlags; - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Opens the requested database. -*****************************************************************************/ -RCODE FSV_SESN::OpenDatabase( - FLMUNICODE * puzDbPath, - FLMUNICODE * puzDataDir, - FLMUNICODE * puzRflDir, - FLMUINT uiOpenFlags) -{ - RCODE rc = FERR_OK; - char * pszDbPath = NULL; - char * pszDataDir; - char * pszRflDir; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - flmAssert( m_hDb == HFDB_NULL); - - if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE * 3, &pszDbPath))) - { - goto Exit; - } - pszDataDir = pszDbPath + F_PATH_MAX_SIZE; - pszRflDir = pszDataDir + F_PATH_MAX_SIZE; - - /* - Perform some sanity checking. - */ - - if( !puzDbPath) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Convert the UNICODE URL to a server path. - */ - - if( RC_BAD( rc = m_pServerContext->BuildFilePath( - puzDbPath, pszDbPath))) - { - goto Exit; - } - - /* - Convert the data directory - */ - - if( puzDataDir) - { - if( RC_BAD( rc = m_pServerContext->BuildFilePath( - puzDataDir, pszDataDir))) - { - goto Exit; - } - } - else - { - pszDataDir = NULL; - } - - /* - Convert the RFL path - */ - - if( puzRflDir) - { - if( RC_BAD( rc = m_pServerContext->BuildFilePath( - puzRflDir, pszRflDir))) - { - goto Exit; - } - } - else - { - *pszRflDir = 0; - } - - /* - Open the database. - */ - - if( RC_BAD( rc = FlmDbOpen( pszDbPath, pszDataDir, pszRflDir, - uiOpenFlags, NULL, &m_hDb))) - { - goto Exit; - } - -Exit: - - if (pszDbPath) - { - f_free( &pszDbPath); - } - - /* - Free resources - */ - - if( RC_BAD( rc)) - { - if( m_hDb != HFDB_NULL) - { - (void)FlmDbClose( &m_hDb); - } - } - - return( rc); -} - - -/**************************************************************************** -Desc: Creates a new database. -*****************************************************************************/ -RCODE FSV_SESN::CreateDatabase( - FLMUNICODE * puzDbPath, - FLMUNICODE * puzDataDir, - FLMUNICODE * puzRflDir, - FLMUNICODE * puzDictPath, - FLMUNICODE * puzDictBuf, - CREATE_OPTS * pCreateOpts) -{ - RCODE rc = FERR_OK; - POOL tmpPool; - char * pucDictBuf = NULL; - char * pszDbPath = NULL; - char * pszDataDir; - char * pszRflDir; - char * pszDictPath; - - /* - Initialize a temporary pool. - */ - - GedPoolInit( &tmpPool, 1024); - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - flmAssert( m_hDb == HFDB_NULL); - - if( RC_BAD( rc = f_alloc( F_PATH_MAX_SIZE * 4, &pszDbPath))) - { - goto Exit; - } - pszDataDir = pszDbPath + F_PATH_MAX_SIZE; - pszRflDir = pszDataDir + F_PATH_MAX_SIZE; - pszDictPath = pszRflDir + F_PATH_MAX_SIZE; - - /* - Perform some sanity checking. - */ - - if( !puzDbPath) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* - Convert the DB URL to a server path. - */ - - if( RC_BAD( rc = m_pServerContext->BuildFilePath( puzDbPath, pszDbPath))) - { - goto Exit; - } - - /* - Convert the dictionary URL to a server path. - */ - - if( puzDictPath) - { - if( RC_BAD( rc = - m_pServerContext->BuildFilePath( puzDictPath, pszDictPath))) - { - goto Exit; - } - } - else - { - pszDictPath = NULL; - } - - /* - Convert the data directory - */ - - if( puzDataDir) - { - if( RC_BAD( rc = m_pServerContext->BuildFilePath( - puzDataDir, pszDataDir))) - { - goto Exit; - } - } - else - { - pszDataDir = NULL; - } - - /* - Convert the RFL path - */ - - if( puzRflDir) - { - if( RC_BAD( rc = m_pServerContext->BuildFilePath( - puzRflDir, pszRflDir))) - { - goto Exit; - } - } - else - { - *pszRflDir = 0; - } - - /* - Attempt to convert the UNICODE dictionary buffer to a native string - */ - - if( puzDictBuf) - { - if( RC_BAD( rc = fcsConvertUnicodeToNative( &tmpPool, - puzDictBuf, &pucDictBuf))) - { - goto Exit; - } - } - - /* - Create the database. - */ - - if( RC_BAD( rc = FlmDbCreate( pszDbPath, pszDataDir, pszRflDir, - pszDictPath, pucDictBuf, pCreateOpts, &m_hDb))) - { - goto Exit; - } - -Exit: - - if (pszDbPath) - { - f_free( &pszDbPath); - } - - /* - Free resources - */ - - if( RC_BAD( rc)) - { - if( m_hDb != HFDB_NULL) - { - (void)FlmDbClose( &m_hDb); - } - } - - GedPoolFree( &tmpPool); - return( rc); -} - - -/**************************************************************************** -Desc: Closes the database. -*****************************************************************************/ -RCODE FSV_SESN::CloseDatabase( void) -{ - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Close the database. - */ - - if( m_hDb != HFDB_NULL) - { - if( RC_BAD( rc = FlmDbClose( &m_hDb))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Creates a new iterator and adds it to the session's iterator list. -*****************************************************************************/ -RCODE FSV_SESN::InitializeIterator( - FLMUINT * puiIteratorIdRV, - HFDB hDb, - FLMUINT uiContainer, - HFCURSOR * phIteratorRV) -{ - HFCURSOR hIterator = HFCURSOR_NULL; - FLMUINT uiSlot; - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Set the iterator id. - */ - - *puiIteratorIdRV = FCS_INVALID_ID; - - /* - Find a slot in the session's iterator table - */ - - for( uiSlot = 0; uiSlot < MAX_SESN_ITERATORS; uiSlot++) - { - if( m_IteratorList[ uiSlot] == HFCURSOR_NULL) - { - break; - } - } - - /* - Too many open iterators - */ - - if( uiSlot == MAX_SESN_ITERATORS) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - /* - Initialize a new iterator (cursor). - */ - - if( RC_BAD( rc = FlmCursorInit( hDb, uiContainer, &hIterator))) - { - goto Exit; - } - - /* - Add the iterator to the iterator list. - */ - - m_IteratorList[ uiSlot] = hIterator; - *puiIteratorIdRV = uiSlot; - -Exit: - - /* - Free resources - */ - - if( RC_BAD( rc)) - { - if( hIterator != HFCURSOR_NULL) - { - (void)FlmCursorFree( &hIterator); - } - } - else - { - if( phIteratorRV) - { - *phIteratorRV = hIterator; - } - } - - return( rc); -} - - -/**************************************************************************** -Desc: Frees the specified iterator and removes it from the session's - iterator list. -*****************************************************************************/ -RCODE FSV_SESN::FreeIterator( - FLMUINT uiIteratorId) -{ - HFCURSOR hIterator = HFCURSOR_NULL; - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - /* - Find the iterator in the resource bag and remove it. - */ - - if( uiIteratorId >= MAX_SESN_ITERATORS || - m_IteratorList[ uiIteratorId] == HFCURSOR_NULL) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - hIterator = m_IteratorList[ uiIteratorId]; - m_IteratorList[ uiIteratorId] = HFCURSOR_NULL; - - /* - Free the iterator. - */ - - if( RC_BAD( rc = FlmCursorFree( &hIterator))) - { - goto Exit; - } - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Returns the specified iterator's handle -*****************************************************************************/ -RCODE FSV_SESN::GetIterator( - FLMUINT uiIteratorId, - HFCURSOR * phIteratorRV) -{ - RCODE rc = FERR_OK; - - /* - Make sure that setup has been called. - */ - - flmAssert( m_bSetupCalled == TRUE); - - if( uiIteratorId >= MAX_SESN_ITERATORS || - m_IteratorList[ uiIteratorId] == HFCURSOR_NULL) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - *phIteratorRV = m_IteratorList[ uiIteratorId]; - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Returns a pointer to the buffer input stream -*****************************************************************************/ -RCODE FSV_SESN::GetBIStream( - FCS_BIOS ** ppBIStream) -{ - RCODE rc = FERR_OK; - - *ppBIStream = NULL; - - if( !m_pBIStream) - { - m_pBIStream = f_new FCS_BIOS; - if( !m_pBIStream) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - *ppBIStream = m_pBIStream; - -Exit: - - return( rc); -} - - -/**************************************************************************** -Desc: Returns a pointer to the buffer output stream -*****************************************************************************/ -RCODE FSV_SESN::GetBOStream( - FCS_BIOS ** ppBOStream) -{ - RCODE rc = FERR_OK; - - *ppBOStream = NULL; - - if( !m_pBOStream) - { - m_pBOStream = f_new FCS_BIOS; - if( !m_pBOStream) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - *ppBOStream = m_pBOStream; - -Exit: - - return( rc); -} diff --git a/flaim/src/fsv_sev.cpp b/flaim/src/fsv_sev.cpp deleted file mode 100644 index 77b9674..0000000 --- a/flaim/src/fsv_sev.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Client/Server stream dispatcher and handler. -// Tabs: 3 -// -// Copyright (c) 1999-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_sev.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*************************************************************************** -Desc: Receives stream events and dispatches them to the appropriate handlers -*****************************************************************************/ -RCODE flmStreamEventDispatcher( - FCS_BIOS_p pStream, - FLMUINT uiEvent, - void * UserData) -{ - CS_CONTEXT_p pCSContext = (CS_CONTEXT_p)UserData; - FLMUINT uiStreamHandlerId = FSEV_HANDLER_UNKNOWN; - RCODE rc = FERR_OK; - - /* - Determine the handler - */ - - if( pCSContext->uiStreamHandlerId == FSEV_HANDLER_UNKNOWN) - { - if( f_stricmp( pCSContext->pucAddr, "DS") == 0) - { - uiStreamHandlerId = FSEV_HANDLER_DS; - } - else if( f_stricmp( pCSContext->pucAddr, "LOOPBACK") == 0) - { - uiStreamHandlerId = FSEV_HANDLER_LOOPBACK; - } - - pCSContext->uiStreamHandlerId = uiStreamHandlerId; - } - else - { - uiStreamHandlerId = pCSContext->uiStreamHandlerId; - } - - /* - Invoke the handler - */ - - switch( uiStreamHandlerId) - { - case FSEV_HANDLER_LOOPBACK: - { - if( RC_BAD( rc = fsvStreamLoopback( pStream, uiEvent, UserData))) - { - goto Exit; - } - break; - } - - default: - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - } - - /* - Release CPU to prevent CPU hog - */ - - f_yieldCPU(); - -Exit: - - if( RC_BAD( rc)) - { - /* - Clear the saved handler ID in case a new handler is tried - */ - - pCSContext->uiStreamHandlerId = FSEV_HANDLER_UNKNOWN; - } - - return( rc); -} - -/**************************************************************************** -Desc: Provides loopback support for C/S testing -*****************************************************************************/ -RCODE fsvStreamLoopback( - FCS_BIOS_p pStream, - FLMUINT uiEvent, - void * UserData) -{ - CS_CONTEXT_p pCSContext = (CS_CONTEXT_p)UserData; - FCS_DIS dataIStream; - FCS_DOS dataOStream; - RCODE rc = FERR_OK; - - F_UNREFERENCED_PARM( pStream); - - if( uiEvent == FCS_BIOS_EOM_EVENT) - { - if( RC_BAD( rc = dataIStream.setup( - (FCS_BIOS_p)(pCSContext->pOStream)))) - { - goto Exit; - } - - if( RC_BAD( rc = dataOStream.setup( - (FCS_BIOS_p)(pCSContext->pIStream)))) - { - goto Exit; - } - - if( RC_BAD( rc = fsvProcessRequest( &dataIStream, &dataOStream, - &(pCSContext->pool), NULL))) - { - goto Exit; - } - } - -Exit: - - return( rc); -} diff --git a/flaim/src/fsv_tcph.cpp b/flaim/src/fsv_tcph.cpp deleted file mode 100644 index 4dbc8c0..0000000 --- a/flaim/src/fsv_tcph.cpp +++ /dev/null @@ -1,535 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: TCP handler -// Tabs: 3 -// -// Copyright (c) 1999-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_tcph.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -RCODE fsvTcpListener( - F_Thread * pThread); - -RCODE fsvTcpClientHandler( - F_Thread * pThread); - -RCODE fsvTcpVulture( - F_Thread * pThread); - -RCODE fsvTcpAcceptConnection( - F_MUTEX * phHandlerSem, - FCS_TCP * pClient); - -#define FSV_MAX_TCP_HANDLERS 64 - -FLMBOOL gv_bTcpAllowConnections = TRUE; -FLMBOOL gv_bTcpRunning = FALSE; -F_Thread * gv_TcpHandlers[ FSV_MAX_TCP_HANDLERS]; -F_Thread * gv_pTcpListenerThrd = NULL; - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE fsvStartTcpListener( - FLMUINT uiPort) -{ - RCODE rc = FERR_OK; - - if( RC_BAD( rc = f_threadCreate( &gv_pTcpListenerThrd, - fsvTcpListener, "DB TCP Listener", - FLM_DEFAULT_THREAD_GROUP, 0, (void *)uiPort))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void fsvShutdownTcpListener( void) -{ - f_threadDestroy( &gv_pTcpListenerThrd); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE fsvTcpListener( - F_Thread * pThread) -{ - RCODE rc = FERR_OK; - FCS_TCP_SERVER * pServer; - FCS_TCP * pClient = NULL; - F_Thread * pVultureThread = NULL; - F_MUTEX hHandlerSem = F_MUTEX_NULL; - FLMUINT uiLoop; - FLMUINT uiPort = (FLMUINT)pThread->getParm1(); - - /* Initialize TCP */ - - if( (pServer = f_new FCS_TCP_SERVER) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = pServer->bind( uiPort))) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, "TCPH: Unable to bind to port.", - rc, FSV_LOG_ERROR); -#endif - gv_bTcpAllowConnections = FALSE; - goto Exit; - } - - for( uiLoop = 0; uiLoop < FSV_MAX_TCP_HANDLERS; uiLoop++) - { - gv_TcpHandlers[ uiLoop] = NULL; - } - - if( RC_BAD( rc = f_mutexCreate( &hHandlerSem))) - { - goto Exit; - } - - if( RC_BAD( rc = f_threadCreate( &pVultureThread, - fsvTcpVulture, "DB TCP Vulture", - FLM_DEFAULT_THREAD_GROUP, 0, (void *)(&hHandlerSem)))) - { - goto Exit; - } - - gv_bTcpRunning = TRUE; - - for( ;;) - { - if( pThread->getShutdownFlag()) - { - goto Exit; - } - - if( pClient == NULL) - { - if( (pClient = f_new FCS_TCP) == NULL) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - "TCPH: Unable to create a new connection", - rc, FSV_LOG_ERROR); -#endif - f_sleep( 100); - continue; - } - } - - /* - See if a client is waiting to connect. - */ - - if( RC_OK( rc = pServer->connectClient( pClient, 2, 1200))) - { - if( RC_BAD( fsvTcpAcceptConnection( &hHandlerSem, pClient))) - { - pClient->Release(); - } - pClient = NULL; - } - else - { - if( rc != FERR_SVR_READ_TIMEOUT) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - "TCPH: Error listening for connections.", - rc, FSV_LOG_ERROR); - - fsvLogHandlerMessage( NULL, "TCPH: Attempting to reset.", - rc, FSV_LOG_ERROR); -#endif - - /* - Drop the current client. - */ - - pClient->Release(); - pClient = NULL; - - /* - Re-initialize the listener. - */ - - pServer->Release(); - pServer = f_new FCS_TCP_SERVER; - flmAssert( pServer != NULL); - - if( RC_BAD( rc = pServer->bind( uiPort))) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, "TCPH: Unable to bind to port.", - rc, FSV_LOG_ERROR); -#endif - gv_bTcpAllowConnections = FALSE; - } - else - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, "TCPH: Server reset completed.", - rc, FSV_LOG_EVENT); -#endif - } - } - } - } - -Exit: - - // Shut down all threads and free any allocated resources - - f_threadDestroy( &pVultureThread); - - if( pClient) - { - pClient->Release(); - } - - if( pServer) - { - pServer->Release(); - } - - gv_bTcpRunning = FALSE; - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE fsvTcpVulture( - F_Thread * pThread) -{ - F_MUTEX * phHandlerMutex = (F_MUTEX *)pThread->getParm1(); - FLMUINT uiLoop; - FLMUINT uiActiveThreads; - FLMUINT uiRetry; - FLMBOOL bShutdown = FALSE; - - while( !bShutdown) - { - if( pThread->getShutdownFlag()) - { - bShutdown = TRUE; - break; - } - - f_mutexLock( *phHandlerMutex); - - uiActiveThreads = 0; - uiLoop = 0; - while( uiLoop < FSV_MAX_TCP_HANDLERS) - { - if( gv_TcpHandlers[ uiLoop] != NULL) - { - if( !gv_TcpHandlers[ uiLoop]->isThreadRunning()) - { -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, "TCPH: Thread resources discarded.", - FERR_OK, FSV_LOG_DEBUG); -#endif - f_threadDestroy( &(gv_TcpHandlers[ uiLoop])); - } - else - { - uiActiveThreads++; - } - } - uiLoop++; - } - - f_mutexUnlock( *phHandlerMutex); - - for( uiLoop = 0; uiLoop < 100; uiLoop++) - { - if( pThread->getShutdownFlag()) - { - bShutdown = TRUE; - break; - } - f_sleep( 100); - } - } - - uiRetry = 0; - while( uiRetry < 60) - { - uiActiveThreads = 0; - uiLoop = 0; - while( uiLoop < FSV_MAX_TCP_HANDLERS) - { - if( gv_TcpHandlers[ uiLoop] != NULL) - { - if( !gv_TcpHandlers[ uiLoop]->isThreadRunning()) - { - f_threadDestroy( &(gv_TcpHandlers[ uiLoop])); - } - else - { - gv_TcpHandlers[ uiLoop]->setShutdownFlag(); - uiActiveThreads++; - } - } - uiLoop++; - } - - if( uiActiveThreads == 0) - { - break; - } - f_sleep( 1000); - uiRetry++; - } - - return( FERR_OK); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE fsvTcpAcceptConnection( - F_MUTEX * phHandlerMutex, - FCS_TCP * pClient) -{ - RCODE rc = FERR_OK; - FLMBOOL bMutexLocked = FALSE; - FLMUINT uiLoop; - F_Thread * pClientThrd; - - f_mutexLock( *phHandlerMutex); - bMutexLocked = TRUE; - - uiLoop = 0; - while( uiLoop < FSV_MAX_TCP_HANDLERS) - { - if( gv_TcpHandlers[ uiLoop] == NULL) - { - break; - } - uiLoop++; - } - - if( uiLoop < FSV_MAX_TCP_HANDLERS) - { - if( RC_BAD( rc = f_threadCreate( &pClientThrd, - fsvTcpClientHandler, "DB TCP Handler", - FLM_DEFAULT_THREAD_GROUP, 0, pClient))) - { - goto Exit; - } - gv_TcpHandlers[ uiLoop] = pClientThrd; - } - else - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - -Exit: - - if( bMutexLocked) - { - f_mutexUnlock( *phHandlerMutex); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE fsvTcpClientHandler( - F_Thread * pThread) -{ - RCODE rc = FERR_OK; - FCS_TCP * pClient = (FCS_TCP *)pThread->getParm1(); - FCS_IPIS * pIpIStream; - FCS_IPOS * pIpOStream = NULL; - FCS_DIS * pDataIStream = NULL; - FCS_DOS * pDataOStream = NULL; - FLMUINT uiSessionId = FCS_INVALID_ID; - POOL pool; -#ifdef FSV_LOGGING - FLMBYTE pucLogBuf[ 256]; -#endif - - /* - Initialize the scratch pool - */ - - GedPoolInit( &pool, 2048); - -#ifdef FSV_LOGGING - f_sprintf( pucLogBuf, "TCPH: Connection accepted from %s", - pClient->peerIpNameTxt()); - fsvLogHandlerMessage( NULL, pucLogBuf, - FERR_OK, FSV_LOG_EVENT); -#endif - - /* - Allocate required objects. - */ - - if( (pIpIStream = f_new FCS_IPIS( pClient)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( (pIpOStream = f_new FCS_IPOS( pClient)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( (pDataIStream = f_new FCS_DIS) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( (pDataOStream = f_new FCS_DOS) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - for( ;;) - { - if( pThread->getShutdownFlag()) - { - goto Exit; - } - - if( RC_BAD( rc = pClient->socketPeekRead( 5))) - { - if( rc != FERR_SVR_READ_TIMEOUT) - { - goto Exit; - } - } - else - { - - /* - Configure the data input stream. - */ - - if( RC_BAD( rc = pDataIStream->setup( pIpIStream))) - { - goto Exit; - } - - /* - Configure the data output stream. - */ - - if( RC_BAD( rc = pDataOStream->setup( pIpOStream))) - { - goto Exit; - } - - /* - Process the request. - */ - - if( RC_BAD( rc = fsvProcessRequest( pDataIStream, - pDataOStream, &pool, &uiSessionId))) - { - goto Exit; - } - } - } - -Exit: - -#ifdef FSV_LOGGING - if( pClient) - { - f_sprintf( pucLogBuf, "TCPH: %s disconnected.", - pClient->peerIpNameTxt()); - } - else - { - f_sprintf( pucLogBuf, "TCPH: disconnected."); - } - - fsvLogHandlerMessage( NULL, pucLogBuf, - FERR_OK, FSV_LOG_EVENT); -#endif - - if( pDataIStream) - { - pDataIStream->Release(); - } - - if( pDataOStream) - { - pDataOStream->Release(); - } - - if( pIpIStream) - { - pIpIStream->Release(); - } - - if( pIpOStream) - { - pIpOStream->Release(); - } - - if( pClient) - { - pClient->Release(); - } - - if( RC_BAD( rc) && uiSessionId != FCS_INVALID_ID) - { - FSV_SCTX * pServerContext = NULL; - - // Close the session and release any resources - // held by the client (open transactions, etc.) - - if( RC_OK( fsvGetGlobalContext( &pServerContext))) - { - pServerContext->CloseSession( uiSessionId); - } - -#ifdef FSV_LOGGING - fsvLogHandlerMessage( NULL, - "Session discarded.", FERR_OK, FSV_LOG_DEBUG); -#endif - } - - GedPoolFree( &pool); - return( rc); -} diff --git a/flaim/src/fsv_wire.cpp b/flaim/src/fsv_wire.cpp deleted file mode 100644 index 50aca27..0000000 --- a/flaim/src/fsv_wire.cpp +++ /dev/null @@ -1,267 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Wire class - read and parse client request or server response. -// Tabs: 3 -// -// Copyright (c) 1998-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fsv_wire.cpp 12297 2006-01-19 14:59:48 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: Resets all member variables to their default / initial values. -*****************************************************************************/ -void FSV_WIRE::reset( void) -{ - resetCommon(); - m_uiOpSeqNum = 0; - m_uiClientVersion = 0; - m_uiAutoTrans = 0; - m_uiMaxLockWait = 0; - m_puzDictPath = NULL; - m_puzDictBuf = NULL; - m_puzFileName = NULL; - m_pucPassword = NULL; - m_pDrnList = NULL; - m_uiAreaId = 0; - m_pIteratorSelect = NULL; - m_pIteratorFrom = NULL; - m_pIteratorWhere = NULL; - m_pIteratorConfig = NULL; - m_pSession = NULL; - m_hIterator = HFCURSOR_NULL; - m_uiType = 0; - m_bSendGedcom = FALSE; -} - -/**************************************************************************** -Desc: Sets the FSV_SESSSION and determines if GEDCOM is supported by the - client -*****************************************************************************/ -void FSV_WIRE::setSession( FSV_SESN * pSession) -{ - m_pSession = pSession; - - /* - See if GEDCOM is supported by the client - */ - - if( m_pSession && (m_pSession->getFlags() & FCS_SESSION_GEDCOM_SUPPORT)) - { - m_bSendGedcom = TRUE; - } -} - -/**************************************************************************** -Desc: Reads a client request or server response and sets the appropriate - member variable values. -*****************************************************************************/ -RCODE FSV_WIRE::read( void) -{ - FLMUINT uiTag; - FLMUINT uiCount = 0; - FLMBOOL bDone = FALSE; - RCODE rc = FERR_OK; - - /* - Read the opcode. - */ - - if( RC_BAD( rc = readOpcode())) - { - goto Exit; - } - - /* - Read the request / response values. - */ - - for( ;;) - { - if( RC_BAD( rc = readCommon( &uiTag, &bDone))) - { - goto Exit; - } - - if( bDone) - { - goto Exit; - } - - /* - uiTag will be non-zero if readCommon did not understand it. - */ - - uiCount++; - if( uiTag) - { - switch( (uiTag & WIRE_VALUE_TAG_MASK)) - { - case WIRE_VALUE_OP_SEQ_NUM: - { - if( RC_BAD( rc = readNumber( uiTag, &m_uiOpSeqNum, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_CLIENT_VERSION: - { - if( RC_BAD( rc = readNumber( uiTag, &m_uiClientVersion, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_DICT_FILE_PATH: - { - if( RC_BAD( rc = m_pDIStream->readUTF( m_pPool, - &m_puzDictPath))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_DICT_BUFFER: - { - if( RC_BAD( rc = m_pDIStream->readUTF( m_pPool, - &m_puzDictBuf))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_PASSWORD: - { - if( RC_BAD( rc = m_pDIStream->readBinary( m_pPool, - &m_pucPassword, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_TYPE: - { - if( RC_BAD( rc = readNumber( uiTag, &m_uiType, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_AREA_ID: - { - if( RC_BAD( rc = readNumber( uiTag, &m_uiAreaId, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_FILE_NAME: - { - if( RC_BAD( rc = m_pDIStream->readUTF( m_pPool, - &m_puzFileName))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_AUTOTRANS: - { - if( RC_BAD( rc = readNumber( uiTag, - &m_uiAutoTrans, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_ITERATOR_SELECT: - { - if( RC_BAD( rc = m_pDIStream->readHTD( - m_pPool, 0, 0, &m_pIteratorSelect, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_ITERATOR_FROM: - { - if( RC_BAD( rc = m_pDIStream->readHTD( - m_pPool, 0, 0, &m_pIteratorFrom, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_ITERATOR_WHERE: - { - if( RC_BAD( rc = m_pDIStream->readHTD( - m_pPool, 0, 0, &m_pIteratorWhere, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_ITERATOR_CONFIG: - { - if( RC_BAD( rc = m_pDIStream->readHTD( - m_pPool, 0, 0, &m_pIteratorConfig, NULL))) - { - goto Exit; - } - break; - } - - case WIRE_VALUE_MAX_LOCK_WAIT: - { - if( RC_BAD( rc = readNumber( uiTag, - &m_uiMaxLockWait, NULL))) - { - goto Exit; - } - break; - } - - default: - { - if( RC_BAD( rc = skipValue( uiTag))) - { - goto Exit; - } - break; - } - } - } - } - -Exit: - - return( rc); -} diff --git a/flaim/src/fsysdata.cpp b/flaim/src/fsysdata.cpp index 1f8e25a..0eb8d1f 100644 --- a/flaim/src/fsysdata.cpp +++ b/flaim/src/fsysdata.cpp @@ -115,7 +115,7 @@ FSTATIC void flmCleanup( void); FSTATIC void flmUnlinkFileFromBucket( FFILE * pFile); -RCODE flmMonitor( +RCODE flmSystemMonitor( F_Thread * pThread); FSTATIC RCODE flmRegisterHttpCallback( @@ -602,17 +602,16 @@ FSTATIC void flmUnlockSysData( void) #endif } -/*API~*********************************************************************** +/**************************************************************************** Desc : Startup FLAIM. Notes: This routine may be called multiple times. However, if that is done FlmShutdown() should be called for each time this is called successfully. This routine does not handle race conditions on platforms that do not support atomic increment. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmStartup( void) { RCODE rc = FERR_OK; - FLMINT iEventCategory; FLMUINT uiCacheBytes; #ifdef FLM_USE_NICI int iHandle; @@ -710,13 +709,10 @@ FLMEXP RCODE FLMAPI FlmStartup( void) gv_FlmSysData.uiMaxStratifyTime = DEFAULT_MAX_STRATIFY_TIME; // Initialize the event categories to have no mutex. - - for (iEventCategory = 0; - iEventCategory < F_MAX_EVENT_CATEGORIES; - iEventCategory++) - { - gv_FlmSysData.EventHdrs [iEventCategory].hMutex = F_MUTEX_NULL; - } + + gv_FlmSysData.UpdateEvents.hMutex = F_MUTEX_NULL; + gv_FlmSysData.LockEvents.hMutex = F_MUTEX_NULL; + gv_FlmSysData.SizeEvents.hMutex = F_MUTEX_NULL; // Memory initialization should be first. @@ -958,22 +954,29 @@ FLMEXP RCODE FLMAPI FlmStartup( void) // Set up mutexes for the event table. - for (iEventCategory = 0; - iEventCategory < F_MAX_EVENT_CATEGORIES; - iEventCategory++) + if (RC_BAD( rc = f_mutexCreate( + &gv_FlmSysData.UpdateEvents.hMutex))) { - if (RC_BAD( rc = f_mutexCreate( - &gv_FlmSysData.EventHdrs [iEventCategory].hMutex))) - { - goto Exit; - } + goto Exit; } - + + if (RC_BAD( rc = f_mutexCreate( + &gv_FlmSysData.LockEvents.hMutex))) + { + goto Exit; + } + + if (RC_BAD( rc = f_mutexCreate( + &gv_FlmSysData.SizeEvents.hMutex))) + { + goto Exit; + } + // Start the monitor thread - ALWAYS DO LAST. EVERYTHING MUST BE // SETUP PROPERLY BEFORE STARTING THIS THREAD. if (RC_BAD( rc = f_threadCreate( &gv_FlmSysData.pMonitorThrd, - flmMonitor, "DB Monitor"))) + flmSystemMonitor, "FLAIM System Monitor"))) { goto Exit; } @@ -982,9 +985,9 @@ FLMEXP RCODE FLMAPI FlmStartup( void) iHandle = f_getpid(); // Initialize NICI - if (CCS_Init(&iHandle)) { + // Failure. rc = RC_SET( FERR_NICI_INIT_FAILED); goto Exit; } @@ -1047,10 +1050,7 @@ DONT_PREALLOCATE: // Log a message indicating that we couldn't pre-allocate // the cache - flmLogMessage( - FLM_DEBUG_MESSAGE, - FLM_YELLOW, - FLM_BLACK, + flmLogMessage( FLM_DEBUG_MESSAGE, FLM_YELLOW, FLM_BLACK, "WARNING: Couldn't pre-allocate cache."); goto DONT_PREALLOCATE; @@ -1089,9 +1089,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Configures how memory will be dynamically regulated. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmSetDynamicMemoryLimit( FLMUINT uiCacheAdjustPercent, FLMUINT uiCacheAdjustMin, @@ -1131,9 +1131,9 @@ FLMEXP RCODE FLMAPI FlmSetDynamicMemoryLimit( #endif } -/*API~*********************************************************************** +/**************************************************************************** Desc : Sets a hard memory limit for cache. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmSetHardMemoryLimit( FLMUINT uiPercent, FLMBOOL bPercentOfAvail, @@ -1174,9 +1174,9 @@ FLMEXP RCODE FLMAPI FlmSetHardMemoryLimit( return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Returns information about memory usage. -*END************************************************************************/ +****************************************************************************/ FLMEXP void FLMAPI FlmGetMemoryInfo( FLM_MEM_INFO * pMemInfo) { @@ -1506,10 +1506,9 @@ Exit: return( rc); } - -/*API~*********************************************************************** +/**************************************************************************** Desc: Configures share attributes. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmConfig( eFlmConfigTypes eConfigType, void * Value1, @@ -1798,56 +1797,54 @@ FLMEXP RCODE FLMAPI FlmConfig( break; case FLM_ASSIGN_HTTP_SYMS: - //Note: before you attempt this, you had better have loaded the - //necessary shared library... - if ( gv_FlmSysData.HttpConfigParms.fnReg || - gv_FlmSysData.HttpConfigParms.fnDereg || - gv_FlmSysData.HttpConfigParms.fnReqPath || - gv_FlmSysData.HttpConfigParms.fnReqQuery || - gv_FlmSysData.HttpConfigParms.fnReqHdrValue || - gv_FlmSysData.HttpConfigParms.fnSetHdrValue || - gv_FlmSysData.HttpConfigParms.fnPrintf || - gv_FlmSysData.HttpConfigParms.fnEmit || - gv_FlmSysData.HttpConfigParms.fnSetNoCache || - gv_FlmSysData.HttpConfigParms.fnSendHeader || - gv_FlmSysData.HttpConfigParms.fnSetIOMode || - gv_FlmSysData.HttpConfigParms.fnSendBuffer || - gv_FlmSysData.HttpConfigParms.fnAcquireSession || - gv_FlmSysData.HttpConfigParms.fnReleaseSession || - gv_FlmSysData.HttpConfigParms.fnAcquireUser || - gv_FlmSysData.HttpConfigParms.fnReleaseUser || - gv_FlmSysData.HttpConfigParms.fnSetSessionValue || - gv_FlmSysData.HttpConfigParms.fnGetSessionValue || - gv_FlmSysData.HttpConfigParms.fnGetGblValue || - gv_FlmSysData.HttpConfigParms.fnSetGblValue || - gv_FlmSysData.HttpConfigParms.fnRecvBuffer ) + if( gv_FlmSysData.HttpConfigParms.fnReg || + gv_FlmSysData.HttpConfigParms.fnDereg || + gv_FlmSysData.HttpConfigParms.fnReqPath || + gv_FlmSysData.HttpConfigParms.fnReqQuery || + gv_FlmSysData.HttpConfigParms.fnReqHdrValue || + gv_FlmSysData.HttpConfigParms.fnSetHdrValue || + gv_FlmSysData.HttpConfigParms.fnPrintf || + gv_FlmSysData.HttpConfigParms.fnEmit || + gv_FlmSysData.HttpConfigParms.fnSetNoCache || + gv_FlmSysData.HttpConfigParms.fnSendHeader || + gv_FlmSysData.HttpConfigParms.fnSetIOMode || + gv_FlmSysData.HttpConfigParms.fnSendBuffer || + gv_FlmSysData.HttpConfigParms.fnAcquireSession || + gv_FlmSysData.HttpConfigParms.fnReleaseSession || + gv_FlmSysData.HttpConfigParms.fnAcquireUser || + gv_FlmSysData.HttpConfigParms.fnReleaseUser || + gv_FlmSysData.HttpConfigParms.fnSetSessionValue || + gv_FlmSysData.HttpConfigParms.fnGetSessionValue || + gv_FlmSysData.HttpConfigParms.fnGetGblValue || + gv_FlmSysData.HttpConfigParms.fnSetGblValue || + gv_FlmSysData.HttpConfigParms.fnRecvBuffer) { rc = RC_SET( FERR_HTTP_SYMS_EXIST); goto Exit; } else { - gv_FlmSysData.HttpConfigParms.fnReg = ((HTTPCONFIGPARAMS *)Value1)->fnReg; - gv_FlmSysData.HttpConfigParms.fnDereg = ((HTTPCONFIGPARAMS *)Value1)->fnDereg; - gv_FlmSysData.HttpConfigParms.fnReqPath = ((HTTPCONFIGPARAMS *)Value1)->fnReqPath; - gv_FlmSysData.HttpConfigParms.fnReqQuery = ((HTTPCONFIGPARAMS *)Value1)->fnReqQuery; - gv_FlmSysData.HttpConfigParms.fnReqHdrValue = ((HTTPCONFIGPARAMS *)Value1)->fnReqHdrValue; - gv_FlmSysData.HttpConfigParms.fnSetHdrValue = ((HTTPCONFIGPARAMS *)Value1)->fnSetHdrValue; - gv_FlmSysData.HttpConfigParms.fnPrintf = ((HTTPCONFIGPARAMS *)Value1)->fnPrintf; - gv_FlmSysData.HttpConfigParms.fnEmit = ((HTTPCONFIGPARAMS *)Value1)->fnEmit; - gv_FlmSysData.HttpConfigParms.fnSetNoCache = ((HTTPCONFIGPARAMS *)Value1)->fnSetNoCache; - gv_FlmSysData.HttpConfigParms.fnSendHeader = ((HTTPCONFIGPARAMS *)Value1)->fnSendHeader; - gv_FlmSysData.HttpConfigParms.fnSetIOMode = ((HTTPCONFIGPARAMS *)Value1)->fnSetIOMode; - gv_FlmSysData.HttpConfigParms.fnSendBuffer = ((HTTPCONFIGPARAMS *)Value1)->fnSendBuffer; - gv_FlmSysData.HttpConfigParms.fnAcquireSession = ((HTTPCONFIGPARAMS *)Value1)->fnAcquireSession; - gv_FlmSysData.HttpConfigParms.fnReleaseSession = ((HTTPCONFIGPARAMS *)Value1)->fnReleaseSession; - gv_FlmSysData.HttpConfigParms.fnAcquireUser = ((HTTPCONFIGPARAMS *)Value1)->fnAcquireUser; - gv_FlmSysData.HttpConfigParms.fnReleaseUser = ((HTTPCONFIGPARAMS *)Value1)->fnReleaseUser; + gv_FlmSysData.HttpConfigParms.fnReg = ((HTTPCONFIGPARAMS *)Value1)->fnReg; + gv_FlmSysData.HttpConfigParms.fnDereg = ((HTTPCONFIGPARAMS *)Value1)->fnDereg; + gv_FlmSysData.HttpConfigParms.fnReqPath = ((HTTPCONFIGPARAMS *)Value1)->fnReqPath; + gv_FlmSysData.HttpConfigParms.fnReqQuery = ((HTTPCONFIGPARAMS *)Value1)->fnReqQuery; + gv_FlmSysData.HttpConfigParms.fnReqHdrValue = ((HTTPCONFIGPARAMS *)Value1)->fnReqHdrValue; + gv_FlmSysData.HttpConfigParms.fnSetHdrValue = ((HTTPCONFIGPARAMS *)Value1)->fnSetHdrValue; + gv_FlmSysData.HttpConfigParms.fnPrintf = ((HTTPCONFIGPARAMS *)Value1)->fnPrintf; + gv_FlmSysData.HttpConfigParms.fnEmit = ((HTTPCONFIGPARAMS *)Value1)->fnEmit; + gv_FlmSysData.HttpConfigParms.fnSetNoCache = ((HTTPCONFIGPARAMS *)Value1)->fnSetNoCache; + gv_FlmSysData.HttpConfigParms.fnSendHeader = ((HTTPCONFIGPARAMS *)Value1)->fnSendHeader; + gv_FlmSysData.HttpConfigParms.fnSetIOMode = ((HTTPCONFIGPARAMS *)Value1)->fnSetIOMode; + gv_FlmSysData.HttpConfigParms.fnSendBuffer = ((HTTPCONFIGPARAMS *)Value1)->fnSendBuffer; + gv_FlmSysData.HttpConfigParms.fnAcquireSession = ((HTTPCONFIGPARAMS *)Value1)->fnAcquireSession; + gv_FlmSysData.HttpConfigParms.fnReleaseSession = ((HTTPCONFIGPARAMS *)Value1)->fnReleaseSession; + gv_FlmSysData.HttpConfigParms.fnAcquireUser = ((HTTPCONFIGPARAMS *)Value1)->fnAcquireUser; + gv_FlmSysData.HttpConfigParms.fnReleaseUser = ((HTTPCONFIGPARAMS *)Value1)->fnReleaseUser; gv_FlmSysData.HttpConfigParms.fnSetSessionValue = ((HTTPCONFIGPARAMS *)Value1)->fnSetSessionValue; gv_FlmSysData.HttpConfigParms.fnGetSessionValue = ((HTTPCONFIGPARAMS *)Value1)->fnGetSessionValue; - gv_FlmSysData.HttpConfigParms.fnGetGblValue = ((HTTPCONFIGPARAMS *)Value1)->fnGetGblValue; - gv_FlmSysData.HttpConfigParms.fnSetGblValue = ((HTTPCONFIGPARAMS *)Value1)->fnSetGblValue; - gv_FlmSysData.HttpConfigParms.fnRecvBuffer = ((HTTPCONFIGPARAMS *)Value1)->fnRecvBuffer; + gv_FlmSysData.HttpConfigParms.fnGetGblValue = ((HTTPCONFIGPARAMS *)Value1)->fnGetGblValue; + gv_FlmSysData.HttpConfigParms.fnSetGblValue = ((HTTPCONFIGPARAMS *)Value1)->fnSetGblValue; + gv_FlmSysData.HttpConfigParms.fnRecvBuffer = ((HTTPCONFIGPARAMS *)Value1)->fnRecvBuffer; } break; @@ -1868,28 +1865,27 @@ FLMEXP RCODE FLMAPI FlmConfig( break; case FLM_UNASSIGN_HTTP_SYMS: - gv_FlmSysData.HttpConfigParms.fnReg = NULL; - gv_FlmSysData.HttpConfigParms.fnDereg = NULL; - gv_FlmSysData.HttpConfigParms.fnReqPath = NULL; - gv_FlmSysData.HttpConfigParms.fnReqQuery = NULL; - gv_FlmSysData.HttpConfigParms.fnReqHdrValue = NULL; - gv_FlmSysData.HttpConfigParms.fnSetHdrValue = NULL; - gv_FlmSysData.HttpConfigParms.fnPrintf = NULL; - gv_FlmSysData.HttpConfigParms.fnEmit = NULL; - gv_FlmSysData.HttpConfigParms.fnSetNoCache = NULL; - gv_FlmSysData.HttpConfigParms.fnSendHeader = NULL; - gv_FlmSysData.HttpConfigParms.fnSetIOMode = NULL; - gv_FlmSysData.HttpConfigParms.fnSendBuffer = NULL; - gv_FlmSysData.HttpConfigParms.fnAcquireSession = NULL; - gv_FlmSysData.HttpConfigParms.fnReleaseSession = NULL; - gv_FlmSysData.HttpConfigParms.fnAcquireUser = NULL; - gv_FlmSysData.HttpConfigParms.fnReleaseUser = NULL; - gv_FlmSysData.HttpConfigParms.fnSetSessionValue = NULL; - gv_FlmSysData.HttpConfigParms.fnGetSessionValue = NULL; - gv_FlmSysData.HttpConfigParms.fnGetGblValue = NULL; - gv_FlmSysData.HttpConfigParms.fnSetGblValue = NULL; - gv_FlmSysData.HttpConfigParms.fnRecvBuffer = NULL; - + gv_FlmSysData.HttpConfigParms.fnReg = NULL; + gv_FlmSysData.HttpConfigParms.fnDereg = NULL; + gv_FlmSysData.HttpConfigParms.fnReqPath = NULL; + gv_FlmSysData.HttpConfigParms.fnReqQuery = NULL; + gv_FlmSysData.HttpConfigParms.fnReqHdrValue = NULL; + gv_FlmSysData.HttpConfigParms.fnSetHdrValue = NULL; + gv_FlmSysData.HttpConfigParms.fnPrintf = NULL; + gv_FlmSysData.HttpConfigParms.fnEmit = NULL; + gv_FlmSysData.HttpConfigParms.fnSetNoCache = NULL; + gv_FlmSysData.HttpConfigParms.fnSendHeader = NULL; + gv_FlmSysData.HttpConfigParms.fnSetIOMode = NULL; + gv_FlmSysData.HttpConfigParms.fnSendBuffer = NULL; + gv_FlmSysData.HttpConfigParms.fnAcquireSession = NULL; + gv_FlmSysData.HttpConfigParms.fnReleaseSession = NULL; + gv_FlmSysData.HttpConfigParms.fnAcquireUser = NULL; + gv_FlmSysData.HttpConfigParms.fnReleaseUser = NULL; + gv_FlmSysData.HttpConfigParms.fnSetSessionValue = NULL; + gv_FlmSysData.HttpConfigParms.fnGetSessionValue = NULL; + gv_FlmSysData.HttpConfigParms.fnGetGblValue = NULL; + gv_FlmSysData.HttpConfigParms.fnSetGblValue = NULL; + gv_FlmSysData.HttpConfigParms.fnRecvBuffer = NULL; break; case FLM_KILL_DB_HANDLES: @@ -1991,9 +1987,9 @@ Exit: return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Gets configured shared attributes. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmGetConfig( eFlmConfigTypes eConfigType, void * Value1 @@ -2153,9 +2149,9 @@ FLMEXP RCODE FLMAPI FlmGetConfig( return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc: -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmGetThreadInfo( POOL * pPool, F_THREAD_INFO ** ppThreadInfo, @@ -2163,7 +2159,7 @@ FLMEXP RCODE FLMAPI FlmGetThreadInfo( const char * pszUrl) { RCODE rc = FERR_OK; - CS_CONTEXT_p pCSContext = NULL; + CS_CONTEXT * pCSContext = NULL; if( pszUrl) { @@ -2466,6 +2462,15 @@ void flmFreeFile( pFile->pCPThrd->Release(); pFile->pCPThrd = NULL; } + + // Shutdown the monitor thread + + if( pFile->pMonitorThrd) + { + pFile->pMonitorThrd->stopThread(); + pFile->pMonitorThrd->Release(); + pFile->pMonitorThrd = NULL; + } f_mutexLock( gv_FlmSysData.hShareMutex); @@ -2612,7 +2617,7 @@ void flmFreeFile( { f_free( &pFile->pszDbPassword); } - + // Free the FFILE f_free( &pFile); @@ -2666,7 +2671,6 @@ Desc : Cleans up - assumes that the spin lock has already been FSTATIC void flmCleanup( void) { FLMUINT uiCnt; - FLMINT iEventCategory; // NOTE: We are checking and decrementing a global variable here. // However, on platforms that properly support atomic exchange, @@ -2863,26 +2867,44 @@ FSTATIC void flmCleanup( void) f_mutexDestroy( &gv_FlmSysData.HttpConfigParms.hMutex); } - // Free up callbacks that have been registered for events. - for (iEventCategory = 0; - iEventCategory < F_MAX_EVENT_CATEGORIES; - iEventCategory++) + if (gv_FlmSysData.UpdateEvents.hMutex != F_MUTEX_NULL) { - if (gv_FlmSysData.EventHdrs [iEventCategory].hMutex != F_MUTEX_NULL) + while (gv_FlmSysData.UpdateEvents.pEventCBList) { - while (gv_FlmSysData.EventHdrs [iEventCategory].pEventCBList) - { - flmFreeEvent( - gv_FlmSysData.EventHdrs [iEventCategory].pEventCBList, - gv_FlmSysData.EventHdrs [iEventCategory].hMutex, - &gv_FlmSysData.EventHdrs [iEventCategory].pEventCBList); - } - f_mutexDestroy( &gv_FlmSysData.EventHdrs [iEventCategory].hMutex); + flmFreeEvent( + gv_FlmSysData.UpdateEvents.pEventCBList, + gv_FlmSysData.UpdateEvents.hMutex, + &gv_FlmSysData.UpdateEvents.pEventCBList); } + f_mutexDestroy( &gv_FlmSysData.UpdateEvents.hMutex); } + if (gv_FlmSysData.LockEvents.hMutex != F_MUTEX_NULL) + { + while (gv_FlmSysData.LockEvents.pEventCBList) + { + flmFreeEvent( + gv_FlmSysData.LockEvents.pEventCBList, + gv_FlmSysData.LockEvents.hMutex, + &gv_FlmSysData.LockEvents.pEventCBList); + } + f_mutexDestroy( &gv_FlmSysData.LockEvents.hMutex); + } + + if (gv_FlmSysData.SizeEvents.hMutex != F_MUTEX_NULL) + { + while (gv_FlmSysData.SizeEvents.pEventCBList) + { + flmFreeEvent( + gv_FlmSysData.SizeEvents.pEventCBList, + gv_FlmSysData.SizeEvents.hMutex, + &gv_FlmSysData.SizeEvents.pEventCBList); + } + f_mutexDestroy( &gv_FlmSysData.SizeEvents.hMutex); + } + // Free (release) FLAIM's File Shared File System Object. if (gv_FlmSysData.pFileSystem) @@ -2959,13 +2981,13 @@ FSTATIC void flmCleanup( void) #endif } -/*API~*********************************************************************** +/**************************************************************************** Desc : Shuts down FLAIM. Notes: Allows itself to be called multiple times and even before FlmStartup is called, or even if FlmStartup fails. Warning: May not handle race conditions very well on platforms that do not support atomic exchange. -*END************************************************************************/ +****************************************************************************/ FLMEXP void FLMAPI FlmShutdown( void) { flmLockSysData(); @@ -3483,7 +3505,7 @@ Desc: This routine functions as a thread. It monitors open files and frees up files which have been closed longer than the maximum close time. ****************************************************************************/ -RCODE flmMonitor( +RCODE flmSystemMonitor( F_Thread * pThread) { FLMUINT uiLastUnusedCleanupTime = 0; @@ -3601,9 +3623,9 @@ RCODE flmMonitor( return( FERR_OK); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Registers a callback function to receive events. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI FlmRegisterForEvent( FEventCategory eCategory, FEVENT_CB fnEventCB, @@ -3615,14 +3637,6 @@ FLMEXP RCODE FLMAPI FlmRegisterForEvent( *phEventRV = HFEVENT_NULL; - // Make sure it is a legal event category to register for. - - if (eCategory >= F_MAX_EVENT_CATEGORIES) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - // Allocate an event structure if (RC_BAD( rc = f_calloc( (FLMUINT)(sizeof( FEVENT)), &pEvent))) @@ -3637,26 +3651,68 @@ FLMEXP RCODE FLMAPI FlmRegisterForEvent( pEvent->eCategory = eCategory; pEvent->fnEventCB = fnEventCB; pEvent->pvAppData = pvAppData; - // pEvent->pPrev = NULL; // done by flmAlloc above. // Mutex should be locked to link into list. - - f_mutexLock( gv_FlmSysData.EventHdrs [eCategory].hMutex); - if ((pEvent->pNext = - gv_FlmSysData.EventHdrs [eCategory].pEventCBList) != NULL) + + switch( eCategory) { - pEvent->pNext->pPrev = pEvent; + case F_EVENT_UPDATES: + { + f_mutexLock( gv_FlmSysData.UpdateEvents.hMutex); + if ((pEvent->pNext = + gv_FlmSysData.UpdateEvents.pEventCBList) != NULL) + { + pEvent->pNext->pPrev = pEvent; + } + + gv_FlmSysData.UpdateEvents.pEventCBList = pEvent; + f_mutexUnlock( gv_FlmSysData.UpdateEvents.hMutex); + break; + } + + case F_EVENT_LOCKS: + { + f_mutexLock( gv_FlmSysData.LockEvents.hMutex); + if ((pEvent->pNext = + gv_FlmSysData.LockEvents.pEventCBList) != NULL) + { + pEvent->pNext->pPrev = pEvent; + } + + gv_FlmSysData.LockEvents.pEventCBList = pEvent; + f_mutexUnlock( gv_FlmSysData.LockEvents.hMutex); + break; + } + + case F_EVENT_SIZE: + { + f_mutexLock( gv_FlmSysData.SizeEvents.hMutex); + if ((pEvent->pNext = + gv_FlmSysData.SizeEvents.pEventCBList) != NULL) + { + pEvent->pNext->pPrev = pEvent; + } + + gv_FlmSysData.SizeEvents.pEventCBList = pEvent; + f_mutexUnlock( gv_FlmSysData.SizeEvents.hMutex); + break; + } + + default: + { + rc = RC_SET_AND_ASSERT( FERR_NOT_IMPLEMENTED); + goto Exit; + } } - gv_FlmSysData.EventHdrs [eCategory].pEventCBList = pEvent; - f_mutexUnlock( gv_FlmSysData.EventHdrs [eCategory].hMutex); Exit: + return( rc); } -/*API~*********************************************************************** +/**************************************************************************** Desc : Deregisters a callback function that was registered to receive events. -*END************************************************************************/ +****************************************************************************/ FLMEXP void FLMAPI FlmDeregisterForEvent( HFEVENT * phEventRV) { @@ -3664,12 +3720,38 @@ FLMEXP void FLMAPI FlmDeregisterForEvent( { FEVENT * pEvent = (FEVENT *)(*phEventRV); - if (pEvent->eCategory < F_MAX_EVENT_CATEGORIES) + switch( pEvent->eCategory) { - flmFreeEvent( pEvent, - gv_FlmSysData.EventHdrs [pEvent->eCategory].hMutex, - &gv_FlmSysData.EventHdrs [pEvent->eCategory].pEventCBList); + case F_EVENT_UPDATES: + { + flmFreeEvent( pEvent, + gv_FlmSysData.UpdateEvents.hMutex, + &gv_FlmSysData.UpdateEvents.pEventCBList); + break; + } + + case F_EVENT_LOCKS: + { + flmFreeEvent( pEvent, + gv_FlmSysData.LockEvents.hMutex, + &gv_FlmSysData.LockEvents.pEventCBList); + break; + } + + case F_EVENT_SIZE: + { + flmFreeEvent( pEvent, + gv_FlmSysData.SizeEvents.hMutex, + &gv_FlmSysData.SizeEvents.pEventCBList); + break; + } + + default: + { + flmAssert( 0); + } } + *phEventRV = HFEVENT_NULL; } } @@ -3686,16 +3768,58 @@ void flmDoEventCallback( { FEVENT * pEvent; - f_mutexLock( gv_FlmSysData.EventHdrs [eCategory].hMutex); - pEvent = gv_FlmSysData.EventHdrs [eCategory].pEventCBList; - while (pEvent) + switch( eCategory) { - (*pEvent->fnEventCB)( eEventType, pEvent->pvAppData, - pvEventData1, - pvEventData2); - pEvent = pEvent->pNext; + case F_EVENT_UPDATES: + { + f_mutexLock( gv_FlmSysData.UpdateEvents.hMutex); + pEvent = gv_FlmSysData.UpdateEvents.pEventCBList; + while (pEvent) + { + (*pEvent->fnEventCB)( eEventType, pEvent->pvAppData, + pvEventData1, + pvEventData2); + pEvent = pEvent->pNext; + } + f_mutexUnlock( gv_FlmSysData.UpdateEvents.hMutex); + break; + } + + case F_EVENT_LOCKS: + { + f_mutexLock( gv_FlmSysData.LockEvents.hMutex); + pEvent = gv_FlmSysData.LockEvents.pEventCBList; + while (pEvent) + { + (*pEvent->fnEventCB)( eEventType, pEvent->pvAppData, + pvEventData1, + pvEventData2); + pEvent = pEvent->pNext; + } + f_mutexUnlock( gv_FlmSysData.LockEvents.hMutex); + break; + } + + case F_EVENT_SIZE: + { + f_mutexLock( gv_FlmSysData.SizeEvents.hMutex); + pEvent = gv_FlmSysData.SizeEvents.pEventCBList; + while (pEvent) + { + (*pEvent->fnEventCB)( eEventType, pEvent->pvAppData, + pvEventData1, + pvEventData2); + pEvent = pEvent->pNext; + } + f_mutexUnlock( gv_FlmSysData.SizeEvents.hMutex); + break; + } + + default: + { + flmAssert( 0); + } } - f_mutexUnlock( gv_FlmSysData.EventHdrs [eCategory].hMutex); } /**************************************************************************** @@ -5238,8 +5362,7 @@ Exit: Desc: Deletes (releases) and F_CCS objected referenced in the ITT table. *****************************************************************************/ void flmDeleteCCSRefs( - FDICT * pDict - ) + FDICT * pDict) { FLMUINT uiLoop; F_CCS * pCcs = NULL; diff --git a/flaim/src/ftk.h b/flaim/src/ftk.h index f7754b3..8ce430d 100644 --- a/flaim/src/ftk.h +++ b/flaim/src/ftk.h @@ -25,22 +25,28 @@ #ifndef FTK_H #define FTK_H - #if defined( FLM_DEBUG) && !defined( FLM_HPUX) - #define f_new new( __FILE__, __LINE__) - #else - #define f_new new - #endif - + /**************************************************************************** + Desc: Internal return code macros + ****************************************************************************/ #ifdef FLM_DEBUG - #define RC_SET( rc) \ - flmMakeErr(rc, __FILE__, __LINE__) - RCODE flmMakeErr( RCODE rc, const char * pszFile, - int iLine); + int iLine, + FLMBOOL bAssert); + + #define RC_SET( rc) \ + flmMakeErr( rc, __FILE__, __LINE__, FALSE) + + #define RC_SET_AND_ASSERT( rc) \ + flmMakeErr( rc, __FILE__, __LINE__, TRUE) + + #define RC_UNEXPECTED_ASSERT( rc) \ + flmMakeErr( rc, __FILE__, __LINE__, TRUE) #else - #define RC_SET(rc) (rc) + #define RC_SET( rc) (rc) + #define RC_SET_AND_ASSERT( rc) (rc) + #define RC_UNEXPECTED_ASSERT( rc) #endif #define F_SEM_WAITFOREVER 0xFFFFFFFF @@ -145,9 +151,9 @@ #define f_va_start va_start #define f_va_arg va_arg #define f_va_end va_end - - #elif defined( FLM_UNIX) + #elif defined( FLM_UNIX) + #include #include #include @@ -185,6 +191,10 @@ #ifdef FLM_AIX #include #endif + + #if defined( FLM_SOLARIS) || defined( FLM_LINUX) + #include + #endif #define FSTATIC static @@ -255,9 +265,9 @@ #ifndef SOCKET #define SOCKET int #endif - + #endif - + /**************************************************************************** CROSS PLATFORM DEFINITIONS ****************************************************************************/ @@ -345,7 +355,6 @@ #include "fpackon.h" - // IMPORTANT NOTE: No other include files should follow this one except // for fpackoff.h @@ -356,97 +365,97 @@ Desc: ASCII Constants ****************************************************************************/ - #define ASCII_TAB 0x09 - #define ASCII_NEWLINE 0x0A - #define ASCII_CR 0x0D - #define ASCII_CTRLZ 0x1A - #define ASCII_SPACE 0x20 - #define ASCII_DQUOTE 0x22 - #define ASCII_POUND 0x23 - #define ASCII_DOLLAR 0x24 - #define ASCII_SQUOTE 0x27 - #define ASCII_WILDCARD 0x2A - #define ASCII_PLUS 0x2B - #define ASCII_COMMA 0x2C - #define ASCII_DASH 0x2D - #define ASCII_MINUS 0x2D - #define ASCII_DOT 0x2E - #define ASCII_SLASH 0x2F - #define ASCII_COLON 0x3A - #define ASCII_SEMICOLON 0x3B - #define ASCII_EQUAL 0x3D - #define ASCII_QUESTIONMARK 0x3F - #define ASCII_AT 0x40 - #define ASCII_BACKSLASH 0x5C - #define ASCII_CARAT 0x5E - #define ASCII_UNDERSCORE 0x5F - #define ASCII_TILDE 0x7E - #define ASCII_AMP 0x26 + #define ASCII_TAB 0x09 + #define ASCII_NEWLINE 0x0A + #define ASCII_CR 0x0D + #define ASCII_CTRLZ 0x1A + #define ASCII_SPACE 0x20 + #define ASCII_DQUOTE 0x22 + #define ASCII_POUND 0x23 + #define ASCII_DOLLAR 0x24 + #define ASCII_SQUOTE 0x27 + #define ASCII_WILDCARD 0x2A + #define ASCII_PLUS 0x2B + #define ASCII_COMMA 0x2C + #define ASCII_DASH 0x2D + #define ASCII_MINUS 0x2D + #define ASCII_DOT 0x2E + #define ASCII_SLASH 0x2F + #define ASCII_COLON 0x3A + #define ASCII_SEMICOLON 0x3B + #define ASCII_EQUAL 0x3D + #define ASCII_QUESTIONMARK 0x3F + #define ASCII_AT 0x40 + #define ASCII_BACKSLASH 0x5C + #define ASCII_CARAT 0x5E + #define ASCII_UNDERSCORE 0x5F + #define ASCII_TILDE 0x7E + #define ASCII_AMP 0x26 - #define ASCII_UPPER_A 0x41 - #define ASCII_UPPER_B 0x42 - #define ASCII_UPPER_C 0x43 - #define ASCII_UPPER_D 0x44 - #define ASCII_UPPER_E 0x45 - #define ASCII_UPPER_F 0x46 - #define ASCII_UPPER_G 0x47 - #define ASCII_UPPER_H 0x48 - #define ASCII_UPPER_I 0x49 - #define ASCII_UPPER_J 0x4A - #define ASCII_UPPER_K 0x4B - #define ASCII_UPPER_L 0x4C - #define ASCII_UPPER_M 0x4D - #define ASCII_UPPER_N 0x4E - #define ASCII_UPPER_O 0x4F - #define ASCII_UPPER_P 0x50 - #define ASCII_UPPER_Q 0x51 - #define ASCII_UPPER_R 0x52 - #define ASCII_UPPER_S 0x53 - #define ASCII_UPPER_T 0x54 - #define ASCII_UPPER_U 0x55 - #define ASCII_UPPER_V 0x56 - #define ASCII_UPPER_W 0x57 - #define ASCII_UPPER_X 0x58 - #define ASCII_UPPER_Y 0x59 - #define ASCII_UPPER_Z 0x5A + #define ASCII_UPPER_A 0x41 + #define ASCII_UPPER_B 0x42 + #define ASCII_UPPER_C 0x43 + #define ASCII_UPPER_D 0x44 + #define ASCII_UPPER_E 0x45 + #define ASCII_UPPER_F 0x46 + #define ASCII_UPPER_G 0x47 + #define ASCII_UPPER_H 0x48 + #define ASCII_UPPER_I 0x49 + #define ASCII_UPPER_J 0x4A + #define ASCII_UPPER_K 0x4B + #define ASCII_UPPER_L 0x4C + #define ASCII_UPPER_M 0x4D + #define ASCII_UPPER_N 0x4E + #define ASCII_UPPER_O 0x4F + #define ASCII_UPPER_P 0x50 + #define ASCII_UPPER_Q 0x51 + #define ASCII_UPPER_R 0x52 + #define ASCII_UPPER_S 0x53 + #define ASCII_UPPER_T 0x54 + #define ASCII_UPPER_U 0x55 + #define ASCII_UPPER_V 0x56 + #define ASCII_UPPER_W 0x57 + #define ASCII_UPPER_X 0x58 + #define ASCII_UPPER_Y 0x59 + #define ASCII_UPPER_Z 0x5A - #define ASCII_LOWER_A 0x61 - #define ASCII_LOWER_B 0x62 - #define ASCII_LOWER_C 0x63 - #define ASCII_LOWER_D 0x64 - #define ASCII_LOWER_E 0x65 - #define ASCII_LOWER_F 0x66 - #define ASCII_LOWER_G 0x67 - #define ASCII_LOWER_H 0x68 - #define ASCII_LOWER_I 0x69 - #define ASCII_LOWER_J 0x6A - #define ASCII_LOWER_K 0x6B - #define ASCII_LOWER_L 0x6C - #define ASCII_LOWER_M 0x6D - #define ASCII_LOWER_N 0x6E - #define ASCII_LOWER_O 0x6F - #define ASCII_LOWER_P 0x70 - #define ASCII_LOWER_Q 0x71 - #define ASCII_LOWER_R 0x72 - #define ASCII_LOWER_S 0x73 - #define ASCII_LOWER_T 0x74 - #define ASCII_LOWER_U 0x75 - #define ASCII_LOWER_V 0x76 - #define ASCII_LOWER_W 0x77 - #define ASCII_LOWER_X 0x78 - #define ASCII_LOWER_Y 0x79 - #define ASCII_LOWER_Z 0x7A + #define ASCII_LOWER_A 0x61 + #define ASCII_LOWER_B 0x62 + #define ASCII_LOWER_C 0x63 + #define ASCII_LOWER_D 0x64 + #define ASCII_LOWER_E 0x65 + #define ASCII_LOWER_F 0x66 + #define ASCII_LOWER_G 0x67 + #define ASCII_LOWER_H 0x68 + #define ASCII_LOWER_I 0x69 + #define ASCII_LOWER_J 0x6A + #define ASCII_LOWER_K 0x6B + #define ASCII_LOWER_L 0x6C + #define ASCII_LOWER_M 0x6D + #define ASCII_LOWER_N 0x6E + #define ASCII_LOWER_O 0x6F + #define ASCII_LOWER_P 0x70 + #define ASCII_LOWER_Q 0x71 + #define ASCII_LOWER_R 0x72 + #define ASCII_LOWER_S 0x73 + #define ASCII_LOWER_T 0x74 + #define ASCII_LOWER_U 0x75 + #define ASCII_LOWER_V 0x76 + #define ASCII_LOWER_W 0x77 + #define ASCII_LOWER_X 0x78 + #define ASCII_LOWER_Y 0x79 + #define ASCII_LOWER_Z 0x7A - #define ASCII_ZERO 0x30 - #define ASCII_ONE 0x31 - #define ASCII_TWO 0x32 - #define ASCII_THREE 0x33 - #define ASCII_FOUR 0x34 - #define ASCII_FIVE 0x35 - #define ASCII_SIX 0x36 - #define ASCII_SEVEN 0x37 - #define ASCII_EIGHT 0x38 - #define ASCII_NINE 0x39 + #define ASCII_ZERO 0x30 + #define ASCII_ONE 0x31 + #define ASCII_TWO 0x32 + #define ASCII_THREE 0x33 + #define ASCII_FOUR 0x34 + #define ASCII_FIVE 0x35 + #define ASCII_SIX 0x36 + #define ASCII_SEVEN 0x37 + #define ASCII_EIGHT 0x38 + #define ASCII_NINE 0x39 /**************************************************************************** Desc: Native constants @@ -602,6 +611,17 @@ Desc: Byte order macros ****************************************************************************/ + FINLINE FLMUINT16 flmBigEndianToUINT16( + FLMBYTE * pucBuf) + { + FLMUINT16 ui16Val = 0; + + ui16Val |= ((FLMUINT16)pucBuf[ 0]) << 8; + ui16Val |= ((FLMUINT16)pucBuf[ 1]); + + return( ui16Val); + } + FINLINE FLMUINT32 flmBigEndianToUINT32( FLMBYTE * pucBuf) { @@ -632,15 +652,45 @@ return( ui64Val); } - FINLINE FLMUINT16 flmBigEndianToUINT16( + FINLINE FLMINT16 flmBigEndianToINT16( FLMBYTE * pucBuf) { - FLMUINT16 ui16Val = 0; + FLMINT16 i16Val = 0; - ui16Val |= ((FLMUINT16)pucBuf[ 0]) << 8; - ui16Val |= ((FLMUINT16)pucBuf[ 1]); + i16Val |= ((FLMINT16)pucBuf[ 0]) << 8; + i16Val |= ((FLMINT16)pucBuf[ 1]); - return( ui16Val); + return( i16Val); + } + + FINLINE FLMINT32 flmBigEndianToINT32( + FLMBYTE * pucBuf) + { + FLMINT32 i32Val = 0; + + i32Val |= ((FLMINT32)pucBuf[ 0]) << 24; + i32Val |= ((FLMINT32)pucBuf[ 1]) << 16; + i32Val |= ((FLMINT32)pucBuf[ 2]) << 8; + i32Val |= ((FLMINT32)pucBuf[ 3]); + + return( i32Val); + } + + FINLINE FLMINT64 flmBigEndianToINT64( + FLMBYTE * pucBuf) + { + FLMINT64 i64Val = 0; + + i64Val |= ((FLMINT64)pucBuf[ 0]) << 56; + i64Val |= ((FLMINT64)pucBuf[ 1]) << 48; + i64Val |= ((FLMINT64)pucBuf[ 2]) << 40; + i64Val |= ((FLMINT64)pucBuf[ 3]) << 32; + i64Val |= ((FLMINT64)pucBuf[ 4]) << 24; + i64Val |= ((FLMINT64)pucBuf[ 5]) << 16; + i64Val |= ((FLMINT64)pucBuf[ 6]) << 8; + i64Val |= ((FLMINT64)pucBuf[ 7]); + + return( i64Val); } FINLINE void flmUINT32ToBigEndian( @@ -1564,6 +1614,25 @@ return( 0); } + /*************************************************************************** + Desc: + ****************************************************************************/ + FINLINE FLMUINT64 flmRoundUp( + FLMUINT64 ui64ValueToRound, + FLMUINT64 ui64Boundary) + { + FLMUINT64 ui64RetVal; + + ui64RetVal = ((ui64ValueToRound / ui64Boundary) * ui64Boundary); + + if( ui64RetVal < ui64ValueToRound) + { + ui64RetVal += ui64Boundary; + } + + return( ui64RetVal); + } + /**************************************************************************** Desc: Process ID Functions ****************************************************************************/ diff --git a/flaim/src/ftkmem.h b/flaim/src/ftkmem.h index 0212c8e..fb279dd 100644 --- a/flaim/src/ftkmem.h +++ b/flaim/src/ftkmem.h @@ -76,7 +76,7 @@ FLMUINT * memWalkStack( void); - typedef struct F_MemHdrTag + typedef struct F_MEM_HDR { FLMUINT uiDataSize; #ifdef FLM_DEBUG diff --git a/flaim/src/ftkpath.cpp b/flaim/src/ftkpath.cpp index d1ab6e6..9c817cd 100644 --- a/flaim/src/ftkpath.cpp +++ b/flaim/src/ftkpath.cpp @@ -381,7 +381,7 @@ FLMEXP RCODE FLMAPI f_pathReduce( // Check for valid path pointers - if( !pszPath || !pszDir) + if( !pszPath) { rc = RC_SET( FERR_INVALID_PARM); goto Exit; @@ -427,30 +427,33 @@ FLMEXP RCODE FLMAPI f_pathReduce( // Copy the reduced source path to the dir path - if (pszFileNameStart > pszPath) + if( pszDir) { - uiLen = (FLMUINT)(pszFileNameStart - pszPath); - f_memcpy( pszDir, pszPath, uiLen); - - if (uiLen >= 2 && f_isSlashSeparator( pszDir [uiLen - 1]) -#ifndef FLM_UNIX - && pszDir [uiLen - 2] != ':' -#endif - ) + if (pszFileNameStart > pszPath) { - // Trim off the trailing path separator + uiLen = (FLMUINT)(pszFileNameStart - pszPath); + f_memcpy( pszDir, pszPath, uiLen); - pszDir [uiLen - 1] = 0; + if (uiLen >= 2 && f_isSlashSeparator( pszDir [uiLen - 1]) +#ifndef FLM_UNIX + && pszDir [uiLen - 2] != ':' +#endif + ) + { + // Trim off the trailing path separator + + pszDir [uiLen - 1] = 0; + } + else + { + pszDir [uiLen] = 0; + } } else { - pszDir [uiLen] = 0; + *pszDir = 0; } } - else - { - *pszDir = 0; - } } else { @@ -460,8 +463,11 @@ FLMEXP RCODE FLMAPI f_pathReduce( { f_strcpy( pszPathComponent, pszPath); } - - *pszDir = 0; + + if( pszDir) + { + *pszDir = 0; + } } Exit: diff --git a/flaim/src/ftkthrd.h b/flaim/src/ftkthrd.h index 4f8ee44..90349f9 100644 --- a/flaim/src/ftkthrd.h +++ b/flaim/src/ftkthrd.h @@ -84,6 +84,7 @@ class F_ThreadMgr; #define FLM_CHECKPOINT_THREAD_GROUP 2 #define FLM_BACKGROUND_INDEXING_THREAD_GROUP 3 #define FLM_DB_THREAD_GROUP 4 +#define FLM_DB_MONITOR_THREAD_GROUP 5 /**************************************************************************** Desc: Class for managing a set of threads diff --git a/flaim/src/ftkwptxt.h b/flaim/src/ftkwptxt.h deleted file mode 100644 index c9f8b32..0000000 --- a/flaim/src/ftkwptxt.h +++ /dev/null @@ -1,767 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: WP text and character definitions. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1994-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: ftkwptxt.h 12299 2006-01-19 15:01:23 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#ifndef FTKWPTXT_H -#define FTKWPTXT_H - -#include "fpackon.h" - -// IMPORTANT NOTE: No other include files should follow this one except -// for fpackoff.h - -#define Upper_JP_A 0x2520 -#define Upper_JP_Z 0x2539 -#define Upper_KR_A 0x5420 -#define Upper_KR_Z 0x5439 -#define Upper_CS_A 0x82FC -#define Upper_CS_Z 0x8316 -#define Upper_CT_A 0xA625 -#define Upper_CT_Z 0xA63E - -#define Lower_JP_a 0x2540 -#define Lower_JP_z 0x2559 -#define Lower_KR_a 0x5440 -#define Lower_KR_z 0x5459 -#define Lower_CS_a 0x82DC -#define Lower_CS_z 0x82F5 -#define Lower_CT_a 0xA60B -#define Lower_CT_z 0xA624 - -/* character set #'s are same as high byte values except for algorithmic set. */ - -/* ------ character code high byte values for character sets */ - -#define CHSASCI 0 /* ASCII */ -#define CHSMUL1 1 /* Multinational 1 */ -#define CHSMUL2 2 /* Multinational 2 */ -#define CHSBOXD 3 /* Box drawing */ -#define CHSSYM1 4 /* Typographic Symbols */ -#define CHSSYM2 5 /* Iconic Symbols */ -#define CHSMATH 6 /* Math */ -#define CHMATHX 7 /* Math Extension */ -#define CHSGREK 8 /* Greek */ -#define CHSHEB 9 /* Hebrew */ -#define CHSCYR 10 /* Cyrillic */ -#define CHSKANA 11 /* Japanese Kana */ -#define CHSUSER 12 /* User-defined */ -#define CHSARB1 13 /* Arabic */ -#define CHSARB2 14 /* Arabic script */ - -#define NCHSETS 15 /* # of character sets (excluding asian) */ -#define ACHSETS 0x0E0 /* maximum character set value - asian */ -#define ACHSMIN 0x024 /* minimum character set value - asian */ -#define ACHCMAX 0x0FE /* maxmimum character value in asian sets */ - - -/* - # of characters in each character set. - CHANGING ANY OF THESE DEFINES WILL CAUSE BUGS! -*/ -#define ASC_N 95 -#define ML1_N 242 -#define ML2_N 145 -#define BOX_N 88 -#define TYP_N 103 -#define ICN_N 255 -#define MTH_N 238 -#define MTX_N 229 -#define GRK_N 219 -#define HEB_N 123 -#define CYR_N 250 -#define KAN_N 63 -#define USR_N 255 -#define ARB_N 196 -#define ARS_N 220 - -/* - TOTAL: 1447 WP + 255 User Characters -*/ - -#define C_N ASC_N+ML1_N+ML2_N+BOX_N+MTH_N+MTX_N+TYP_N+ICN_N+GRK_N+\ - HEB_N+CYR_N+KAN_N+USR_N+ARB_N+ARS_N - -/* - Definitions for diacritics. -*/ - -#define grave 0 -#define centerd 1 -#define tilde 2 -#define circum 3 -#define crossb 4 -#define slash 5 -#define acute 6 -#define umlaut 7 -#define macron 8 - -#define aposab 9 -#define aposbes 10 -#define aposba 11 - -#define ring 14 -#define dota 15 -#define dacute 16 -#define cedilla 17 -#define ogonek 18 -#define caron 19 -#define stroke 20 - -#define breve 22 -#define dotlesi 239 -#define dotlesj 25 - -#define gacute 83 /* greek acute */ -#define gdia 84 /* greek diaeresis */ -#define gactdia 85 /* acute diaeresis */ -#define ggrvdia 86 /* grave diaeresis */ -#define ggrave 87 /* greek grave */ -#define gcircm 88 /* greek circumflex */ -#define gsmooth 89 /* smooth breathing */ -#define grough 90 /* rough breathing */ -#define giota 91 /* iota subscript */ -#define gsmact 92 /* smooth breathing acute */ -#define grgact 93 /* rough breathing acute */ -#define gsmgrv 94 /* smooth breathing grave */ -#define grggrv 95 /* rough breathing grave */ -#define gsmcir 96 /* smooth breathing circumflex */ -#define grgcir 97 /* rough breathing circumflex */ -#define gactio 98 /* acute iota */ -#define ggrvio 99 /* grave iota */ -#define gcirio 100 /* circumflex iota */ -#define gsmio 101 /* smooth iota */ -#define grgio 102 /* rough iota */ -#define gsmaio 103 /* smooth acute iota */ -#define grgaio 104 /* rough acute iota */ -#define gsmgvio 105 /* smooth grave iota */ -#define grggvio 106 /* rough grave iota */ -#define gsmcio 107 /* smooth circumflex iota */ -#define grgcio 108 /* rough circumflex iota */ -#define ghprime 81 /* high prime */ -#define glprime 82 /* low prime */ - -#define racute 200 /* russian acute */ -#define rgrave 201 /* russian grave */ -#define rrtdesc 204 /* russian right descender */ -#define rogonek 205 /* russian ogonek */ -#define rmacron 206 /* russian macron */ - -typedef struct base_diacrit_table -{ - FLMBYTE base; - FLMBYTE diacrit; -} BASE_DIACRIT_TABLE, *BASE_DIACRIT_TABLEP; - -typedef struct base_diacrit -{ - FLMUINT16 char_count; /*# of characters in table.*/ - FLMUINT16 start_char; /*start char.*/ - BASE_DIACRIT_TABLEP table; - -} BASE_DIACRIT, *BASE_DIACRITP; - -typedef struct cpose -{ - FLMBYTE chars[2]; - FLMUINT16 wpchar; -} CPOSE; - -/* Collating Sequence Equates */ -/* NOTE:The collating sequence MUST start at 32 (20h). This allows for the */ -/* handling of nulls and control characters. */ -/* (see \shar50\wp50lib\cmpws.asm) */ - -#define COLLS 32 /* first collating number (space/end of line) */ -#define COLS1 (COLLS+9) /* quotes */ -#define COLS2 (COLS1+5) /* parens */ -#define COLS3 (COLS2+6) /* money */ -#define COLS4 (COLS3+6) /* math ops */ -#define COLS5 (COLS4+8) /* math others */ -#define COLS6 (COLS5+14) /* others: %#&@\_|~ */ -#define COLS7 (COLS6+13) /* greek */ -#define COLS8 (COLS7+25) /* numbers */ -#define COLS9 (COLS8+10) /* alphabet */ - /* Three below will overlap each other */ -#define COLS10 (COLS9+60) /* cyrillic */ -#define COLS10h (COLS9+42) /* hebrew - writes over european & cyrilic */ -#define COLS10a (COLS10h+28)/* arabic - inclusive from 198(C6)-252(FC) */ - -#define COLS11 253 /* End of list - arabic goes to the end */ - -#define COLS0_ARABIC COLS11 /* Set if arabic accent marking */ -#define COLS0_HEBREW COLS11 /* Set if hebrew accent marking */ - -#define COLSOEM 254 /* OEM character in upper range - non-collatable*/ - /* Phase COLSOEM out - not used! */ -#define COLS0_UNICODE 254 /* Use this for UNICODE */ -#define COLS0 255 /* graphics/misc - chars without a collate value*/ - -/* -*** Language definitions - to get rid of testing "US" or multiple bytes -*** will define needed languages as a number with backward conversions. -*** Keep these defines synchronized with the table in wps6cmpc.c -**/ -#define US_LANG 0 /* English, United States */ -#define AF_LANG 1 /* Afrikaans */ -#define AR_LANG 2 /* Arabic */ -#define CA_LANG 3 /* Catalan */ -#define HR_LANG 4 /* Croatian */ -#define CZ_LANG 5 /* Czech */ -#define DK_LANG 6 /* Danish */ -// JDP - SCO already defines NL_LANG as something else -#define _NL_LANG 7 /* Dutch */ -#define OZ_LANG 8 /* English, Australia */ -#define CE_LANG 9 /* English, Canada */ -#define UK_LANG 10 /* English, United Kingdom */ -#define FA_LANG 11 /* Farsi */ -#define SU_LANG 12 /* Finnish */ -#define CF_LANG 13 /* French, Canada */ -#define FR_LANG 14 /* French, France */ -#define GA_LANG 15 /* Galician */ -#define DE_LANG 16 /* German, Germany */ -#define SD_LANG 17 /* German, Switzerland */ -#define GR_LANG 18 /* Greek */ -#define HE_LANG 19 /* Hebrew */ -#define HU_LANG 20 /* Hungarian */ -#define IS_LANG 21 /* Icelandic */ -#define IT_LANG 22 /* Italian */ -#define NO_LANG 23 /* Norwegian */ -#define PL_LANG 24 /* Polish */ -#define BR_LANG 25 /* Portuguese, Brazil */ -#define PO_LANG 26 /* Portuguese, Portugal */ -#define RU_LANG 27 /* Russian */ -#define SL_LANG 28 /* Slovak */ -#define ES_LANG 29 /* Spanish */ -#define SV_LANG 30 /* Swedish */ -#define YK_LANG 31 /* Ukrainian */ -#define UR_LANG 32 /* Urdu */ -#define TK_LANG 33 /* Turkey */ -#define JP_LANG 34 /* Japanese */ -#define KO_LANG 35 /* Korean */ -#define CT_LANG 36 /* Chinese-Traditional */ -#define CS_LANG 37 /* Chinese-Simplified */ -#define LA_LANG 38 /* another asian language */ - -/* defines for languageID */ -/* -WARNING: If adding new languages to LANGUAGE_ID, do NOT alter existing - ID values. Add new languages to the end of the enumeration, just before - ID_LANG_UNKNOWN. -*/ -typedef enum { - ID_LANG_AF, /* Afrikaans */ - ID_LANG_AL, /* Albanian */ - ID_LANG_AR, /* Arabic */ - ID_LANG_BG, /* Bulgarian */ - ID_LANG_CA, /* Catalan */ - ID_LANG_CH, /* Swiss */ - ID_LANG_CN_S, /* Chinese (Simplified) */ - ID_LANG_CN_T, /* Chinese (Traditional) */ - ID_LANG_CS, /* Czech */ - ID_LANG_DA, /* Danish */ - ID_LANG_DE, /* German */ - ID_LANG_DE_CH, /* German-Switzerland */ - ID_LANG_EN_AU, /* Australia */ - ID_LANG_EN_UK, /* U.K. English */ - ID_LANG_EN_US, /* U.S. English */ - ID_LANG_ES, /* Spanish, Castilian */ - ID_LANG_ES_EA, /* Spanish, Latin America */ - ID_LANG_FR, /* French */ - ID_LANG_FR_CA, /* Canadian French */ - ID_LANG_GL, /* Galician */ - ID_LANG_GR, /* Greek */ - ID_LANG_HE, /* Hebrew */ - ID_LANG_HR, /* Croatian */ - ID_LANG_HU, /* Hungarian */ - ID_LANG_IC, /* Icelandic */ - ID_LANG_IT, /* Italian */ - ID_LANG_JP, /* Japanese */ - ID_LANG_KR, /* Korean */ - ID_LANG_NE, /* Dutch (Netherlands) */ - ID_LANG_NO, /* Norwegian - Bokmal */ - ID_LANG_PL, /* Polish */ - ID_LANG_PO, /* Portugese */ - ID_LANG_PO_BR, /* Brazilian Portugese */ - ID_LANG_RO, /* Romanian */ - ID_LANG_RU, /* Russian */ - ID_LANG_SK, /* Slovak */ - ID_LANG_SL, /* Slovenian */ - ID_LANG_SU, /* Finnish */ - ID_LANG_SV, /* Swedish */ - ID_LANG_TR, /* Turkish */ - ID_LANG_AF_WIN, /* Afrikaans */ - ID_LANG_AL_WIN, /* Albanian */ - ID_LANG_AR_WIN, /* Arabic */ - ID_LANG_BG_WIN, /* Bulgarian */ - ID_LANG_CA_WIN, /* Catalan */ - ID_LANG_CH_WIN, /* Swiss */ - ID_LANG_CN_S_WIN, /* Chinese (Simplified) */ - ID_LANG_CN_T_WIN, /* Chinese (Traditional) */ - ID_LANG_CS_WIN, /* Czech */ - ID_LANG_DA_WIN, /* Danish */ - ID_LANG_DE_WIN, /* German */ - ID_LANG_DE_CH_WIN, /* German-Switzerland */ - ID_LANG_EN_AU_WIN, /* Australia */ - ID_LANG_EN_UK_WIN, /* U.K. English */ - ID_LANG_EN_US_WIN, /* U.S. English */ - ID_LANG_ES_WIN, /* Spanish, Castilian */ - ID_LANG_ES_EA_WIN, /* Spanish, Latin America */ - ID_LANG_FR_WIN, /* French */ - ID_LANG_FR_CA_WIN, /* Canadian French */ - ID_LANG_GL_WIN, /* Galician */ - ID_LANG_GR_WIN, /* Greek */ - ID_LANG_HE_WIN, /* Hebrew */ - ID_LANG_HR_WIN, /* Croatian */ - ID_LANG_HU_WIN, /* Hungarian */ - ID_LANG_IC_WIN, /* Icelandic */ - ID_LANG_IT_WIN, /* Italian */ - ID_LANG_JP_WIN, /* Japanese */ - ID_LANG_KR_WIN, /* Korean */ - ID_LANG_NE_WIN, /* Dutch (Netherlands) */ - ID_LANG_NO_WIN, /* Norwegian - Bokmal */ - ID_LANG_PL_WIN, /* Polish */ - ID_LANG_PO_WIN, /* Portugese */ - ID_LANG_PO_BR_WIN, /* Brazilian Portugese */ - ID_LANG_RO_WIN, /* Romanian */ - ID_LANG_RU_WIN, /* Russian */ - ID_LANG_SK_WIN, /* Slovak */ - ID_LANG_SL_WIN, /* Slovenian */ - ID_LANG_SU_WIN, /* Finnish */ - ID_LANG_SV_WIN, /* Swedish */ - ID_LANG_TR_WIN, /* Turkish */ - ID_LANG_AF_ISO, /* Afrikaans */ - ID_LANG_AL_ISO, /* Albanian */ - ID_LANG_AR_ISO, /* Arabic */ - ID_LANG_BG_ISO, /* Bulgarian */ - ID_LANG_CA_ISO, /* Catalan */ - ID_LANG_CH_ISO, /* Swiss */ - ID_LANG_CN_S_ISO, /* Chinese (Simplified) */ - ID_LANG_CN_T_ISO, /* Chinese (Traditional) */ - ID_LANG_CS_ISO, /* Czech */ - ID_LANG_DA_ISO, /* Danish */ - ID_LANG_DE_ISO, /* German */ - ID_LANG_DE_CH_ISO, /* German-Switzerland */ - ID_LANG_EN_AU_ISO, /* Australia */ - ID_LANG_EN_UK_ISO, /* U.K. English */ - ID_LANG_EN_US_ISO, /* U.S. English */ - ID_LANG_ES_ISO, /* Spanish, Castilian */ - ID_LANG_ES_EA_ISO, /* Spanish, Latin America */ - ID_LANG_FR_ISO, /* French */ - ID_LANG_FR_CA_ISO, /* Canadian French */ - ID_LANG_GL_ISO, /* Galician */ - ID_LANG_GR_ISO, /* Greek */ - ID_LANG_HE_ISO, /* Hebrew */ - ID_LANG_HR_ISO, /* Croatian */ - ID_LANG_HU_ISO, /* Hungarian */ - ID_LANG_IC_ISO, /* Icelandic */ - ID_LANG_IT_ISO, /* Italian */ - ID_LANG_JP_ISO, /* Japanese */ - ID_LANG_KR_ISO, /* Korean */ - ID_LANG_NE_ISO, /* Dutch (Netherlands) */ - ID_LANG_NO_ISO, /* Norwegian - Bokmal */ - ID_LANG_PL_ISO, /* Polish */ - ID_LANG_PO_ISO, /* Portugese */ - ID_LANG_PO_BR_ISO, /* Brazilian Portugese */ - ID_LANG_RO_ISO, /* Romanian */ - ID_LANG_RU_ISO, /* Russian */ - ID_LANG_SK_ISO, /* Slovak */ - ID_LANG_SL_ISO, /* Slovenian */ - ID_LANG_SU_ISO, /* Finnish */ - ID_LANG_SV_ISO, /* Swedish */ - ID_LANG_TR_ISO, /* Turkish */ - ID_LANG_RU_KOI8, /* Russian */ - ID_LANG_UNKNOWN -} LANGUAGE_ID; - -// We must not use TA_LANG - taiwanses is chinese simplified. -// You should re-use #39 (TA_LANG) -- it is NOT used for Taiwanese... -// #define TA_LANG 39 /* Taiwanese */ - -/* - LAST_LANG - Used for tables than contain items for each language. - *_DBCS_LANG - Start and end points for double byte languages. -*/ - -#define LAST_LANG (LA_LANG+1) /* last language marker */ -#define FIRST_DBCS_LANG (JP_LANG) -#define LAST_DBCS_LANG (LA_LANG) - -/* VISIT: ACHSETS may be wrong. - check for double wide asian characters */ -#define isAsianSet(set) ((set) >= ACHSMIN && (set) <= ACHSETS) - -/** -*** State table information for double character sorting -**/ - -#define STATE1 1 -#define STATE2 2 -#define STATE3 3 -#define STATE4 4 -#define STATE5 5 -#define STATE6 6 -#define STATE7 7 -#define STATE8 8 -#define STATE9 9 -#define STATE10 10 -#define STATE11 11 -#define AFTERC 12 -#define AFTERH 13 -#define AFTERL 14 -#define INSTAE 15 -#define INSTOE 16 -#define INSTSG 17 -#define INSTIJ 18 -#define WITHAA 19 - -#define START_COL 12 -#define START_ALL (START_COL+1) /* all US and european */ -#define START_DK (START_COL+2) /* Danish */ -#define START_IS (START_COL+3) /* Icelandic */ -#define START_NO (START_COL+4) /* Norwegian */ -#define START_SU (START_COL+5) /* Finnish */ -#define START_SV (START_COL+5) /* Swedish */ -#define START_YK (START_COL+6) /* Ukrain */ -#define START_TK (START_COL+7) /* Turkish */ -#define START_CZ (START_COL+8) /* Czech */ -#define START_SL (START_COL+8) /* Slovak */ - -#define FIXUP_AREA_SIZE 24 /* Number of characters to fix up */ - -#define WPCH_HIMASK 0x00FF -#define WPCH_LOMASK 0xFF00 -#define WPCH_MAX_COMPLEX 5 - -#define UTOWP60_ENTRIES 1502 /* number of entries in WP_UTOWP60[] */ - /* 2042 with WP user defined values in */ -extern FLMBYTE fwp_c60_max[]; -extern FLMUINT16 * WP60toUni[]; -extern FLMUINT16 * WP60toCpxUni[]; -extern FLMUINT16 WP_UTOWP60[][2]; - -#define MULT60_ENTRIES 154 -#define WP60toUni_MAX 15 - -extern FLMUINT16 WPCH_WP60UNI1[]; -extern FLMUINT16 WPCH_WP60UNI2[]; -extern FLMUINT16 WPCH_WPUNI3[]; -extern FLMUINT16 WPCH_WPUNI4[]; -extern FLMUINT16 WPCH_WP60UNI5[]; -extern FLMUINT16 WPCH_WPUNI6[]; -extern FLMUINT16 WPCH_WPUNI7[]; -extern FLMUINT16 WPCH_WP60UNI8[]; -extern FLMUINT16 WPCH_WP60UNI9[]; -extern FLMUINT16 WPCH_WP60UNI10[]; -extern FLMUINT16 WPCH_WP60UNI11[]; -extern FLMUINT16 WPCH_WPUNI13[]; -extern FLMUINT16 WPCH_WPUNI14[]; - -extern FLMUINT16 WPCH_CPXTAB1[][5]; -extern FLMUINT16 WPCH_CPXGREEK[][5]; -extern FLMUINT16 WPCH_CPXHEBREW[][5]; -extern FLMUINT16 WPCH_CPXARABIC[][5]; -extern FLMUINT16 WPCH_CPXARABIC2[][5]; -extern FLMUINT16 WPCH_CPXCYRILLIC[][5]; - -extern BASE_DIACRIT * fwp_car60_c[]; -extern FLMBYTE fwp_ml1_cb60[]; -extern FLMBYTE fwp_max_car60_size; - -typedef struct { - FLMBYTE key; - FLMBYTE * charPtr; -} TBL_B_TO_BP; - -extern TBL_B_TO_BP fwp_col60Tbl[]; -extern FLMUINT16 fwp_indexi[]; -extern FLMUINT16 fwp_indexj[]; -extern FLMUINT16 fwp_valuea[]; -extern TBL_B_TO_BP fwp_HebArabicCol60Tbl[]; - -FLMBYTE GedTextObjType( - FLMBYTE c ); - -#define GedTextObjType(c) ( \ - (((c & ASCII_CHAR_MASK) == ASCII_CHAR_CODE) \ - ? ASCII_CHAR_CODE \ - : (((c & WHITE_SPACE_MASK) == WHITE_SPACE_CODE) \ - ? WHITE_SPACE_CODE \ - : (((c & UNK_EQ_1_MASK) == UNK_EQ_1_CODE) \ - ? UNK_EQ_1_CODE \ - : (((c & CHAR_SET_MASK) == CHAR_SET_CODE) \ - ? CHAR_SET_CODE \ - : c \ - ) \ - ) \ - ) \ - ) \ -) - -/* Bit patterns for codes in internal TEXT type */ -/* - ASCII_CHAR - 0x20..0x7E - CHAR_SET - WP Char sets from 1 to 63 - WHITE_SPACE - -*/ -#define ASCII_CHAR_CODE 0x00 /* 0nnnnnnn */ -#define ASCII_CHAR_MASK 0x80 /* 10000000 */ -#define CHAR_SET_CODE 0x80 /* 10nnnnnn */ -#define CHAR_SET_MASK 0xC0 /* 11000000 */ -#define WHITE_SPACE_CODE 0xC0 /* 110nnnnn */ -#define WHITE_SPACE_MASK 0xE0 /* 11100000 */ - -// UNK_GT_255 is an outdated code not part of 3x or newer -#define UNK_GT_255_CODE 0xE0 /* 11100nnn */ -#define UNK_GT_255_MASK 0xF8 /* 11111000 */ -#define UNK_EQ_1_CODE 0xF0 /* 11110nnn */ -#define UNK_EQ_1_MASK 0xF8 /* 11111000 */ - -// UNK_LE_255 is an outdated code not part of 3x or newer -#define UNK_LE_255_CODE 0xF8 /* 11111nnn */ -#define UNK_LE_255_MASK 0xF8 /* 11111000 */ -#define EXT_CHAR_CODE 0xE8 /* 11101000 */ -#define OEM_CODE 0xE9 /* 11101001 */ -#define UNICODE_CODE 0xEA /* 11101010 */ - -/* The Heart is what Novell NDS is using if a Unicode character */ -/* cannot be converted into the current ANSI/ASCII code page */ - -#define UNICODE_UNCONVERTABLE_CHAR 0x03 /* Heart */ - -/* Type codes to go with UNK_GT_255_CODE, UNK_EQ_1_CODE, and */ -/* UNK_LE_255_CODE -- maximum of 8 */ - -#define WP60_TYPE 1 -#define NATIVE_TYPE 2 - -// The HYPHEN's in 3x and 4x don't exist in the database. -#define HARD_HYPHEN 3 -#define HARD_HYPHEN_EOL 4 -#define HARD_HYPHEN_EOP 5 -#define HARD_RETURN 7 -#define NATIVE_TAB 12 -#define NATIVE_LINEFEED 13 - -/** -*** Max Buffer sizes -**/ - -// GWBUG 30,645 - Had 200 and 70 - the 200 for max subcol was not -// enough for the sset and JP characters - computed wrong. -// This crashed the process that was building a key of sset characaters. - -#define MAX_SUBCOL_BUF (500) /* (((MAX_KEY_SIZ / 4) * 3 + fluff */ -#define MAX_LOWUP_BUF (150) /* ((MAX_KEY_SIZ -(MAX_KEY_SIZ / 8)) / 8)*2*/ - - -/* -*** Simple portable UWORD-->BYTE<--UWORD conversions -*** Word to High/Low byte convertsions - WP set # is high byte value -*** -*** If there are portability problems then put #ifdef machine -*** or find a macro within swp.h or toolkit to use. -*** The definition works great for LITENDIN or other machines. -**/ - -#define F_GETLOWBYTE(w) ((FLMBYTE)(w)) -#define F_GETHIGHBYTE(w) ((FLMBYTE)((w) >> 8)) - -/* FLAGS */ -#define HAD_SUB_COLLATION 0x01 /* Set if had sub-collating values-diacritics*/ -#define HAD_LOWER_CASE 0x02 /* Set if you hit a lowercase character */ - - -#define COMPOUND_MARKER 0x02 /* Compound key marker between each piece */ -#define END_COMPOUND_MARKER 0x01 /* Last of all compound markers - for post*/ - /* This must be < CM because of multiple */ - /* COMPOUND_MARKERS that could appear */ -#define NULL_KEY_MARKER 0x03 -#define COLL_FIRST_SUBSTRING 0x03 /* First substring marker */ - -#define COLL_MARKER 0x04 /* Marks place of sub-collation */ - -#define SC_LOWER 0x00 /* Only lowercase characters exist */ -#define SC_MIXED 0x01 /* Lower/uppercase flags follow in next byte*/ -#define SC_UPPER 0x02 /* Only upper characters exist */ -#define SC_SUB_COL 0x03 /* Sub-collation follows (diacritics|extCh) */ - -#define UNK_UNICODE_CODE 0xFFFE /* Used for collation */ - -/* In the future a SUB_COL-1 value could mean leading information */ - -// Leave room for stuff before truncated value. -#define COLL_TRUNCATED 0x0C /* This key piece has been truncated from original*/ - -/* Max. opcode for any collation markers - was 7 before Nov 98 */ -#define MAX_COL_OPCODE COLL_TRUNCATED - - -#define BYTES_IN_BITS(bits) ((bits + 7) >> 3) /* Computes # of bytes */ - -#define TEST1BIT( buf, bPos) ((((buf)[ (bPos) >> 3]) >> (7 - ((bPos) & 7))) & 1) -#define GET1BIT( buf, bPos) ((((buf)[ (bPos) >> 3]) >> (7 - ((bPos) & 7))) & 1) - -#define GETnBITS( n, bf, bit) \ -(((unsigned int)( \ - ((unsigned char)bf[ (bit) >> 3] << 8)/* append high bits (byte 1) to ... */\ - | \ - (unsigned char)bf[ ((bit) >> 3) + 1] /* ... overflow bits in 2nd byte */\ - ) >> (16 - (n) - ((bit) & 7)) /* reposition to low end of value */\ - ) & ((1 << (n)) - 1) /* mask off high bits */\ -) /* return value */ - -#define SET_BIT(buf,bPos) ((buf)[(bPos) >> 3] |= (FLMBYTE)((1 << (7 - ((bPos) & 7))))) - -#define RESET_BIT(buf,bPos) ((buf)[(bPos) >> 3] &= (FLMBYTE)(~(1 << (7 - ((bPos) & 7))))) - -#define SETnBITS( n, bf, bit, v) \ - { (bf)[ (bit) >> 3] |= /* 1st byte */\ - (FLMBYTE)(((v) << (8 - (n))) /* align to bit 0 */\ - >> \ - ((bit) & 7)); /* re-align to actual bit position */\ - (bf)[ ((bit) >> 3) + 1] = /* 2nd byte */\ - (FLMBYTE)((v) \ - << \ - (16 - (n) - ((bit) & 7))); /* align spill-over bits */\ - } - - -/* Defines for numeric collation/uncollation */ - -#define SIG_POS 0x80 -#define COLLATED_DIGIT_OFFSET 0x05 -#define COLLATED_NUM_EXP_BIAS 64 -#define MIN_7BIT_EXP 0x08 -#define MAX_7BIT_EXP 0x78 - -RCODE FTextToColStr( - const FLMBYTE * str, /* Points to the internal TEXT string */ - FLMUINT uiStrLen, /* Length of the internal TEXT string */ - FLMBYTE * colStr, /* Output collated string */ - FLMUINT * puiColStrLen, /* Collated string length return value */ - /* Input value is MAX num of bytes in buffer*/ - FLMUINT uiUppercaseFlag, /* If set then treat string like uppercase */ - FLMUINT * puiCollationLen, /* Returns the collation bytes length */ - FLMUINT * puiCaseLen, /* Returns length of case area */ - FLMUINT uiWPLang, /* WP Language using Flaim language number */ - FLMUINT uiCharLimit, - FLMBOOL bFirstSubstring, - FLMBOOL * pbOriginalCharsLost, - FLMBOOL * pbDataTruncated); - -FLMUINT FColStrToText( /* Returns strlen of null term output string */ - FLMBYTE * ColStr, /* Points to the FLAIM collated string */ - FLMUINT * puiColStrLenRV, /* FLAIM Collated string length return value */ - FLMBYTE * textStr, /* Output text string buffer */ - FLMUINT uiWPLang, /* WP Language using Flaim language number */ - FLMBYTE * postBuf, /* Lower/upper POST buffer or NULL */ - FLMUINT * postBytesRV, /* Returns number bytes used in post buffer */ - FLMBOOL * pbDataTruncated, - FLMBOOL * pbFirstSubstring); - -RCODE AsiaFlmTextToColStr( - const FLMBYTE * Str, /* Points to the internal TEXT string */ - FLMUINT uiStrLen, /* Length of the internal TEXT string */ - FLMBYTE * ColStr, /* Output collated string */ - FLMUINT * puiColStrLenRV, /* Collated string length return value */ - /* Input value is MAX num of bytes in buffer*/ - FLMUINT uiUppercaseFlag, /* Set if to convert to uppercase */ - FLMUINT * puiCollationLen, /* Returns the collation bytes length */ - FLMUINT * puiCaseLenRV, /* Returns length of case bytes */ - FLMUINT uiCharLimit, - FLMBOOL bFirstSubstring, - FLMBOOL * pbDataTruncated); - -FLMUINT AsiaConvertColStr( - FLMBYTE * CollatedStr, /* Points to the Flaim collated string */ - FLMUINT * puiCollatedStrLenRV, /* Length of the Flaim collated string */ - FLMBYTE * WordStr, /* Output string to build - WP word string */ - FLMBOOL * pbDataTruncated, - FLMBOOL * pbFirstSubstring); - -FLMUINT AsiaParseSubCol( - FLMBYTE * WordStr, /* Existing word string to modify */ - FLMUINT * puiWordStrLen, /* Wordstring length in bytes */ - FLMBYTE * SubColBuf); /* Diacritic values in 5 bit sets */ - -FLMUINT AsiaParseCase( - FLMBYTE * WordStr, /* Existing word string to modify */ - FLMUINT * uiWordStrLenRV, /* Length of the WordString in bytes */ - FLMBYTE * pCaseBits); /* Lower/upper case bit string */ - -typedef struct -{ - FLMBYTE ByteValue; - FLMUINT16 WordValue; -} BYTE_WORD_TBL; - -FLMUINT16 fwpCh6Upper( - FLMUINT16 ui16WpChar); - -FLMBOOL fwpIsUpper( - FLMUINT16 ui16Char); - -FLMUINT16 fwpCh6Lower( - FLMUINT16 ui16WpChar); - -FLMBOOL fwpCh6Brkcar( - FLMUINT16 ui16WpChar, - FLMUINT16 * pui16BaseChar, - FLMUINT16 * pui16DiacriticChar); - -FLMBOOL fwpCh6Cmbcar( - FLMUINT16 * pui16WpChar, - FLMUINT16 ui16BaseChar, - FLMINT16 i16DiacriticChar); - -FLMUINT16 fwpGetCollation( - FLMUINT16 ui16WpChr, - FLMUINT uiLang); - -FLMUINT16 fwpCheckDoubleCollation( - FLMUINT16 * pui16WpChar, - FLMBOOL * pbTwoIntoOne, - const FLMBYTE ** ppucInputStr, - FLMUINT uiLanguage); - -FLMUINT16 fwpAsiaGetCollation( - FLMUINT16 WpChar, - FLMUINT16 NextChar, - FLMUINT16 PrevColValue, - FLMUINT16 * ColValueRV, - FLMUINT16 * SubColValRV, - FLMBYTE * CaseFlagsRV, - FLMUINT16 UppercaseFlag); - -FLMUINT16 ZenToHankaku( - FLMUINT16 WpChar, - FLMUINT16 * DakutenOrHandakutenRV); - -FLMUINT16 HanToZenkaku( - FLMUINT16 WpChar, - FLMUINT16 NextChar, - FLMUINT16 * ZenkakuRV ); - -#include "fpackoff.h" - -#endif diff --git a/flaim/src/funicode.cpp b/flaim/src/funicode.cpp deleted file mode 100644 index f54073b..0000000 --- a/flaim/src/funicode.cpp +++ /dev/null @@ -1,551 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Unicode functions. -// Tabs: 3 -// -// Copyright (c) 1999-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: funicode.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC FLMUINT flmUnicodeToWP( - const FLMUNICODE * puzUniStr, - FLMUINT16 * pWPChr); - -/**************************************************************************** -Desc: Returns the size of buffer needed to hold the unicode string in - FLAIM's storage format. -****************************************************************************/ -FLMEXP FLMUINT FLMAPI FlmGetUnicodeStorageLength( - const FLMUNICODE * puzStr) -{ - FLMBYTE chrSet; - FLMUINT uiStorageLength = 0; - FLMUINT uniLength; - FLMUINT16 wp60Buf[12]; - - flmAssert( puzStr != NULL); - - // Two passes are needed to store a UNICODE string: - // 1st pass determines the storage length (via FlmGetUnicodeStorageLength) - // 2nd pass stores the string into FLAIMs internal text format - // (via FlmUnicode2Storage). - - do - { - // Cannot check for A..Z because flmUnicodeToWP may convert - // multiple Unicode characters into 1 WP char - (D-slash) - // This 'complex' convert code is defined out. - // - // Personally, I don't think this should ever be done, but the - // conversions must be looked at. The hard part of all of this - // is deciding if we should have perfect UNI-->WP60-->UNI where - // the 2nd UNI is exactly the same as the first. - // - // For the NDS project, this code MUST have exact conversions. - - if( *puzStr < 0x20) - { - uniLength = 1; - uiStorageLength += 3; - } - else - { - // This is a speed good optimization. - - if( *puzStr < 0x7F) - { - uiStorageLength++; - puzStr++; - continue; - } - - uniLength = flmUnicodeToWP( puzStr, wp60Buf); - - if( !uniLength) - { - uiStorageLength += 3; - uniLength = 1; - } - else - { - if( (chrSet = (FLMBYTE) (wp60Buf[0] >> 8)) == 0) - { - uiStorageLength++; - } - else - { - uiStorageLength += (chrSet <= 63) ? 2 : 3; - } - } - } - puzStr += uniLength; - - } while( *puzStr != 0 ); - - return( uiStorageLength); -} - -/**************************************************************************** -Desc: Copies and formats a Unicode string into FLAIM's storage format. - The Unicode string must be in little endian format. - Unicode values that are not represented as WordPerfect 6.x characters - are preserved as non-WP characters. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmUnicode2Storage( - const FLMUNICODE * puzStr, - FLMUINT * puiBufLength, - FLMBYTE * pBuf) -{ - FLMBYTE chrSet; - FLMUINT16 wp60Buf[ 12]; - FLMUINT uiStorageLength = 0; - FLMUINT uniLength; - - flmAssert( puzStr != NULL); - flmAssert( pBuf != NULL); - - do - { - if( *puzStr < 0x20 ) - { - // Output the character as an unconvertable unicode character. - - *pBuf++ = UNICODE_CODE; - *pBuf++ = *puzStr >> 8; - *pBuf++ = (FLMBYTE) *puzStr; - uniLength = 1; - uiStorageLength += 3; - } - else - { - if( *puzStr < 0x7F) - { - uiStorageLength++; - *pBuf++ = (FLMBYTE)*puzStr++; - continue; - } - - uniLength = flmUnicodeToWP( puzStr, wp60Buf); - - if( !uniLength) - { - *pBuf++ = UNICODE_CODE; - *pBuf++ = *puzStr >> 8; - *pBuf++ = (FLMBYTE)*puzStr; - uniLength = 1; - uiStorageLength += 3; - } - else - { - chrSet = wp60Buf[0] >> 8; - - if( chrSet == 0) - { - *pBuf++ = (FLMBYTE) wp60Buf[0]; - uiStorageLength++; - } - else if( chrSet <= 63) - { - *pBuf++ = CHAR_SET_CODE | chrSet; - *pBuf++ = (FLMBYTE) wp60Buf[0]; - uiStorageLength += 2; - } - else - { - *pBuf++ = EXT_CHAR_CODE; - *pBuf++ = chrSet; - *pBuf++ = (FLMBYTE) wp60Buf[0]; - uiStorageLength += 3; - } - } - } - puzStr += uniLength; - - // Make sure input buffer was large enough - - if( *puiBufLength < uiStorageLength) - { - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - } - - } while( *puzStr != 0); - - *puiBufLength = uiStorageLength; - return( FERR_OK ); -} - -/**************************************************************************** -Desc: Convert from Unicode to 1 and only 1 WP60 character -Ret: Conversion Count - 0 means Unicode character could not be converted. -Notes: See commented out code below this for real neat multiple character - conversions. We don't really want this so that the original - UNICODE characters are preserved on get/put as much as possible. - Code copied from WPTEXT\WPCHU.C in WpChUUniToWPLang() because - of the multiple character conversion and that we only do one - character at a time for both interfaces. - Called from the UNICODE put routine above and QuickFinder - UNICODE to WP conversion. -****************************************************************************/ -FSTATIC FLMUINT flmUnicodeToWP( - const FLMUNICODE * pUniStr, - FLMUINT16 * pWPChr) -{ - FLMUINT uiReturnLen = 1; - FLMUNICODE uzUniChar = *pUniStr; - FLMINT16 max; - FLMINT16 min; - FLMINT16 temp; - FLMUINT16 * tablePtr; - FLMUINT16 tblChr; - - if( uzUniChar < 127) - { - *pWPChr = uzUniChar; - goto Exit; - } - - tablePtr = (FLMUINT16 *) WP_UTOWP60; - - // Value we should use ... max = UTOWP60_ENTRIES - 1; - // Bug introduced before Nov99 where UTOWP60_ENTRIES is actually 1502 - // and the value of 2042 was used. Through debugging, all values in the - // table from 1021 to 1502 were never converted to WP character. So, in order - // to search correctly on these values we must preserve the WRONG conversion - // of these characters (Unicode x222E on). The new max table size is 1021 so - // max will be set to 1020 to work correctly. - - max = 1020; - min = 0; - - do - { - temp = (min+max) >> 1; - tblChr = *(tablePtr+(temp*2)); - if( tblChr < uzUniChar ) - { - min = temp+1; - } - else if( tblChr > uzUniChar ) - { - max = temp-1; - } - else - { - *pWPChr = *(tablePtr + (temp*2) + 1); - goto Exit; - } - - } while( min <= max); - - uiReturnLen = 0; - -Exit: - - return( uiReturnLen ); -} - -/**************************************************************************** -Desc: Converts storage formats to UNICODE. -****************************************************************************/ -FLMEXP RCODE FLMAPI FlmStorage2Unicode( - FLMUINT uiValueType, - FLMUINT uiValueLength, - const FLMBYTE * pucValue, - FLMUINT * puiStrBufLen, - FLMUNICODE * puzStrBuf) -{ - FLMUNICODE * tablePtr; - FLMBYTE c; - FLMUINT bytesProcessed = 0; - FLMUINT bytesOutput = 0; - FLMUINT outputData; - FLMUINT maxOutLen; - FLMBYTE objType; - FLMUINT objLength = 0; - FLMBYTE tempBuf[ 80]; - FLMBYTE chrSet, chrVal; - FLMUNICODE newChrVal; - RCODE rc = FERR_OK; - - // If the value is a number, convert to text first - - if( uiValueType != FLM_TEXT_TYPE) - { - if( pucValue == NULL) - { - uiValueLength = 0; - } - else - { - if( uiValueType == FLM_NUMBER_TYPE) - { - uiValueLength = sizeof( tempBuf); - rc = GedNumToText( pucValue, tempBuf, &uiValueLength); - } - else - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - - if( RC_BAD(rc)) - { - goto Exit; - } - - pucValue = &tempBuf[ 0]; - } - } - - maxOutLen = *puiStrBufLen; - outputData = ((puzStrBuf != NULL) && (maxOutLen > 1)); - - if( outputData) - { - maxOutLen -= 2; - } - - // Parse through the string outputting data to the buffer as we go - - while( bytesProcessed < uiValueLength) - { - // Determine what we are pointing at - - c = *pucValue; - objType = GedTextObjType( c); - switch( objType) - { - case ASCII_CHAR_CODE: - objLength = 1; - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - *puzStrBuf++ = c; - } - bytesOutput += 2; - break; - - case CHAR_SET_CODE: - objLength = 2; - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - // Convert WP to UNICODE - - chrSet = c & 0x3F; - chrVal = *(pucValue + 1); - - goto ConvertWPToUni; - } - - bytesOutput += 2; - break; - - case WHITE_SPACE_CODE: - objLength = 1; - - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - if( c == (WHITE_SPACE_CODE | NATIVE_TAB)) - { - *puzStrBuf = (FLMUNICODE) 9; - } - else if( c == (WHITE_SPACE_CODE | NATIVE_LINEFEED)) - { - *puzStrBuf = (FLMUNICODE) 10; - } - else if( c == (WHITE_SPACE_CODE | HARD_RETURN)) - { - *puzStrBuf = (FLMUNICODE) 13; - } - else - { - *puzStrBuf = (FLMUNICODE) 0x20; - } - - puzStrBuf++; - } - - bytesOutput += 2; - break; - - case EXT_CHAR_CODE: - objLength = 3; - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - // Convert back from WP to UNICODE - - chrSet = *(pucValue + 1); - chrVal = *(pucValue + 2); - -ConvertWPToUni: - - // Code taken from _WpChWPToUni() in WPTEXT\WPCHU.C - // There should always be a chrSet value. - - if( (chrSet < WP60toUni_MAX) && - ((tablePtr = WP60toUni[ chrSet ]) != 0 )) - { - FLMUNICODE * pCpxUniStr; - - newChrVal = tablePtr[ chrVal]; - - if ((newChrVal & WPCH_LOMASK) == 0xF000) - { - /* - ** Does character convert to many Unicode chars? - ** Yes: Use complex character table - ** Move to the correct location in the table - */ - - pCpxUniStr = WP60toCpxUni[chrSet]; - pCpxUniStr += (newChrVal & WPCH_HIMASK) * WPCH_MAX_COMPLEX; - - while( *pCpxUniStr) - { - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - *puzStrBuf++ = *pCpxUniStr++; - } - bytesOutput += 2; - } - } - else - { - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - *puzStrBuf++ = newChrVal; - } - bytesOutput += 2; - } - } - else - { - // Big extended WP char - - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - *puzStrBuf++ = 0x03; - } - - bytesOutput += 2; - } - } - break; - - case OEM_CODE: - - // We always just skip OEM codes - - objLength = 2; - break; - - case UNICODE_CODE: - objLength = 3; - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - - *puzStrBuf++ = (*(pucValue + 1) << 8) + *(pucValue + 2); - } - bytesOutput += 2; - break; - - case UNK_EQ_1_CODE: - objLength = 2; - if( outputData) - { - if( (maxOutLen < 2) || (bytesOutput > maxOutLen - 2)) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto GedGetUNICODE_Output; - } - *puzStrBuf++ = *(pucValue+1); - } - bytesOutput += 2; - break; - - default: - flmAssert(0); - bytesProcessed = uiValueLength; - break; - } - pucValue += objLength; - bytesProcessed += objLength; - } - - // Add TWO terminating NULL characters, but DO NOT increment the - // bytesOutput counter! - -GedGetUNICODE_Output: - - if( outputData) - { - *puzStrBuf = 0; - } - - *puiStrBufLen = bytesOutput; - -Exit: - - return( rc); -} diff --git a/flaim/src/fwin.cpp b/flaim/src/fwin.cpp index a585b38..2585dfe 100644 --- a/flaim/src/fwin.cpp +++ b/flaim/src/fwin.cpp @@ -25,22 +25,21 @@ #include "flaimsys.h" #if defined( FLM_WIN) - -extern RCODE gv_CriticalFSError; - -FSTATIC RCODE _DeleteFile( - const char * path); - + extern RCODE gv_CriticalFSError; + + FSTATIC RCODE _DeleteFile( + const char * path); +#endif /*************************************************************************** Desc: Maps WIN errors to IO errors. ***************************************************************************/ +#if defined( FLM_WIN) RCODE MapWinErrorToFlaim( DWORD udErrCode, RCODE defaultRc) { - - /* Switch on passed in error code value */ + // Switch on passed in error code value switch (udErrCode) { @@ -119,10 +118,12 @@ RCODE MapWinErrorToFlaim( } } +#endif /**************************************************************************** Desc: Default Constructor for F_FileHdl class ****************************************************************************/ +#if defined( FLM_WIN) F_FileHdlImp::F_FileHdlImp() { m_FileHandle = INVALID_HANDLE_VALUE; @@ -139,10 +140,12 @@ F_FileHdlImp::F_FileHdlImp() m_bCanDoAsync = FALSE; // Change to TRUE when we want to do async writes. m_Overlapped.hEvent = NULL; } +#endif /**************************************************************************** Desc: Destructor for F_FileHdl class ****************************************************************************/ +#if defined( FLM_WIN) F_FileHdlImp::~F_FileHdlImp() { // Close file if it was open. @@ -151,6 +154,7 @@ F_FileHdlImp::~F_FileHdlImp() { (void)Close(); } + if (m_pucAlignedBuff) { f_mutexLock( gv_FlmSysData.hShareMutex); @@ -164,15 +168,18 @@ F_FileHdlImp::~F_FileHdlImp() m_pucAlignedBuff = NULL; m_uiAlignedBuffSize = 0; } + if (m_Overlapped.hEvent) { CloseHandle( m_Overlapped.hEvent); } } +#endif /*************************************************************************** Desc: Open or create a file. ***************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::OpenOrCreate( const char * pFileName, FLMUINT uiAccess, @@ -253,9 +260,7 @@ RCODE F_FileHdlImp::OpenOrCreate( m_bCanDoAsync = gv_FlmSysData.bOkToDoAsyncWrites; } - /* - Set up the file characteristics requested by caller. - */ + // Set up the file characteristics requested by caller. if (uiAccess & F_IO_SH_DENYRW) { @@ -277,13 +282,14 @@ RCODE F_FileHdlImp::OpenOrCreate( udShareMode = (FILE_SHARE_READ | FILE_SHARE_WRITE); } - /* Begin setting the CreateFile flags and fields */ + // Begin setting the CreateFile flags and fields udAttrFlags = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; if (m_bDoDirectIO) { udAttrFlags |= FILE_FLAG_NO_BUFFERING; } + if (m_bCanDoAsync) { udAttrFlags |= FILE_FLAG_OVERLAPPED; @@ -312,7 +318,7 @@ RCODE F_FileHdlImp::OpenOrCreate( Retry_Create: - /* Try to create or open the file */ + // Try to create or open the file if( (m_FileHandle = CreateFile( (LPCTSTR)pFileName, udAccessMode, udShareMode, NULL, udCreateMode, @@ -326,7 +332,7 @@ Retry_Create: uiAccess &= ~F_IO_CREATE_DIR; - /* Remove the file name for which we are creating the directory. */ + // Remove the file name for which we are creating the directory if( RC_OK( f_pathReduce( szSaveFileName, ioDirPath, szTemp))) { @@ -340,6 +346,7 @@ Retry_Create: } } } + rc = MapWinErrorToFlaim( udErrCode, (RCODE)(bCreateFlag ? (RCODE)(m_bDoDirectIO @@ -350,20 +357,25 @@ Retry_Create: : (RCODE)FERR_OPENING_FILE))); goto Exit; } + Exit: + if (RC_BAD( rc)) { m_FileHandle = INVALID_HANDLE_VALUE; } + return( rc ); } +#endif /**************************************************************************** Desc: Create a file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Create( const char * pszIoPath, - FLMUINT uiIoFlags ) + FLMUINT uiIoFlags) { RCODE rc = FERR_OK; @@ -387,10 +399,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::CreateUnique( char * pszIoPath, const char * pszFileExtension, @@ -487,10 +501,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Open a file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Open( const char * pszIoPath, FLMUINT uiIoFlags) @@ -534,10 +550,12 @@ Exit: return( rc); } +#endif /**************************************************************************** Desc: Close a file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Close( void) { FLMBOOL bDeleteAllowed = TRUE; @@ -583,11 +601,13 @@ Exit: return( rc); } +#endif /**************************************************************************** -Desc: Does nothing. +Desc: ****************************************************************************/ -RCODE F_FileHdlImp::Flush() +#if defined( FLM_WIN) +RCODE F_FileHdlImp::Flush( void) { RCODE rc = FERR_OK; @@ -604,10 +624,12 @@ RCODE F_FileHdlImp::Flush() } return( rc); } +#endif /**************************************************************************** Desc: Allocate an aligned buffer. ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::AllocAlignBuffer( void) { RCODE rc = FERR_OK; @@ -618,6 +640,7 @@ RCODE F_FileHdlImp::AllocAlignBuffer( void) // boundary if it is not already on one. m_uiAlignedBuffSize = RoundToNextSector( 64 * 1024); + if ((m_pucAlignedBuff = (FLMBYTE *)VirtualAlloc( NULL, (DWORD)m_uiAlignedBuffSize, MEM_COMMIT, PAGE_READWRITE)) == NULL) @@ -625,6 +648,7 @@ RCODE F_FileHdlImp::AllocAlignBuffer( void) rc = MapWinErrorToFlaim( GetLastError(), FERR_MEM); goto Exit; } + f_mutexLock( gv_FlmSysData.hShareMutex); gv_FlmSysData.SCacheMgr.Usage.uiTotalBytesAllocated += m_uiAlignedBuffSize; @@ -633,16 +657,17 @@ RCODE F_FileHdlImp::AllocAlignBuffer( void) Exit: return( rc); } +#endif /**************************************************************************** Desc: Position and do a single read operation. ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::DoOneRead( DWORD udReadOffset, DWORD udBytesToRead, LPVOID pvReadBuffer, - LPDWORD pudBytesRead - ) + LPDWORD pudBytesRead) { RCODE rc = FERR_OK; OVERLAPPED * pOverlapped; @@ -707,14 +732,18 @@ RCODE F_FileHdlImp::DoOneRead( goto Exit; } } + Exit: + return( rc); } +#endif /**************************************************************************** Desc: Read from a file - reads using aligned buffers and offsets - only sector boundaries ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::DirectRead( FLMUINT uiReadOffset, FLMUINT uiBytesToRead, @@ -826,11 +855,14 @@ RCODE F_FileHdlImp::DirectRead( { udBytesRead = (DWORD)uiBytesToRead; } + uiBytesToRead -= (FLMUINT)udBytesRead; + if( puiBytesReadRV) { (*puiBytesReadRV) += (FLMUINT)udBytesRead; } + m_uiCurrentPos = uiReadOffset + (FLMUINT)udBytesRead; // If using a different buffer for reading, copy the @@ -840,8 +872,11 @@ RCODE F_FileHdlImp::DirectRead( { f_memcpy( pucDestBuffer, pucReadBuffer, udBytesRead); } + if (!uiBytesToRead) + { break; + } // Still more to read - did we hit EOF above? @@ -850,17 +885,21 @@ RCODE F_FileHdlImp::DirectRead( rc = RC_SET( FERR_IO_END_OF_FILE); break; } + pucDestBuffer += udBytesRead; uiReadOffset += (FLMUINT)udBytesRead; } Exit: - return( rc ); + + return( rc); } +#endif /**************************************************************************** Desc: Read from a file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Read( FLMUINT uiReadOffset, FLMUINT uiBytesToRead, @@ -917,12 +956,15 @@ RCODE F_FileHdlImp::Read( } Exit: - return( rc ); + + return( rc); } +#endif /**************************************************************************** Desc: Sets current position of file. ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Seek( FLMUINT uiOffset, FLMINT iWhence, @@ -954,14 +996,19 @@ RCODE F_FileHdlImp::Seek( rc = RC_SET( FERR_NOT_IMPLEMENTED); goto Exit; } + *puiNewOffset = m_uiCurrentPos; + Exit: + return( rc); } +#endif /**************************************************************************** Desc: Return the size of the file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Size( FLMUINT * puiSize) { @@ -978,13 +1025,17 @@ RCODE F_FileHdlImp::Size( rc = MapWinErrorToFlaim( GetLastError(), FERR_GETTING_FILE_SIZE); goto Exit; } + Exit: - return( rc ); + + return( rc); } +#endif /**************************************************************************** Desc: Returns m_uiCurrentPos ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Tell( FLMUINT * puiOffset) { @@ -1001,12 +1052,14 @@ Exit: return( rc ); } +#endif /**************************************************************************** Desc: Truncate the file to the indicated size WARNING: Direct IO methods are calling this method. Make sure that all changes to this method work in direct IO mode. ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Truncate( FLMUINT uiSize) { @@ -1037,20 +1090,23 @@ RCODE F_FileHdlImp::Truncate( rc = MapWinErrorToFlaim( GetLastError(), FERR_TRUNCATING_FILE); goto Exit; } + Exit: + return( rc); } +#endif /**************************************************************************** Desc: Handles when a file is extended in direct IO mode. May extend the file some more. Will always call FlushFileBuffers to ensure that the new file size gets written out. ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::extendFile( - FLMUINT uiEndOfLastWrite, // Must be on a sector boundary - FLMUINT uiMaxBytesToExtend, - FLMBOOL bFlush - ) + FLMUINT uiEndOfLastWrite, // Must be on a sector boundary + FLMUINT uiMaxBytesToExtend, + FLMBOOL bFlush) { RCODE rc = FERR_OK; FLMUINT uiTotalBytesToExtend; @@ -1201,12 +1257,15 @@ RCODE F_FileHdlImp::extendFile( } Exit: + return( rc); } +#endif /**************************************************************************** Desc: Write to a file using direct IO ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::DirectWrite( FLMUINT uiWriteOffset, FLMUINT uiBytesToWrite, @@ -1549,10 +1608,12 @@ Exit: return( rc ); } +#endif /**************************************************************************** Desc: Write to a file ****************************************************************************/ +#if defined( FLM_WIN) RCODE F_FileHdlImp::Write( FLMUINT uiWriteOffset, FLMUINT uiBytesToWrite, @@ -1663,32 +1724,34 @@ RCODE F_FileHdlImp::Write( } Exit: - return( rc ); + + return( rc); } +#endif /**************************************************************************** Desc: Deletes a file. ****************************************************************************/ +#if defined( FLM_WIN) FSTATIC RCODE _DeleteFile( const char * path) { RCODE rc = FERR_OK; - /* Delete the file */ if( DeleteFile( (LPTSTR)path) == FALSE) { rc = MapWinErrorToFlaim( GetLastError(), FERR_DELETING_FILE); } return( rc); -} +} +#endif -#else - #if defined( FLM_NLM) && !defined( __MWERKS__) - int gv_iXxxxxDummy( void) - { - return( 0); - } - #endif -#endif // #if defined( FLM_WIN) +/**************************************************************************** +Desc: +****************************************************************************/ +int fwinDummy( void) +{ + return( 0); +} diff --git a/flaim/src/fwpasia.cpp b/flaim/src/fwpasia.cpp deleted file mode 100644 index 0c9ef7f..0000000 --- a/flaim/src/fwpasia.cpp +++ /dev/null @@ -1,1078 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Collation for Asian languages. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1994-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fwpasia.cpp 12301 2006-01-19 15:02:55 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define SET_CASE_BIT 0x01 -#define SET_KATAKANA_BIT 0x01 -#define SET_WIDTH_BIT 0x02 -#define COLS_ASIAN_MARKS 0x140 - - -extern FLMBYTE fwp_dia60Tbl[]; /* Diacritic conversions */ - -/**---------------------------------------------- -*** Tables -*** The tables below were taken from the -*** following files: -*** XCH2COL.ASM -*** CMPWS.ASM - k_diac (KanaSubColTbl[]) -***---------------------------------------------*/ - -/**--------------------------------------------- -*** Map special chars in CharSet (x24) to -*** collation values -***--------------------------------------------*/ - -BYTE_WORD_TBL fwp_Ch24ColTbl[] = /* Position in the table+1 is subColValue */ -{ - {1, COLLS+2}, /* comma */ - {2, COLLS+1}, /* maru */ - {5, COLS_ASIAN_MARKS+2}, /* chuuten */ - {10, COLS_ASIAN_MARKS}, /* dakuten */ - {11, COLS_ASIAN_MARKS+1}, /* handakuten */ - {43, COLS2+2}, /* angled brackets */ - {44, COLS2+3}, /* */ - {49, COLS2+2}, /* pointy brackets */ - {50, COLS2+3}, - {51, COLS2+2}, /* double pointy brackets */ - {52, COLS2+3}, - {53, COLS1}, /* Japanese quotes */ - {54, COLS1}, - {55, COLS1}, /* hollow Japanese quotes */ - {56, COLS1}, - {57, COLS2+2}, /* filled rounded brackets */ - {58, COLS2+3} -}; - -/**------------------------------------- -*** Kana subcollation values -*** BIT 0: set if large char -*** BIT 1: set if voiced -*** BIT 2: set if half voiced -*** Note: -*** To save space should be nibbles -*** IMPORTANT: -*** The '1' entries that do not have -*** a matching '0' entry have been -*** changed to zero to save space in -*** the subcollation area. -*** The original table is listed below. -***------------------------------------*/ - -FLMBYTE KanaSubColTbl[] = -{ - 0,1,0,1,0,1,0,1,0,1, /* a A i I u U e E o O */ - 1,3,0,3,0,3,1,3,0,3, /* KA GA KI GI KU GU KE GE KO GO */ - 0,3,0,3,0,3,0,3,0,3, /* SA ZA SHI JI SU ZU SE ZE SO ZO */ - 0,3,0,3,0,1,3,0,3,0,3, /* TA DA CHI JI tsu TSU ZU TE DE TO DO*/ - 0,0,0,0,0, /* NA NI NU NE NO */ - 0,3,5,0,3,5,0,3,5, /* HA BA PA HI BI PI FU BU PU */ - 0,3,5,0,3,5, /* HE BE PE HO BO PO */ - 0,0,0,0,0, /* MA MI MU ME MO */ - 0,1,0,1,0,1, /* ya YA yu YU yo YO */ - 0,0,0,0,0, /* RA RI RU RE RO */ - 0,1,0,0,0, /* wa WA WI WE WO */ - 0,3,0,0 /* N VU ka ke */ -}; - -/** -*** Map katakana (CharSet x26) to collation values -*** kana collating values are two byte values -*** where the high byte is 0x01. -**/ - -FLMBYTE KanaColTbl[] = -{ - 0, 0, 1, 1, 2, 2, 3, 3, 4, 4,/* a A i I u U e E o O */ - 5, 5, 6, 6, 7, 7, 8, 8, 9, 9,/* KA GA KI GI KU GU KE GE KO GO */ - 10,10,11,11,12,12,13,13,14,14,/* SA ZA SHI JI SU ZU SE ZE SO ZO */ - 15,15,16,16,17,17,17,18,18,19,19,/* TA DA CHI JI tsu TSU ZU TE DE TO DO*/ - 20,21,22,23,24, /* NA NI NU NE NO */ - 25,25,25,26,26,26,27,27,27, /* HA BA PA HI BI PI FU BU PU */ - 28,28,28,29,29,29, /* HE BE PE HO BO PO */ - 30,31,32,33,34, /* MA MI MU ME MO */ - 35,35,36,36,37,37, /* ya YA yu YU yo YO */ - 38,39,40,41,42, /* RA RI RU RE RO */ - 43,43,44,45,46, /* wa WA WI WE WO */ - 47, 2, 5, 8 /* N VU ka ke */ -}; - - -/**--------------------------------------- -*** Map KataKana collated value to vowel -*** value for use for the previous char. -***--------------------------------------*/ -FLMBYTE KanaColToVowel[] = -{ - 0,1,2,3,4, /* a i u e o */ - 0,1,2,3,4, /* ka ki ku ke ko */ - 0,1,2,3,4, /* sa shi su se so */ - 0,1,2,3,4, /* ta chi tsu te to */ - 0,1,2,3,4, /* na ni nu ne no */ - 0,1,2,3,4, /* ha hi hu he ho */ - 0,1,2,3,4, /* ma mi mu me mo */ - 0,2,4, /* ya yu yo */ - 0,1,2,3,4, /* ra ri ru re ro */ - 0,1,3,4, /* wa wi we wo */ -}; - -/** -*** Convert Zenkaku (double wide) to Hankaku (single wide) -*** Character set 0x24 maps to single wide chars in other char sets. -*** This enables collation values to be found on some symbols. -*** This is also used to convert symbols from hankaku to Zen24. -*** -**/ - -BYTE_WORD_TBL Zen24ToHankaku[] = { - { 0 ,0x0020 }, /* space */ - { 1 ,0x0b03 }, /* japanese comma */ - { 2 ,0x0b00 }, /* circle period */ - { 3 , 44 }, /* comma */ - { 4 , 46 }, /* period */ - { 5 ,0x0b04 }, /* center dot */ - { 6 , 58 }, /* colon */ - { 7 , 59 }, /* semicolon */ - { 8 , 63 }, /* question mark */ - { 9 , 33 }, /* exclamation mark */ - { 10 ,0x0b3d }, /* dakuten */ - { 11 ,0x0b3e }, /* handakuten */ - { 12 ,0x0106 }, /* accent mark */ - { 13 , 96 }, /* accent mark */ - { 14 ,0x0107 }, /* umlat */ - { 15 , 94 }, /* caret */ - { 16 ,0x0108 }, /* macron */ - { 17 , 95 }, /* underscore */ - { 27 ,0x0b0f }, /* extend vowel */ - { 28 ,0x0422 }, /* mdash */ - { 29 , 45 }, /* hyphen */ - { 30 , 47 }, /* slash */ - { 31 ,0x0607 }, /* backslash */ - { 32 , 126 }, /* tilde */ - { 33 ,0x0611 }, /* doubleline */ - { 34 ,0x0609 }, /* line */ - { 37 ,0x041d }, /* left apostrophe */ - { 38 ,0x041c }, /* right apostrophe */ - { 39 ,0x0420 }, /* left quote */ - { 40 ,0x041f }, /* right quote */ - { 41 , 40 }, /* left paren */ - { 42 , 41 }, /* right paren */ - { 45 , 91 }, /* left bracket */ - { 46 , 93 }, /* right bracket */ - { 47 , 123 }, /* left curly bracket */ - { 48 , 125 }, /* right curly bracket */ - { 53 ,0x0b01 }, /* left j quote */ - { 54 ,0x0b02 }, /* right j quote */ - { 59 , 43 }, /* plus */ - { 60 ,0x0600 }, /* minus */ - { 61 ,0x0601 }, /* plus/minus */ - { 62 ,0x0627 }, /* times */ - { 63 ,0x0608 }, /* divide */ - { 64 , 61 }, /* equal */ - { 65 ,0x0663 }, /* unequal */ - { 66 , 60 }, /* less */ - { 67 , 62 }, /* greater */ - { 68 ,0x0602 }, /* less/equal */ - { 69 ,0x0603 }, /* greater/equal */ - { 70 ,0x0613 }, /* infinity */ - { 71 ,0x0666 }, /* traingle dots */ - { 72 ,0x0504 }, /* man */ - { 73 ,0x0505 }, /* woman */ - { 75 ,0x062d }, /* prime */ - { 76 ,0x062e }, /* double prime */ - { 78 ,0x040c }, /* yen */ - { 79 , 36 }, /* $ */ - { 80 ,0x0413 }, /* cent */ - { 81 ,0x040b }, /* pound */ - { 82 , 37 }, /* % */ - { 83 , 35 }, /* # */ - { 84 , 38 }, /* & */ - { 85 , 42 }, /* * */ - { 86 , 64 }, /* @ */ - { 87 ,0x0406 }, /* squiggle */ - { 89 ,0x06b8 }, /* filled star */ - { 90 ,0x0425 }, /* hollow circle */ - { 91 ,0x042c }, /* filled circle */ - { 93 ,0x065f }, /* hollow diamond */ - { 94 ,0x0660 }, /* filled diamond */ - { 95 ,0x0426 }, /* hollow box */ - { 96 ,0x042e }, /* filled box */ - { 97 ,0x0688 }, /* hollow triangle */ - { 99 ,0x0689 }, /* hollow upside down triangle */ - { 103,0x0615 }, /* right arrow */ - { 104,0x0616 }, /* left arrow */ - { 105,0x0617 }, /* up arrow */ - { 106,0x0622 }, /* down arrow */ - { 119,0x060f }, /* */ - { 121,0x0645 }, /* */ - { 122,0x0646 }, - { 123,0x0643 }, - { 124,0x0644 }, - { 125,0x0642 }, /* union */ - { 126,0x0610 }, /* intersection */ - { 135,0x0655 }, - { 136,0x0656 }, - { 138,0x0638 }, /* right arrow */ - { 139,0x063c }, /* left/right arrow */ - { 140,0x067a }, /* */ - { 141,0x0679 }, - { 153,0x064f }, /* angle */ - { 154,0x0659 }, - { 155,0x065a }, - { 156,0x062c }, - { 157,0x062b }, - { 158,0x060e }, - { 159,0x06b0 }, - { 160,0x064d }, - { 161,0x064e }, - { 162,0x050e }, /* square root */ - { 164,0x0604 }, - { 175,0x0623 }, /* angstrom */ - { 176,0x044b }, /* percent */ - { 177,0x051b }, /* sharp */ - { 178,0x051c }, /* flat */ - { 179,0x0509 }, /* musical note */ - { 180,0x0427 }, /* dagger */ - { 181,0x0428 }, /* double dagger */ - { 182,0x0405 }, /* paragraph */ - { 187,0x068f } /* big hollow circle */ -}; - -/** -*** Maps CS26 to CharSet 11 -*** Taken from Char.asm -*** Used to uncollate characters for FLAIM - placed here for consistency -*** 0x80 - add dakuten -*** 0xC0 - add handakuten -*** 0xFF - no mapping exists -**/ -FLMBYTE MapCS26ToCharSet11[ 86 ] = { - 0x06, /* 0 a */ - 0x10, /* 1 A */ - 0x07, /* 2 i */ - 0x11, /* 3 I */ - 0x08, /* 4 u */ - 0x12, /* 5 U */ - 0x09, /* 6 e */ - 0x13, /* 7 E */ - 0x0a, /* 8 o */ - 0x14, /* 9 O */ - - 0x15, /* 0x0a KA */ - 0x95, /* GA - 21 followed by 0x3D dakuten */ - - 0x16, /* 0x0c KI */ - 0x96, /* GI */ - 0x17, /* 0x0e KU */ - 0x97, /* GU */ - 0x18, /* 0x10 KE */ - 0x98, /* GE */ - 0x19, /* 0x12 KO */ - 0x99, /* GO */ - - 0x1a, /* 0x14 SA */ - 0x9a, /* ZA */ - 0x1b, /* 0x16 SHI */ - 0x9b, /* JI */ - 0x1c, /* 0x18 SU */ - 0x9c, /* ZU */ - 0x1d, /* 0x1a SE */ - 0x9d, /* ZE */ - 0x1e, /* 0x1c SO */ - 0x9e, /* ZO */ - - 0x1f, /* 0x1e TA */ - 0x9f, /* DA */ - 0x20, /* 0x20 CHI */ - 0xa0, /* JI */ - 0x0e, /* 0x22 small tsu */ - 0x21, /* 0x23 TSU */ - 0xa1, /* ZU */ - 0x22, /* 0x25 TE */ - 0xa2, /* DE */ - 0x23, /* 0x27 TO */ - 0xa3, /* DO */ - - 0x24, /* 0x29 NA */ - 0x25, /* 0x2a NI */ - 0x26, /* 0x2b NU */ - 0x27, /* 0x2c NE */ - 0x28, /* 0x2d NO */ - - 0x29, /* 0x2e HA */ - 0xa9, /* 0x2f BA */ - 0xe9, /* 0x30 PA */ - 0x2a, /* 0x31 HI */ - 0xaa, /* 0x32 BI */ - 0xea, /* 0x33 PI */ - 0x2b, /* 0x34 FU */ - 0xab, /* 0x35 BU */ - 0xeb, /* 0x36 PU */ - 0x2c, /* 0x37 HE */ - 0xac, /* 0x38 BE */ - 0xec, /* 0x39 PE */ - 0x2d, /* 0x3a HO */ - 0xad, /* 0x3b BO */ - 0xed, /* 0x3c PO */ - - 0x2e, /* 0x3d MA */ - 0x2f, /* 0x3e MI */ - 0x30, /* 0x3f MU */ - 0x31, /* 0x40 ME */ - 0x32, /* 0x41 MO */ - - 0x0b, /* 0x42 small ya */ - 0x33, /* 0x43 YA */ - 0x0c, /* 0x44 small yu */ - 0x34, /* 0x45 YU */ - 0x0d, /* 0x46 small yo */ - 0x35, /* 0x47 YO */ - - 0x36, /* 0x48 RA */ - 0x37, /* 0x49 RI */ - 0x38, /* 0x4a RU */ - 0x39, /* 0x4b RE */ - 0x3a, /* 0x4c RO */ - - 0xff, /* 0x4d small wa */ - 0x3b, /* 0x4e WA */ - 0xff, /* 0x4f WI */ - 0xff, /* 0x50 WE */ - 0x05, /* 0x51 WO */ - - 0x3c, /* 0x52 N */ - 0xff, /* 0x53 VU */ - 0xff, /* 0x54 ka */ - 0xff /* 0x55 ke */ -}; - - -/** -*** Conversion from single (Hankaku) to double (Zenkaku) wide characters -*** Used in HanToZenkaku() -**/ - -/* maps from charset 11 to CS24 (punctuation) (starting from 11,0) */ - -FLMBYTE From0AToZen[] = { /* ' changed because of windows */ - 0, 9, 40, 0x53, /* sp ! " # */ - 0x4f, 0x52, 0x54, 38, /* $ % & ' */ - /* Was 187 for ! and 186 for ' */ - 0x29, 0x2a, 0x55, 0x3b, /* ( ) * + */ - 3, 0x1d, 4, 0x1e /* , - . / */ - }; - -FLMBYTE From0BToZen[] = { - 6, 7, 0x42, 0x40, /* : ; < = */ - 0x43, 8, 0x56 /* > ? @ */ - }; - -FLMBYTE From0CToZen[] = { - 0x2d, 0x1f, 0x2e, 0x0f, 0x11, 0x0d /* [ \ ] ^ _ ` */ - }; - -FLMBYTE From0DToZen[] = { - 0x2f, 0x22, 0x30, 0x20 /* { | } ~ */ - }; - -FLMBYTE From8ToZen[] = { /* Fast way to convert from 8 to zen */ - 0x5e, 0x7e, 0x5f, 0x7f, 0x5f, 0xFF, 0x60, 0x80, - 0x61, 0x81, 0x62, 0x82, 0x63, 0x83, 0x64, 0x84, - 0x65, 0x85, 0x66, 0x86, 0x67, 0x87, 0x68, 0x88, - 0x69, 0x89, 0x6a, 0x8a, 0x6b, 0x8b, 0x6c, 0x8c, - 0x6d, 0x8d, 0x6e, 0x8e, 0x6f, 0x8f, 0x6f, 0xFF, - 0x70, 0x90, 0x71, 0x91, 0x72, 0x92, 0x73, 0x93, - 0x74, 0x94, 0x75, 0x95 - }; - -static FLMBYTE From11AToZen[] = { /* 11 to 24 punctuation except dash */ - 2, /* japanese period */ - 0x35, /* left bracket */ - 0x36, /* right bracket */ - 0x01, /* comma */ - 0x05 /* chuuten */ - }; - -static FLMBYTE From11BToZen[] = { /* 11 to 26 (katakana) from 11,5 */ - 0x51, /* wo */ - 0,2,4,6,8,0x42,0x44,0x46,0x22, /* small a i u e o ya yu yo tsu */ - 0xFF, 1, 3, 5, 7, 9, /* dash (x241b) a i u e o */ - 0x0a, 0x0c, 0x0e, 0x10, 0x12, /* ka ki ku ke ko */ - 0x14, 0x16, 0x18, 0x1a, 0x1c, /* sa shi su se so */ - 0x1e, 0x20, 0x23, 0x25, 0x27, /* ta chi tsu te to */ - 0x29, 0x2a, 0x2b, 0x2c, 0x2d, /* na ni nu ne no */ - 0x2e, 0x31, 0x34, 0x37, 0x3a, /* ha hi fu he ho */ - 0x3d, 0x3e, 0x3f, 0x40, 0x41, /* ma mi mu me mo */ - 0x43, 0x45, 0x47, /* ya yu yo */ - 0x48, 0x49, 0x4a, 0x4b, 0x4c, /* ra ri ru re ro */ - 0x4e, 0x52 /* WA N */ - }; /* does not have wa WI WE VU ka ke */ - -/**************************************************************************** -Desc: Returns the collation value of the input Wp character. - If in charset 11 will convert the character to Zenkaku (double wide). -In: ui16WpChar - Char to collate off of - could be in CS0..14 or x24..up - ui16NextWpChar - next WP char for CS11 voicing marks - ui16PrevColValue - previous collating value - for repeat/vowel repeat - pui16ColValue - returns 2 byte collation value - pui16SubColVal - 0, 6 or 16 bit value for the latin sub collation - or the kana size & vowel voicing - 001 - set if large (upper) character - 010 - set if voiced - 100 - set if half voiced - - pucCaseBits - returns 2 bits - Latin/Greek/Cyrillic - 01 - case bit set if character is uppercase - 10 - double wide character in CS 0x25xx, 0x26xx and 0x27xx - Japanese - 00 - double wide hiragana 0x255e..25b0 - 01 - double wide katakana 0x2600..2655 - 10 - double wide symbols that map to charset 11 - 11 - single wide katakana from charset 11 -Ret: 0 - no valid collation value - high values set for pui16ColValue - Sub-collation gets original WP character value - 1 - valid collation value - 2 - valid collation value and used the ui16NextWpChar - -Notes: Code taken from XCH2COL.ASM - routine xch2col_f - also from CMPWS.ASM - routine getcase -Terms: - HANKAKU - single wide characters in charsets 0..14 - ZENKAKU - double wide characters in charsets 0x24..end of kanji - KANJI - collation values are 0x2900 less than WPChar value - -****************************************************************************/ -FLMUINT16 fwpAsiaGetCollation( - FLMUINT16 ui16WpChar, // WP char to get collation values - FLMUINT16 ui16NextWpChar, // Next WP char - for CS11 voicing marks - FLMUINT16 ui16PrevColValue, // Previous collating value - FLMUINT16 * pui16ColValue, // Returns collation value - FLMUINT16 * pui16SubColVal, // Returns sub-collation value - FLMBYTE * pucCaseBits, // Returns case bits value - FLMUINT16 uiUppercaseFlag // Set if to convert to uppercase - ) -{ - FLMUINT16 ui16ColValue; - FLMUINT16 ui16SubColVal; - FLMBYTE ucCaseBits = 0; - FLMBYTE ucCharSet = ui16WpChar >> 8; - FLMBYTE ucCharVal = ui16WpChar & 0xFF; - FLMUINT16 ui16Hankaku; - FLMUINT uiLoop; - FLMUINT16 ui16ReturnValue = 1; - - ui16ColValue = ui16SubColVal = 0; - - // Kanji or above - - if (ucCharSet >= 0x2B) - { - - // Puts 2 or above into high byte. - - ui16ColValue = ui16WpChar - 0x2900; - - // No subcollation or case bits need to be set - - goto Exit; - } - - // Single wide character? (HANKAKU) - - if (ucCharSet < 11) - { - // Get the values from a non-asian character - // LATIN, GREEK or CYRILLIC - // The width bit may have been set on a jump to - // label from below. - -Latin_Greek_Cyrillic: - - // YES: Pass US_LANG because this is what we want - - // Prevents double character sorting. - - ui16ColValue = fwpGetCollation( ui16WpChar, US_LANG); - - if (uiUppercaseFlag || fwpIsUpper( ui16WpChar)) - { - // Uppercase - set case bit - - ucCaseBits |= SET_CASE_BIT; - } - - // Character for which there is no collation value? - - if (ui16ColValue == COLS0) - { - ui16ReturnValue = 0; - if (!fwpIsUpper( ui16WpChar)) - { - - // Convert to uppercase - - ui16WpChar--; - } - ui16ColValue = 0xFFFF; - ui16SubColVal = ui16WpChar; - } - else if (ucCharSet) // Don't bother with ascii - { - if (!fwpIsUpper( ui16WpChar)) - { - - // Convert to uppercase - - ui16WpChar--; - } - - if (ucCharSet == CHSMUL1) - { - FLMUINT16 ui16Base; - FLMUINT16 ui16Diacritic; - - ui16SubColVal = !fwpCh6Brkcar( ui16WpChar, &ui16Base, - &ui16Diacritic) - ? fwp_dia60Tbl[ ui16Diacritic & 0xFF] - : ui16WpChar; - } - else if (ucCharSet == CHSGREK) // GREEK - { - if (ui16WpChar >= 0x834 || // [8,52] or above - ui16WpChar == 0x804 || // [8,4] BETA Medial | Terminal - ui16WpChar == 0x826) // [8,38] SIGMA terminal - ui16SubColVal = ui16WpChar; - } - else if (ucCharSet == CHSCYR) // CYRILLIC - { - if (ui16WpChar >= 0xA90) // [10, 144] or above - { - ui16SubColVal = ui16WpChar; // Dup collation values - } - } - // else don't need a sub collation value - } - goto Exit; - } - - // Single wide Japanese character? - - if (ucCharSet == 11) - { - FLMUINT16 ui16KanaChar; - - // Convert charset 11 to Zenkaku (double wide) CS24 or CS26 hex. - // All characters in charset 11 will convert to CS24 or CS26. - // when combining the collation and the sub-collation values. - - if (HanToZenkaku( ui16WpChar, ui16NextWpChar, &ui16KanaChar ) == 2) - { - - // Return 2 - - ui16ReturnValue++; - } - - ucCaseBits |= SET_WIDTH_BIT; // Set so will allow to go back - ui16WpChar = ui16KanaChar; // If in CS24 will fall through to ZenKaku - ucCharSet = ui16KanaChar >> 8; - ucCharVal = ui16KanaChar & 0xFF; - } - - if (ui16WpChar < 0x2400) - { - - // In some other character set - - goto Latin_Greek_Cyrillic; - } - else if (ui16WpChar >= 0x255e && // Hiragana? - ui16WpChar <= 0x2655) // Katakana? - { - if (ui16WpChar >= 0x2600) - { - ucCaseBits |= SET_KATAKANA_BIT; - } - - // HIRAGANA & KATAKANA - // Kana contains both hiragana and katakana. - // The tables contain the same characters in same order - - if (ucCharSet == 0x25) - { - - // Change value to be in character set 26 - - ucCharVal -= 0x5E; - } - - ui16ColValue = 0x0100 + KanaColTbl[ ucCharVal ]; - ui16SubColVal = KanaSubColTbl[ ucCharVal ]; - goto Exit; - } - - // ZenKaku - means any double wide character - // Hankaku - single wide character - - // Inputs: 0x2400..2559 symbols..latin - Zenkaku - // 0x265B..2750 greek..cyrillic - Zenkaku - - // SET_WIDTH_BIT may have been set if original char - // was in 11 and got converted to CS24. [1,2,5,27(extendedVowel),53,54] - // Original chars from CS11 will have some collation value that when - // combined with the sub-collation value will format a character in - // CS24. The width bit will then convert back to CS11. - - if ((ui16Hankaku = ZenToHankaku( ui16WpChar, (FLMUINT16 *) 0 )) != 0) - { - if ((ui16Hankaku >> 8) != 11) // if CharSet11 was a CS24 symbol - { - ui16WpChar = ui16Hankaku; // May be CS24 symbol/latin/gk/cy - ucCharSet = ui16WpChar >> 8; - ucCharVal = ui16WpChar & 0xFF; - ucCaseBits |= SET_WIDTH_BIT; // Latin symbols double wide - goto Latin_Greek_Cyrillic; - } - } - - // 0x2400..0x24bc Japanese symbols that cannot be converted to Hankaku. - // All 6 original symbol chars from 11 will also be here. - // First try to find a collation value of the symbol. - // The sub-collation value will be the position in the CS24 table + 1. - - for (uiLoop = 0; - uiLoop < (sizeof(fwp_Ch24ColTbl) / sizeof(BYTE_WORD_TBL)); - uiLoop++ ) - { - if (ucCharVal == fwp_Ch24ColTbl[ uiLoop].ByteValue) - { - if ((ui16ColValue = fwp_Ch24ColTbl[ uiLoop].WordValue) < 0x100) - { - - // Don't save for chuuten, dakuten, handakuten - - ui16SubColVal = (FLMUINT16)(uiLoop + 1); - } - break; - } - } - if (!ui16ColValue) - { - - // Now see if it's a repeat or repeat-vowel character - - if( (((ucCharVal >= 0x12) && (ucCharVal <= 0x15)) || - (ucCharVal == 0x17) || - (ucCharVal == 0x18)) && - ((ui16PrevColValue >> 8) == 1)) - { - ui16ColValue = ui16PrevColValue; - - // Store original WP character - - ui16SubColVal = ui16WpChar; - } - else if( (ucCharVal == 0x1B) && // repeat vowel? - (ui16PrevColValue >= 0x100) && - (ui16PrevColValue < COLS_ASIAN_MARKS)) // Previous kana char? - { - ui16ColValue = 0x0100 + KanaColToVowel[ ui16PrevColValue & 0xFF ]; - - // Store original WP character - - ui16SubColVal = ui16WpChar; - } - else - { - ui16ReturnValue = 0; - ui16ColValue = 0xFFFF; // No collation value - ui16SubColVal = ui16WpChar; // Never have changed if gets here - } - } - -Exit: - - // Set return values - - *pui16ColValue = ui16ColValue; - *pui16SubColVal = ui16SubColVal; - *pucCaseBits = ucCaseBits; - - return( ui16ReturnValue); -} - -/**************************************************************************** -Desc: Convert a zenkaku (double wide) char to a hankaku (single wide) char -Ret: Hankaku char or 0 if a conversion doesn't exist -Notes: Taken from CHAR.ASM - zen2han_f routine -****************************************************************************/ -FLMUINT16 ZenToHankaku( - FLMUINT16 ui16WpChar, - FLMUINT16 * DakutenOrHandakutenRV ) -{ - FLMUINT16 ui16Hankaku = 0; - FLMBYTE ucCharSet = ui16WpChar >> 8; - FLMBYTE ucCharVal = ui16WpChar & 0xFF; - FLMUINT uiLoop; - - switch (ucCharSet) - { - // SYMBOLS - - case 0x24: - for (uiLoop = 0; - uiLoop < (sizeof(Zen24ToHankaku) / sizeof(BYTE_WORD_TBL)); - uiLoop++) - { - // List is sorted so table entry is more you are done - - if (Zen24ToHankaku [uiLoop].ByteValue >= ucCharVal) - { - if (Zen24ToHankaku [uiLoop].ByteValue == ucCharVal) - { - ui16Hankaku = Zen24ToHankaku [uiLoop].WordValue; - } - break; - } - } - break; - - // ROMAN - 0x250F..2559 - // Hiragana - 0x255E..2580 - - case 0x25: - if (ucCharVal >= 0x0F && ucCharVal < 0x5E) - { - ui16Hankaku = ucCharVal + 0x21; - } - break; - - // Katakana - 0x2600..2655 - // Greek - 0x265B..2695 - - case 0x26: - if (ucCharVal <= 0x55) // Katakana range - { - FLMBYTE ucCS11CharVal; - FLMUINT16 ui16NextWpChar = 0; - - if ((ucCS11CharVal = MapCS26ToCharSet11[ ucCharVal ]) != 0xFF) - { - if (ucCS11CharVal & 0x80) - { - if( ucCS11CharVal & 0x40) - { - - // Handakuten voicing - - ui16NextWpChar = 0xB3E; - } - else - { - - // Dakuten voicing - - ui16NextWpChar = 0xB3D; - } - ucCS11CharVal &= 0x3F; - } - ui16Hankaku = 0x0b00 + ucCS11CharVal; - if( ui16NextWpChar && DakutenOrHandakutenRV ) - { - *DakutenOrHandakutenRV = ui16NextWpChar; - } - } - } - else if (ucCharVal <= 0x95) // Greek - { - FLMBYTE ucGreekChar = ucCharVal; - - // Make a zero based number. - - ucGreekChar -= 0x5E; - - // Check for lowercase - if( ucGreekChar >= 0x20) - { - - // Convert to upper case for now - - ucGreekChar -= 0x20; - } - if (ucGreekChar >= 2) - { - ucGreekChar++; - } - if (ucGreekChar >= 19) - { - ucGreekChar++; - } - - // Convert to character set 8 - - ui16Hankaku = (ucGreekChar << 1) + 0x800; - if (ucCharVal >= (0x5E + 0x20)) - { - - // Adjust to lower case character - - ui16Hankaku++; - } - } - break; - - // Cyrillic - - case 0x27: - - // Uppercase? - - if (ucCharVal <= 0x20) - { - ui16Hankaku = (ucCharVal << 1) + 0xa00; - } - else if (ucCharVal >= 0x30 && ucCharVal <= 0x50) - { - - // Lower case - - ui16Hankaku = ((ucCharVal - 0x30) << 1) + 0xa01; - } - break; - } - - return( ui16Hankaku); -} - -/**************************************************************************** -Desc: Convert a WPChar from hankaku (single wide) to zenkaku (double wide). - 1) Used to see if a char in CS11 can map to a double wide character - 2) Used to convert keys into original data. -Ret: 0 = no conversion - 1 = converted character to zenkaku - 2 = ui16NextWpChar dakuten or handakuten voicing got combined -Notes: Taken from char.asm - han2zen() - From8ToZen could be taken out and placed in code. -****************************************************************************/ -FLMUINT16 HanToZenkaku( - FLMUINT16 ui16WpChar, - FLMUINT16 ui16NextWpChar, - FLMUINT16 * pui16Zenkaku) -{ - FLMUINT16 ui16Zenkaku = 0; - FLMBYTE ucCharSet = ui16WpChar >> 8; - FLMBYTE ucCharVal = ui16WpChar & 0xFF; - FLMUINT uiLoop; - FLMUINT16 ui16CharsUsed = 1; - - switch( ucCharSet) - { - // Character set 0 - symbols - - case 0: - - // Invalid? - all others are used. - - if (ucCharVal < 0x20) - { - ; - } - else if (ucCharVal <= 0x2F) - { - - // Symbols A - - ui16Zenkaku = 0x2400 + From0AToZen[ ucCharVal - 0x20 ]; - } - else if (ucCharVal <= 0x39) - { - - // 0..9 - - ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); - } - else if (ucCharVal <= 0x40) - { - - // Symbols B - - ui16Zenkaku = 0x2400 + From0BToZen[ ucCharVal - 0x3A ]; - } - else if (ucCharVal <= 0x5A) - { - - // A..Z - - ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); - } - else if (ucCharVal <= 0x60) - { - - // Symbols C - - ui16Zenkaku = 0x2400 + From0CToZen[ ucCharVal - 0x5B ]; - } - else if (ucCharVal <= 0x7A) - { - - // a..z - - ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); - } - else if (ucCharVal <= 0x7E) - { - - // Symbols D - - ui16Zenkaku = 0x2400 + From0DToZen[ ucCharVal - 0x7B ]; - } - break; - - // GREEK - - case 8: - if ((ucCharVal >= sizeof( From8ToZen)) || - ((ui16Zenkaku = 0x2600 + From8ToZen[ ucCharVal ]) == 0x26FF)) - { - ui16Zenkaku = 0; - } - break; - - // CYRILLIC - - case 10: - - // Check range - - ui16Zenkaku = 0x2700 + (ucCharVal >> 1); // Uppercase value - - // Convert to lower case? - - if( ucCharVal & 0x01) - { - ui16Zenkaku += 0x30; - } - break; - - // JAPANESE - - case 11: - if (ucCharVal < 5) - { - ui16Zenkaku = 0x2400 + From11AToZen[ ucCharVal ]; - } - else if (ucCharVal < 0x3D) // katakana? - { - if ((ui16Zenkaku = 0x2600 + - From11BToZen[ ucCharVal - 5 ]) == 0x26FF) - { - - // Dash - convert to this - - ui16Zenkaku = 0x241b; - } - else - { - if (ui16NextWpChar == 0xB3D) // dakuten? - voicing - { - - // First check exception(s) then - // check if voicing exists! - will NOT access out of table - - if ((ui16Zenkaku != 0x2652) && // is not 'N'? - (KanaSubColTbl[ ui16Zenkaku - 0x2600 + 1 ] == 3)) - { - ui16Zenkaku++; - - // Return 2 - - ui16CharsUsed++; - } - } - else if (ui16NextWpChar == 0xB3E) // handakuten? - voicing - { - - // Check if voicing exists! - will NOT access out of table - - if (KanaSubColTbl [ui16Zenkaku - 0x2600 + 2 ] == 5) - { - ui16Zenkaku += 2; - - // Return 2 - - ui16CharsUsed++; - } - } - } - } - else if (ucCharVal == 0x3D) // dakuten? - { - - // Convert to voicing symbol - - ui16Zenkaku = 0x240A; - } - else if (ucCharVal == 0x3E) // handakuten? - { - - // Convert to voicing symbol - - ui16Zenkaku = 0x240B; - } - // else cannot convert - break; - - // Other character sets - // CS 1,4,5,6 - symbols - - default: - - // Instead of includes more tables from char.asm - look down the - // Zen24Tohankaku[] table for a matching value - not much slower. - - for (uiLoop = 0; - uiLoop < (sizeof(Zen24ToHankaku) / sizeof(BYTE_WORD_TBL)); - uiLoop++) - { - if (Zen24ToHankaku[ uiLoop].WordValue == ui16WpChar) - { - ui16Zenkaku = 0x2400 + Zen24ToHankaku[ uiLoop].ByteValue; - break; - } - } - break; - } - if (!ui16Zenkaku) - { - - // Change return value - - ui16CharsUsed = 0; - } - - *pui16Zenkaku = ui16Zenkaku; - return( ui16CharsUsed); -} diff --git a/flaim/src/fwpchar.cpp b/flaim/src/fwpchar.cpp deleted file mode 100644 index 7d83b78..0000000 --- a/flaim/src/fwpchar.cpp +++ /dev/null @@ -1,727 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: WP character routines. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1994-2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fwpchar.cpp 12301 2006-01-19 15:02:55 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -static char fwp_langtbl[LAST_LANG+LAST_LANG] - = { - 'U', 'S', /* English, United States */ - 'A', 'F', /* Afrikaans */ - 'A', 'R', /* Arabic */ - 'C', 'A', /* Catalan */ - 'H', 'R', /* Croatian */ - 'C', 'Z', /* Czech */ - 'D', 'K', /* Danish */ - 'N', 'L', /* Dutch */ - 'O', 'Z', /* English, Australia */ - 'C', 'E', /* English, Canada */ - 'U', 'K', /* English, United Kingdom */ - 'F', 'A', /* Farsi */ - 'S', 'U', /* Finnish */ - 'C', 'F', /* French, Canada */ - 'F', 'R', /* French, France */ - 'G', 'A', /* Galician */ - 'D', 'E', /* German, Germany */ - 'S', 'D', /* German, Switzerland */ - 'G', 'R', /* Greek */ - 'H', 'E', /* Hebrew */ - 'M', 'A', /* Hungarian */ - 'I', 'S', /* Icelandic */ - 'I', 'T', /* Italian */ - 'N', 'O', /* Norwegian */ - 'P', 'L', /* Polish */ - 'B', 'R', /* Portuguese, Brazil */ - 'P', 'O', /* Portuguese, Portugal */ - 'R', 'U', /* Russian */ - 'S', 'L', /* Slovak */ - 'E', 'S', /* Spanish */ - 'S', 'V', /* Swedish */ - 'Y', 'K', /* Ukrainian */ - 'U', 'R', /* Urdu */ - 'T', 'K', /* Turkey */ - 'J', 'P', /* Japanese */ - 'K', 'R', /* Korean */ - 'C', 'T', /* Chinese-Traditional */ - 'C', 'S', /* Chinese-Simplified */ - 'L', 'A' /* Future asian language */ -/* Removed in conjunction with change in wps6.h */ -/* 'T', 'A' Taiwanese - really CS! */ - }; - -/* - fwp_caseConvertableRange[] defines the range of characters within the set - which are case convertible. -*/ - -static FLMBYTE fwp_caseConvertableRange[] = { - 26,241, /* Multinational 1 */ - 0,0, /* Multinational 2 */ - 0,0, /* Box Drawing */ - 0,0, /* Symbol 1 */ - 0,0, /* Symbol 2 */ - 0,0, /* Math 1 */ - 0,0, /* Math 2 */ - 0,69, /* Greek 1 */ - 0,0, /* Hebrew */ - 0,199, /* Cyrillic */ - 0,0, /* Japanese Kana */ - 0,0, /* User-defined */ - 0,0, /* Not defined */ - 0,0, /* Not defined */ - 0,0, /* Not defined */ -}; - -/**************************************************************************** -Desc: getNextCharState can be thought of as a 2 dimentional array with - i and j as the row and column indicators respectively. If a value - exists at the intersection of i and j, it is returned. Sparse array - techniques are used to minimize memory usage. -****************************************************************************/ -FINLINE FLMUINT16 getNextCharState( - FLMUINT i, - FLMUINT j) -{ - FLMUINT k, x; - - for( k = fwp_indexi[ x = - (i > START_COL) ? (START_ALL) : i ]; /* adjust so don't use full tables */ - k <= (FLMUINT) (fwp_indexi[ x + 1] - 1); - k++ ) - { - // FIXUP_AREA_SIZE should be 24. - if( j == fwp_indexj[ k]) - { - return( fwp_valuea[ (i > START_COL) - ? (k + (FIXUP_AREA_SIZE * (i - START_ALL))) - : k]); - } - } - - return(0); -} - -/**************************************************************************** -Desc: Determine the language number from the 2 byte language code -****************************************************************************/ -FLMEXP FLMUINT FLMAPI FlmLanguage( - char * pszLanguageCode) -{ - char cFirstChar = *pszLanguageCode; - char cSecondChar = *(pszLanguageCode+1); - FLMUINT uiTablePos; - - for (uiTablePos = 0; uiTablePos < (LAST_LANG+LAST_LANG); uiTablePos += 2 ) - { - if (fwp_langtbl [uiTablePos] == cFirstChar && - fwp_langtbl [uiTablePos + 1] == cSecondChar) - { - - // Return uiTablePos div 2 - - return( uiTablePos >> 1); - } - } - - // Language not found, return default US language - - return( US_LANG); -} - -/**************************************************************************** -Desc: Determine the language code from the language number -****************************************************************************/ -FLMEXP void FLMAPI FlmGetLanguage( - FLMUINT uiLangNum, - char * pszLanguageCode) -{ - - // iLangNum could be negative - - if (uiLangNum >= LAST_LANG) - { - uiLangNum = US_LANG; - } - - uiLangNum += uiLangNum; - *pszLanguageCode++ = fwp_langtbl [uiLangNum]; - *pszLanguageCode++ = fwp_langtbl [uiLangNum + 1]; - *pszLanguageCode = 0; -} - -/**************************************************************************** -Desc: Converts a character to upper case (if possible) -****************************************************************************/ -FLMUINT16 fwpCh6Upper( - FLMUINT16 ui16WpChar) -{ - if (ui16WpChar < 256) - { - if (ui16WpChar >= ASCII_LOWER_A && ui16WpChar <= ASCII_LOWER_Z) - { - - // Return ASCII upper case - - return( ui16WpChar & 0xdf); - } - } - else - { - FLMBYTE ucCharSet = ui16WpChar >> 8; - - if (ucCharSet == CHSMUL1) - { - FLMBYTE ucChar = ui16WpChar & 0xFF; - - if (ucChar >= fwp_caseConvertableRange[ (CHSMUL1-1) * 2] && - ucChar <= fwp_caseConvertableRange[ ((CHSMUL1-1) * 2) + 1]) - { - return( ui16WpChar & 0xFFFE); - } - } - else if (ucCharSet == CHSGREK) - { - if ((ui16WpChar & 0xFF) <= - fwp_caseConvertableRange[ ((CHSGREK-1) * 2) + 1]) - { - return( ui16WpChar & 0xFFFE); - } - } - else if (ucCharSet == CHSCYR) - { - if ((ui16WpChar & 0xFF) <= - fwp_caseConvertableRange[ ((CHSCYR-1) * 2) + 1]) - { - return( ui16WpChar & 0xFFFE); - } - } - else if (ui16WpChar >= Lower_JP_a) - { - - // Possible double byte character set alphabetic character? - - if (ui16WpChar <= Lower_JP_z) - { - - // Japanese? - - ui16WpChar = (ui16WpChar - Lower_JP_a) + Upper_JP_A; - } - else if (ui16WpChar >= Lower_KR_a && ui16WpChar <= Lower_KR_z) - { - - // Korean? - - ui16WpChar = (ui16WpChar - Lower_KR_a) + Upper_KR_A; - } - else if (ui16WpChar >= Lower_CS_a && ui16WpChar <= Lower_CS_z) - { - - // Chinese Simplified? - - ui16WpChar = (ui16WpChar - Lower_CS_a) + Upper_CS_A; - } - else if (ui16WpChar >= Lower_CT_a && ui16WpChar <= Lower_CT_z) - { - - // Chinese Traditional? - - ui16WpChar = (ui16WpChar - Lower_CT_a) + Upper_CT_A; - } - } - } - - // Return original character - original not in lower case. - - return( ui16WpChar); -} - -/**************************************************************************** -Desc: Checks to see if WP character is upper case -****************************************************************************/ -FLMBOOL fwpIsUpper( - FLMUINT16 ui16WpChar - ) -{ - FLMBYTE ucChar; - FLMBYTE ucCharSet; - - // Get character - - ucChar = (FLMBYTE)(ui16WpChar & 0xFF); - - // Test if ASCII character set - - if (!(ui16WpChar & 0xFF00)) - { - return( (ucChar >= ASCII_LOWER_A && ucChar <= ASCII_LOWER_Z) - ? FALSE - : TRUE); - } - - // Get the character set - - ucCharSet = (FLMBYTE) (ui16WpChar >> 8); - - // CHSMUL1 == Multinational 1 character set - // CHSGREK == Greek character set - // CHSCYR == Cyrillic character set - - if ((ucCharSet == CHSMUL1 && ucChar >= 26 && ucChar <= 241) || - (ucCharSet == CHSGREK && ucChar <= 69) || - (ucCharSet == CHSCYR && ucChar <= 199)) - { - return( (ucChar & 1) ? FALSE : TRUE); - } - - // Don't care that double ss is lower - - return( TRUE); -} - -/**************************************************************************** -Desc: Converts a character to lower case (if possible) -****************************************************************************/ -FLMUINT16 fwpCh6Lower( - FLMUINT16 ui16WpChar) -{ - if (ui16WpChar < 256) - { - if (ui16WpChar >= ASCII_UPPER_A && ui16WpChar <= ASCII_UPPER_Z) - { - return( ui16WpChar | 0x20); - } - } - else - { - FLMBYTE ucCharSet = ui16WpChar >> 8; - - if (ucCharSet == CHSMUL1) - { - FLMBYTE ucChar = ui16WpChar & 0xFF; - - if (ucChar >= fwp_caseConvertableRange[ (CHSMUL1-1) * 2] && - ucChar <= fwp_caseConvertableRange[ ((CHSMUL1-1) * 2) + 1] ) - { - return( ui16WpChar | 1); - } - } - else if (ucCharSet == CHSGREK) - { - if ((ui16WpChar & 0xFF) <= - fwp_caseConvertableRange[ ((CHSGREK-1) * 2) + 1]) - { - return( ui16WpChar | 1); - } - } - else if (ucCharSet == CHSCYR) - { - if ((ui16WpChar & 0xFF) <= - fwp_caseConvertableRange[ ((CHSCYR-1) * 2) + 1]) - { - return( ui16WpChar | 1); - } - } - else if (ui16WpChar >= Upper_JP_A) - { - // Possible double byte character set alphabetic character? - - if (ui16WpChar <= Upper_JP_Z) - { - - // Japanese? - - ui16WpChar = ui16WpChar - Upper_JP_A + Lower_JP_a; - } - else if (ui16WpChar >= Upper_KR_A && ui16WpChar <= Upper_KR_Z) - { - - // Korean? - - ui16WpChar = ui16WpChar - Upper_KR_A + Lower_KR_a; - } - else if (ui16WpChar >= Upper_CS_A && ui16WpChar <= Upper_CS_Z) - { - - // Chinese Simplified? - - ui16WpChar = ui16WpChar - Upper_CS_A + Lower_CS_a; - } - else if (ui16WpChar >= Upper_CT_A && ui16WpChar <= Upper_CT_Z) - { - - // Chinese Traditional? - - ui16WpChar = ui16WpChar - Upper_CT_A + Lower_CT_a; - } - } - } - - // Return original character, original not in upper case - - return(ui16WpChar); -} - -/**************************************************************************** -Desc: Break a WP character into a base and a diacritical char. -Ret: TRUE - if not found - FALSE - if found -****************************************************************************/ -FLMBOOL fwpCh6Brkcar( - FLMUINT16 ui16WpChar, - FLMUINT16 * pui16BaseChar, - FLMUINT16 * pui16DiacriticChar) -{ - BASE_DIACRITP pBaseDiacritic; - FLMINT iTableIndex; - - if ((pBaseDiacritic = fwp_car60_c[ HI(ui16WpChar)]) == 0) - { - return( TRUE); - } - - iTableIndex = ((FLMBYTE)ui16WpChar) - pBaseDiacritic->start_char; - if (iTableIndex < 0 || - iTableIndex > pBaseDiacritic->char_count || - pBaseDiacritic->table [iTableIndex].base == (FLMBYTE)0xFF) - { - return( TRUE); - } - - if ((HI( ui16WpChar) != CHSMUL1) || - ((fwp_ml1_cb60[ ((FLMBYTE) ui16WpChar) >> 3] >> - (7 - (ui16WpChar & 0x07))) & 0x01)) - { - - // normal case, same base as same as characters - - *pui16BaseChar = (ui16WpChar & 0xFF00) | - pBaseDiacritic->table [iTableIndex].base; - *pui16DiacriticChar = (ui16WpChar & 0xFF00) | - pBaseDiacritic->table[iTableIndex].diacrit; - } - else - { - - // Multi-national where base is ascii value. - - *pui16BaseChar = pBaseDiacritic->table [iTableIndex].base; - *pui16DiacriticChar = (ui16WpChar & 0xFF00) | - pBaseDiacritic->table[iTableIndex].diacrit; - } - return( FALSE); -} - -/**************************************************************************** -Desc: Take a base and a diacritic and compose a WP character. - Note on base character: i's and j's must be dotless i's and j's (for - those which use them) or they will not be found. -Ret: TRUE - if not found - FALSE - if found -Notes: ascii characters with diacriticals are in multi-national if anywhere; - all other base chars with diacritics are found in their own sets. -****************************************************************************/ -FLMBOOL fwpCh6Cmbcar( - FLMUINT16 * pui16WpChar, - FLMUINT16 ui16BaseChar, - FLMINT16 ui16DiacriticChar) -{ - FLMUINT uiRemaining; - FLMBYTE ucCharSet; - FLMBYTE ucChar; - BASE_DIACRITP pBaseDiacritic; - BASE_DIACRIT_TABLEP pTable; - - ucCharSet = HI( ui16BaseChar); - if (ucCharSet > fwp_max_car60_size) - { - return( TRUE); - } - - // Is base ASCII? If so, look in multinational 1 - - if (!ucCharSet) - { - ucCharSet = CHSMUL1; - } - - if ((pBaseDiacritic = fwp_car60_c[ucCharSet]) == 0) - { - return( TRUE); - } - - ucChar = LO( ui16BaseChar); - ui16DiacriticChar = LO( ui16DiacriticChar); - pTable = pBaseDiacritic->table; - for (uiRemaining = pBaseDiacritic->char_count; - uiRemaining; - uiRemaining--, pTable++ ) - { - - // Same base? - - if (pTable->base == ucChar && - (pTable->diacrit & 0x7F) == ui16DiacriticChar) - { - - // Same diacritic? - - *pui16WpChar = (FLMUINT16) (((FLMUINT16) ucCharSet << 8) + - (pBaseDiacritic->start_char + - (FLMUINT16)(pTable - pBaseDiacritic->table))); - return( FALSE); - } - } - return( TRUE); -} - -/************************************************************************** -Desc: Find the collating value of a WP character -ret: Collating value (COLS0 is high value - undefined WP char) -***********************************************************************/ -FLMUINT16 fwpGetCollation( - FLMUINT16 ui16WpChar, - FLMUINT uiLanguage) -{ - FLMUINT16 ui16State; - FLMBYTE ucCharVal; - FLMBYTE ucCharSet; - FLMBOOL bHebrewArabicFlag = FALSE; - TBL_B_TO_BP * pColTbl = fwp_col60Tbl; - - // State ONLY for non-US - - if (uiLanguage != US_LANG) - { - if (uiLanguage == AR_LANG || // Arabic - uiLanguage == FA_LANG || // Farsi - persian - uiLanguage == HE_LANG || // Hebrew - uiLanguage == UR_LANG) // Urdu - { - pColTbl = fwp_HebArabicCol60Tbl; - bHebrewArabicFlag = TRUE; - } - else - { - - // check if uiLanguage candidate for alternate double collating - - ui16State = getNextCharState( START_COL, uiLanguage); - if (0 != (ui16State = getNextCharState( (ui16State - ? ui16State // look at special case languages - : START_ALL), // look at US and European - (FLMUINT) ui16WpChar))) - { - return( ui16State); - } - } - } - - ucCharVal = (FLMBYTE)ui16WpChar; - ucCharSet = (FLMBYTE)(ui16WpChar >> 8); - - // This is an optimized version of f_b_bp_citrp() inline for performance - - do - { - if (pColTbl->key == ucCharSet) - { - FLMBYTE * pucColVals; // table of collating values - - pucColVals = pColTbl->charPtr; - - // Check if the value is in the range of collated chars - - // Above lower range of table? - - if (ucCharVal >= *pucColVals) - { - - // Make value zero based to index - - ucCharVal -= *pucColVals++; - - // Below maximum number of table entries? - - if (ucCharVal < *pucColVals++) - { - - // Return collated value. - - return( pucColVals[ ucCharVal]); - } - } - } - - // Go to next table entry - - pColTbl++; - } while (pColTbl->key != 0xFF); - - if (bHebrewArabicFlag) - { - if (ucCharSet == CHSHEB || - ucCharSet == CHSARB1 || - ucCharSet == CHSARB2) - { - - // Same as COLS0_HEBREW - - return( COLS0_ARABIC); - } - } - - // Defaults for characters that don't have a collation value. - - return( COLS0); -} - -/**************************************************************************** -Desc: Check for double characters that sort as 1 (like ch in Spanish) or - 1 character that should sort as 2 (like � sorts as ae in French). -Return: 0 = nothing changes. Otherwise, *pui16WpChar is the first - character, and the return value contains the 2nd character. - In addition, *pbTwoIntoOne will be TRUE if we should take two - characters and treat as one (i.e, change the collation on the - outside to one more than the collation of the first character). -****************************************************************************/ -FLMUINT16 fwpCheckDoubleCollation( - FLMUINT16 * pui16WpChar, - FLMBOOL * pbTwoIntoOne, - const FLMBYTE ** ppucInputStr, - FLMUINT uiLanguage) -{ - FLMUINT16 ui16CurState; - FLMUINT16 ui16WpChar; - FLMUINT16 ui16SecondChar; - FLMUINT16 ui16LastChar = 0; - FLMUINT uiInLen; - FLMBOOL bUpperFlag; - - ui16WpChar = *pui16WpChar; - bUpperFlag = fwpIsUpper( ui16WpChar); - - uiInLen = 0; - ui16SecondChar = 0; - - // Primer read - - if ((ui16CurState = getNextCharState( 0, uiLanguage)) == 0) - { - goto Exit; - } - for (;;) - { - switch (ui16CurState) - { - case INSTSG: - *pui16WpChar = ui16SecondChar = (FLMUINT16)f_toascii( 's'); - *pbTwoIntoOne = FALSE; - goto Exit; - case INSTAE: - if (bUpperFlag) - { - *pui16WpChar = (FLMUINT16)f_toascii( 'A'); - ui16SecondChar = (FLMUINT16)f_toascii( 'E'); - } - else - { - *pui16WpChar = (FLMUINT16)f_toascii( 'a'); - ui16SecondChar = (FLMUINT16)f_toascii( 'e'); - } - *pbTwoIntoOne = FALSE; - goto Exit; - case INSTIJ: - if (bUpperFlag) - { - *pui16WpChar = (FLMUINT16)f_toascii( 'I'); - ui16SecondChar = (FLMUINT16)f_toascii( 'J'); - } - else - { - *pui16WpChar = (FLMUINT16)f_toascii( 'i'); - ui16SecondChar = (FLMUINT16)f_toascii( 'j'); - } - *pbTwoIntoOne = FALSE; - goto Exit; - case INSTOE: - if (bUpperFlag) - { - *pui16WpChar = (FLMUINT16)f_toascii( 'O'); - ui16SecondChar = (FLMUINT16)f_toascii( 'E'); - } - else - { - *pui16WpChar = (FLMUINT16)f_toascii( 'o'); - ui16SecondChar = (FLMUINT16)f_toascii( 'e'); - } - *pbTwoIntoOne = FALSE; - goto Exit; - case WITHAA: - *pui16WpChar = (FLMUINT16)(bUpperFlag - ? (FLMUINT16)0x122 - : (FLMUINT16)0x123); - (*ppucInputStr)++; - break; - case AFTERC: - *pui16WpChar = (FLMUINT16)(bUpperFlag - ? (FLMUINT16)f_toascii( 'C') - : (FLMUINT16)f_toascii( 'c')); - ui16SecondChar = ui16LastChar; - *pbTwoIntoOne = TRUE; - (*ppucInputStr)++; - goto Exit; - case AFTERH: - *pui16WpChar = (FLMUINT16)(bUpperFlag - ? (FLMUINT16)f_toascii( 'H') - : (FLMUINT16)f_toascii( 'h')); - ui16SecondChar = ui16LastChar; - *pbTwoIntoOne = TRUE; - (*ppucInputStr)++; - goto Exit; - case AFTERL: - *pui16WpChar = (FLMUINT16)(bUpperFlag - ? (FLMUINT16)f_toascii( 'L') - : (FLMUINT16)f_toascii( 'l')); - ui16SecondChar = ui16LastChar; - *pbTwoIntoOne = TRUE; - (*ppucInputStr)++; - goto Exit; - default: - // Handles STATE1 through STATE11 also - break; - } - - if ((ui16CurState = getNextCharState( ui16CurState, - fwpCh6Lower( ui16WpChar))) == 0) - { - goto Exit; - } - ui16LastChar = ui16WpChar; - ui16WpChar = (FLMUINT16) *((*ppucInputStr) + (uiInLen++)); - } - -Exit: - - return( ui16SecondChar); -} diff --git a/flaim/src/fwpchrs.cpp b/flaim/src/fwpchrs.cpp deleted file mode 100644 index 97f171d..0000000 --- a/flaim/src/fwpchrs.cpp +++ /dev/null @@ -1,3166 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: WP character tables. -// Tabs: 3 -// -// Copyright (c) 1991-1992,1994-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fwpchrs.cpp 12301 2006-01-19 15:02:55 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#ifdef WIN32_EXTRA_LEAN - #undef WIN32_EXTRA_LEAN -#endif - -/*base character location*/ -/*bit mapped table. (1) - corresponding base char is in same set as combined*/ -/* (0) - corresponding base char is in ascii set*/ -/*NOTE: In the following table, the bits are numbered from left*/ -/* to right relative to each individual byte.*/ -/*EX. 00000000b ;0-7*/ -/*bit# 01234567*/ - -FLMBYTE fwp_ml1_cb60[] = { - 0x00, /*0-7*/ - 0x00, /*8-15*/ - 0x00, /*16-23*/ - 0x00, /*24-31*/ - 0x00, /*32-39*/ - 0x00, /*40-47*/ - 0x55, /*48-55*/ - 0x00, /*56-63*/ - 0x00, /*64-71*/ - 0x00, /*72-79*/ - 0x00, /*80-87*/ - 0x00, /*88-95*/ - 0x00, /*96-103*/ - 0x00, /*104-111*/ - 0x00, /*112-119*/ - 0x00, /*120-127*/ - 0x14, /*128-135*/ - 0x44, /*136-143*/ - 0x00, /*144-151*/ - 0x00, /*152-159*/ - 0x00, /*160-167*/ - 0x00, /*168-175*/ - 0x00, /*176-183*/ - 0x00, /*184-191*/ - 0x00, /*192-199*/ - 0x00, /*200-207*/ - 0x00, /*208-215*/ - 0x00, /*216-223*/ - 0x00, /*224-231*/ - 0x04, /*232-239*/ - 0x00, /*240-241*/ -}; - -/*Format of index:*/ -/* 2 words before = count.*/ -/* word before = start character.*/ -/* db code for base char.*/ -/* db code for diacritic */ -/*NOTE: diacritical char is always in same set as composed char*/ -/* base is in same set if other table indicates, else in ASCII*/ - -BASE_DIACRIT_TABLE fwp_ml1c_table[] = { - {'A',acute}, - {'a',acute}, - {'A',circum}, - {'a',circum}, - {'A',umlaut}, - {'a',umlaut}, - {'A',grave}, - {'a',grave}, - {'A',ring}, - {'a',ring}, - {0xff,0xff}, /*no AE diagraph.*/ - {0xff,0xff}, /*no ae diagraph.*/ - {'C',cedilla}, - {'c',cedilla}, - {'E',acute}, - {'e',acute}, - {'E',circum}, - {'e',circum}, - {'E',umlaut}, - {'e',umlaut}, - {'E',grave}, - {'e',grave}, - {'I',acute}, - {dotlesi,acute}, - {'I',circum}, - {dotlesi,circum}, - {'I',umlaut}, - {dotlesi,umlaut}, - {'I',grave}, - {dotlesi,grave}, - {'N',tilde}, - {'n',tilde}, - {'O',acute}, - {'o',acute}, - {'O',circum}, - {'o',circum}, - {'O',umlaut}, - {'o',umlaut}, - {'O',grave}, - {'o',grave}, - {'U',acute}, - {'u',acute}, - {'U',circum}, - {'u',circum}, - {'U',umlaut}, - {'u',umlaut}, - {'U',grave}, - {'u',grave}, - {'Y',umlaut}, - {'y',umlaut}, - {'A',tilde}, - {'a',tilde}, - {'D',crossb}, - {'d',crossb}, - {'O',slash}, - {'o',slash}, - {'O',tilde}, - {'o',tilde}, - {'Y',acute}, - {'y',acute}, - {0xff,0xff}, /*no eth*/ - {0xff,0xff}, /*no eth*/ - {0xff,0xff}, /*no Thorn*/ - {0xff,0xff}, /*no Thorn*/ - {'A',breve}, - {'a',breve}, - {'A',macron}, - {'a',macron}, - {'A',ogonek}, - {'a',ogonek}, - {'C',acute}, - {'c',acute}, - {'C',caron}, - {'c',caron}, - {'C',circum}, - {'c',circum}, - {'C',dota}, - {'c',dota}, - {'D',caron}, - {'d',caron}, - {'E',caron}, - {'e',caron}, - {'E',dota}, - {'e',dota}, - {'E',macron}, - {'e',macron}, - {'E',ogonek}, - {'e',ogonek}, - {'G',acute}, - {'g',acute}, - {'G',breve}, - {'g',breve}, - {'G',caron}, - {'g',caron}, - {'G',cedilla}, - {'g',aposab}, - {'G',circum}, - {'g',circum}, - {'G',dota}, - {'g',dota}, - {'H',circum}, - {'h',circum}, - {'H',crossb}, - {'h',crossb}, - {'I',dota}, - {dotlesi,dota}, - {'I',macron}, - {dotlesi,macron}, - {'I',ogonek}, - {'i',ogonek}, - {'I',tilde}, - {dotlesi,tilde}, - {0xff,0xff}, /*no IJ digraph*/ - {0xff,0xff}, /*no ij digraph*/ - {'J',circum}, - {dotlesj,circum}, - {'K',cedilla}, - {'k',cedilla}, - {'L',acute}, - {'l',acute}, - {'L',caron}, - {'l',caron}, - {'L',cedilla}, - {'l',cedilla}, - {'L',centerd}, - {'l',centerd}, - {'L',stroke}, - {'l',stroke}, - {'N',acute}, - {'n',acute}, - {'N',aposba}, - {'n',aposba}, - {'N',caron}, - {'n',caron}, - {'N',cedilla}, - {'n',cedilla}, - {'O',dacute}, - {'o',dacute}, - {'O',macron}, - {'o',macron}, - {0xff,0xff}, /*OE digraph*/ - {0xff,0xff}, /*oe digraph*/ - {'R',acute}, - {'r',acute}, - {'R',caron}, - {'r',caron}, - {'R',cedilla}, - {'r',cedilla}, - {'S',acute}, - {'s',acute}, - {'S',caron}, - {'s',caron}, - {'S',cedilla}, - {'s',cedilla}, - {'S',circum}, - {'s',circum}, - {'T',caron}, - {'t',caron}, - {'T',cedilla}, - {'t',cedilla}, - {'T',crossb}, - {'t',crossb}, - {'U',breve}, - {'u',breve}, - {'U',dacute}, - {'u',dacute}, - {'U',macron}, - {'u',macron}, - {'U',ogonek}, - {'u',ogonek}, - {'U',ring}, - {'u',ring}, - {'U',tilde}, - {'u',tilde}, - {'W',circum}, - {'w',circum}, - {'Y',circum}, - {'y',circum}, - {'Z',acute}, - {'z',acute}, - {'Z',caron}, - {'z',caron}, - {'Z',dota}, - {'z',dota}, - {0xff,0xff}, /*no Eng*/ - {0xff,0xff}, /*no eng*/ - {'D',macron}, - {'d',macron}, - {'L',macron}, - {'l',macron}, - {'N',macron}, - {'n',macron}, - {'R',grave}, - {'r',grave}, - {'S',macron}, - {'s',macron}, - {'T',macron}, - {'t',macron}, - {'Y',breve}, - {'y',breve}, - {'Y',grave}, - {'y',grave}, - {'D',aposbes}, - {'d',aposbes}, - {'O',aposbes}, - {'o',aposbes}, - {'U',aposbes}, - {'u',aposbes}, - {'E',breve}, - {'e',breve}, - {'I',breve}, - {dotlesi,breve}, - {0xff,0xff}, /*no dotless I*/ - {0xff,0xff}, /*no dotless i*/ - {'O',breve}, - {'o',breve} -}; - -BASE_DIACRIT fwp_ml1c = { - 216, /*# of characters in table.*/ - 26, /*start char.*/ - fwp_ml1c_table, -}; - -/* Format of index: */ -/* 2 words before = count. */ -/* word before = start character. */ -/* db code for base char. */ -/* db code for diacritic */ -/* NOTE: diacritical char is always in same set as composed char */ -/* base is in same set */ - -static BASE_DIACRIT_TABLE fwp_grk_c_table[] = { - { 0, ghprime }, /* ALPHA High Prime */ - { 1, gacute }, /* alpha acute */ - { 10, ghprime }, /* EPSILON High Prime */ - { 11, gacute }, /* epsilon Acute */ - { 14, ghprime }, /* ETA High Prime */ - { 15, gacute }, /* eta Acute */ - { 18, ghprime }, /* IOTA High Prime */ - { 19, gacute }, /* iota Acute */ - { 0xFF, 0xFF }, /* IOTA Diaeresis */ - { 19, gdia }, /* iota Diaeresis */ - { 30, ghprime }, /* OMICRON High Prime */ - { 31, gacute }, /* omicron Acute */ - { 42, ghprime }, /* UPSILON High Prime */ - { 43, gacute }, /* upsilon Acute */ - { 0xFF, 0xFF }, /* UPSILON Diaeresis */ - { 43,gdia }, /* upsilon Diaeresis */ - { 50,ghprime }, /* OMEGA High Prime */ - { 51,gacute }, /* omega Acute */ - { 0xFF, 0xFF }, /* epsilon (Variant) */ - { 0xFF, 0xFF }, /* theta (Variant) */ - { 0xFF, 0xFF }, /* kappa (Variant) */ - { 0xFF, 0xFF }, /* pi (Variant) */ - { 0xFF, 0xFF }, /* rho (Variant) */ - { 0xFF, 0xFF }, /* sigma (Variant) */ - { 0xFF, 0xFF }, /* UPSILON (Variant) */ - { 0xFF, 0xFF }, /* phi (Variant) */ - { 0xFF, 0xFF }, /* omega (Variant) */ - { 0xFF, 0xFF }, /* Greek Question Mark */ - { 0xFF, 0xFF }, /* Greek Semicolon */ - { 0xFF, 0xFF }, /* High Prime */ - { 0xFF, 0xFF }, /* Low Prime */ - { 0xFF, 0xFF }, /* Acute (Greek) */ - { 0xFF, 0xFF }, /* Diaeresis (Greek) */ - { gacute,gdia }, /* Acute Diaeresis */ - { ggrave, gdia }, /* Grave Diaeresis */ - { 0xFF, 0xFF }, /* Grave (Greek) */ - { 0xFF, 0xFF }, /* Circumflex (Greek) */ - { 0xFF, 0xFF }, /* Smooth Breathing */ - { 0xFF, 0xFF }, /* Rough Breathing */ - { 0xFF, 0xFF }, /* Iota Subscript */ - { gsmooth, gacute }, /* Smooth Breathing Acute */ - { grough, gacute }, /* Rough Breathing Acute */ - { gsmooth, ggrave }, /* Smooth Breathing Grave */ - { grough, ggrave }, /* Rough Breathing Grave */ - { gsmooth, gcircm }, /* Smooth Breathing Circumflex */ - { grough, gcircm }, /* Rough Breathing Circumflex */ - { gacute, giota }, /* Acute w/Iota Subscript */ - { ggrave, giota }, /* Grave w/Iota Subscript */ - { gcircm, giota }, /* Circumflex w/Iota Subscript */ - { gsmooth, giota }, /* Smooth Breathing w/Iota Subscript */ - { grough, giota }, /* Rough Breathing w/Iota Subscript */ - { gsmact, giota }, /* Smooth Breathing Acute w/Iota Subscript */ - { grgact, giota }, /* Rough Breathing Acute w/Iota Subscript */ - { gsmgrv, giota }, /* Smooth Breathing Grave w/Iota Subscript */ - { grggrv, giota }, /* Rough Breathing Grave w/Iota Subscript */ - { gsmcir, giota }, /* Smooth Breathing Circumflex w/Iota Sub */ - { grgcir, giota }, /* Rough Breathing Circumflex w/Iota Sub */ - { 1, ggrave }, /* alpha Grave */ - { 1, gcircm }, /* alpha Circumflex */ - { 1, giota }, /* alpha w/Iota */ - { 1, gactio }, /* alpha Acute w/Iota */ - { 1, ggrvio }, /* alpha Grave w/Iota */ - { 1, gcirio }, /* alpha Circumflex w/Iota */ - { 1, gsmooth }, /* alpha Smooth */ - { 1, gsmact }, /* alpha Smooth Acute */ - { 1, gsmgrv }, /* alpha Smooth Grave */ - { 1, gsmcir }, /* alpha Smooth Circumflex */ - { 1, gsmio }, /* alpha Smooth w/Iota */ - { 1, gsmaio }, /* alpha Smooth Acute w/Iota */ - { 1, gsmgvio }, /* alpha Smooth Grave w/Iota */ - { 1, gsmcio }, /* alpha Smooth Circumflex w/Iota */ - { 1, grough }, /* alpha Rough */ - { 1, grgact }, /* alpha Rough Acute */ - { 1, grggrv }, /* alpha Rough Grave */ - { 1, grgcir }, /* alpha Rough Circumflex */ - { 1, grgio }, /* alpha Rough w/Iota */ - { 1, grgaio }, /* alpha Rough Acute w/Iota */ - { 1, grggvio }, /* alpha Rough Grave w/Iota */ - { 1, grgcio }, /* alpha Rough Circumflex w/Iota */ - { 11, ggrave }, /* epsilon Grave */ - { 11, gsmooth }, /* epsilon Smooth */ - { 11, gsmact }, /* epsilon Smooth Acute */ - { 11, gsmgrv }, /* epsilon Smooth Grave */ - { 11, grough }, /* epsilon Rough */ - { 11, grgact }, /* epsilon Rough Acute */ - { 11, grggrv }, /* epsilon Rough Grave */ - { 15, ggrave }, /* eta Grave */ - { 15, gcircm }, /* eta Circumflex */ - { 15, giota }, /* eta w/Iota */ - { 15, gactio }, /* eta Acute w/Iota */ - { 15, ggrvio }, /* eta Grave w/Iota */ - { 15, gcirio }, /* eta Circumflex w/Iota */ - { 15, gsmooth }, /* eta Smooth */ - { 15, gsmact }, /* eta Smooth Acute */ - { 15, gsmgrv }, /* eta Smooth Grave */ - { 15, gsmcir }, /* eta Smooth Circumflex */ - { 15, gsmio }, /* eta Smooth w/Iota */ - { 15, gsmaio }, /* eta Smooth Acute w/Iota */ - { 15, gsmgvio }, /* eta Smooth Grave w/Iota */ - { 15, gsmcio }, /* eta Smooth Circumflex w/Iota */ - { 15, grough }, /* eta Rough */ - { 15, grgact }, /* eta Rough Acute */ - { 15, grggrv }, /* eta Rough Grave */ - { 15, grgcir }, /* eta Rough Circumflex */ - { 15, grgio }, /* eta Rough w/Iota */ - { 15, grgaio }, /* eta Rough Acute w/Iota */ - { 15, grggvio }, /* eta Rough Grave w/Iota */ - { 15, grgcio }, /* eta Rough Circumflex w/Iota */ - { 19, ggrave }, /* iota Grave */ - { 19, gcircm }, /* iota Circumflex */ - { 19, gactdia }, /* iota Acute Diaeresis */ - { 19, ggrvdia }, /* iota Grave Diaeresis */ - { 19, gsmooth }, /* iota Smooth */ - { 19, gsmact }, /* iota Smooth Acute */ - { 19, gsmgrv }, /* iota Smooth Grave */ - { 19, gsmcir }, /* iota Smooth Circumflex */ - { 19, grough }, /* iota Rough */ - { 19, grgact }, /* iota Rough Acute */ - { 19, grggrv }, /* iota Rough Grave */ - { 19, grgcir }, /* iota Rough Circumflex */ - { 31, ggrave }, /* omicron Grave */ - { 31, gsmooth }, /* omicron Smooth */ - { 31, gsmact }, /* omicron Smooth Acute */ - { 31, gsmgrv }, /* omicron Smooth Grave */ - { 31, grough }, /* omicron Rough */ - { 31, grgact }, /* omicron Rough Acute */ - { 31, grggrv }, /* omicron Rough Grave */ - { 0xFF, 0xFF }, /* rho rough */ - { 0xFF, 0xFF }, /* rho smooth */ - { 43, ggrave }, /* upsilon Grave */ - { 43, gcircm }, /* upsilon Circumflex */ - { 43, gactdia }, /* upsilon Acute Diaeresis */ - { 43, ggrvdia }, /* upsilon Grave Diaeresis */ - { 43, gsmooth }, /* upsilon Smooth */ - { 43, gsmact }, /* upsilon Smooth Acute */ - { 43, gsmgrv }, /* upsilon Smooth Grave */ - { 43, gsmcir }, /* upsilon Smooth Circumflex */ - { 43, grough }, /* upsilon Rough */ - { 43, grgact }, /* upsilon Rough Acute */ - { 43, grggrv }, /* upsilon Rough Grave */ - { 43, grgcir }, /* upsilon Rough Circumflex */ - { 51, ggrave }, /* omega Grave */ - { 51, gcircm }, /* omega Circumflex */ - { 51, giota }, /* omega w/Iota */ - { 51, gactio }, /* omega Acute w/Iota */ - { 51, ggrvio }, /* omega Grave w/Iota */ - { 51, gcirio }, /* omega Circumflex w/Iota */ - { 51, gsmooth }, /* omega Smooth */ - { 51, gsmact }, /* omega Smooth Acute */ - { 51, gsmgrv }, /* omega Smooth Grave */ - { 51, gsmcir }, /* omega Smooth Circumflex */ - { 51, gsmio }, /* omega Smooth w/Iota */ - { 51, gsmaio }, /* omega Smooth Acute w/Iota */ - { 51, gsmgvio }, /* omega Smooth Grave w/Iota */ - { 51, gsmcio }, /* omega Smooth Circumflex w/Iota */ - { 51, grough }, /* omega Rough */ - { 51, grgact }, /* omega Rough Acute */ - { 51, grggrv }, /* omega Rough Grave */ - { 51, grgcir }, /* omega Rough Circumflex */ - { 51, grgio }, /* omega Rough w/Iota */ - { 51, grgaio }, /* omega Rough Acute w/Iota */ - { 51, grggvio }, /* omega Rough Grave w/Iota */ - { 51, grgcio} /* omega Rough Circumflex w/Iota */ -}; - -static BASE_DIACRIT fwp_grk_c = { - 163, /* # of characters in table. */ - 52, /* start char. */ - fwp_grk_c_table -}; - -/* Format of index: */ -/* 2 words before = count. */ -/* word before = start character. */ -/* db code for base char. */ -/* db code for diacritic */ -/* NOTE: diacritical char is always in same set as composed char */ -/* base is in same set */ - -static BASE_DIACRIT_TABLE fwp_rus_c_table[] = { - { 14, 204 }, /* ZHE with right descender */ - { 15, 204 }, /* zhe with right descender */ - { 0xFF, 0xFF}, /* DZE */ - { 0xFF, 0xFF}, /* dze */ - { 0xFF, 0xFF}, /* Z */ - { 0xFF, 0xFF}, /* z */ - { 18, 206 }, /* II with macron */ - { 19, 206}, /* ii with macron */ - { 0xFF, 0xFF}, /* I */ - { 0xFF, 0xFF}, /* i */ - { 0xFF, 0xFF}, /* YI */ - { 0xFF, 0xFF}, /* yi */ - { 0xFF, 0xFF}, /* I ligature */ - { 0xFF, 0xFF}, /* i ligature */ - { 0xFF, 0xFF}, /* JE */ - { 0xFF, 0xFF}, /* je */ - { 0xFF, 0xFF}, /* KJE */ - { 0xFF, 0xFF}, /* kje */ - { 22, 204}, /* KA with right descender */ - { 23, 204}, /* ka with right descender */ - { 22, 205 }, /* KA ogonek */ - { 23, 205 }, /* ka ogonek */ - { 0xFF, 0xFF}, /* KA vertical bar */ - { 0xFF, 0xFF}, /* ka vertical bar */ - { 0xFF, 0xFF}, /* LJE */ - { 0xFF, 0xFF}, /* lje */ - { 28, 204 }, /* EN with right descender */ - { 29, 204 }, /* en with right descender */ - { 0xFF, 0xFF}, /* NJE */ - { 0xFF, 0xFF}, /* nje */ - { 0xFF, 0xFF}, /* ROUND OMEGA */ - { 0xFF, 0xFF}, /* round omega */ - { 0xFF, 0xFF}, /* OMEGA */ - { 0xFF, 0xFF}, /* omega */ - { 0xFF, 0xFF}, /* TSHE */ - { 0xFF, 0xFF}, /* tshe */ - { 0xFF, 0xFF}, /* SHORT U */ - { 0xFF, 0xFF}, /* short u */ - { 40, 206}, /* U with macron */ - { 41, 206 }, /* u with macron */ - { 0xFF, 0xFF}, /* STRAIGHT U */ - { 0xFF, 0xFF}, /* straight u */ - { 0xFF, 0xFF}, /* STRAIGHT U BAR */ - { 0xFF, 0xFF}, /* straight u bar */ - { 0xFF, 0xFF}, /* OU ligature */ - { 0xFF, 0xFF}, /* ou ligature */ - { 44, 204 }, /* KHA with right descender */ - { 45, 204 }, /* kha with right descender */ - { 44, 205 }, /* KHA ogonek */ - { 45, 205 }, /* kha ogonek */ - { 0xFF, 0xFF}, /* H */ - { 0xFF, 0xFF}, /* h */ - { 0xFF, 0xFF}, /* OMEGA titlo */ - { 0xFF, 0xFF}, /* omega titlo */ - { 0xFF, 0xFF}, /* DZHE */ - { 0xFF, 0xFF}, /* dzhe */ - { 48, 204 }, /* CHE with right descender */ - { 49, 204 }, /* che with right descender */ - { 0xFF, 0xFF}, /* CHE vertical bar */ - { 0xFF, 0xFF}, /* che vertical bar */ - { 0xFF, 0xFF}, /* SHCHA (variant) */ - { 0xFF, 0xFF}, /* shcha (variant) */ - { 0xFF, 0xFF}, /* YAT */ - { 0xFF, 0xFF}, /* yat */ - { 0xFF, 0xFF}, /* YUS BOLSHOI */ - { 0xFF, 0xFF}, /* yus bolshoi */ - { 0xFF, 0xFF}, /* BIG MALYI */ - { 0xFF, 0xFF}, /* big malyi */ - { 0xFF, 0xFF}, /* KSI */ - { 0xFF, 0xFF}, /* ksi */ - { 0xFF, 0xFF}, /* PSI */ - { 0xFF, 0xFF}, /* psi */ - { 0xFF, 0xFF}, /* FITA */ - { 0xFF, 0xFF}, /* fita */ - { 0xFF, 0xFF}, /* IZHITSA */ - { 0xFF, 0xFF}, /* izhitsa */ - { 00, racute}, /* Russian A acute */ - { 01, racute }, /* Russian a acute */ - { 10, racute }, /* Russian IE acute */ - { 11, racute }, /* Russian ie acute */ - { 78, racute }, /* Russian E acute */ - { 79, racute }, /* Russian e acute */ - { 18, racute }, /* Russian II acute */ - { 19, racute }, /* Russian ii acute */ - { 88, racute }, /* Russian I acute */ - { 89, racute }, /* Russian i acute */ - { 90, racute }, /* Russian YI acute */ - { 91, racute }, /* Russian yi acute */ - { 30, racute }, /* Russian O acute */ - { 31, racute }, /* Russian o acute */ - { 40, racute }, /* Russian U acute */ - { 41, racute }, /* Russian u acute */ - { 56, racute }, /* Russian YERI acute */ - { 57, racute }, /* Russian yeri acute */ - { 60, racute }, /* Russian REVERSED E acute */ - { 61, racute }, /* Russian reversed e acute */ - { 62, racute }, /* Russian IU acute */ - { 63, racute }, /* Russian iu acute */ - { 64, racute }, /* Russian IA acute */ - { 65, racute }, /* Russian ia acute */ - { 00, rgrave }, /* Russian A grave */ - { 01, rgrave }, /* Russian a grave */ - { 10, rgrave }, /* Russian IE grave */ - { 11, rgrave }, /* Russian ie grave */ - { 12, rgrave }, /* Russian YO grave */ - { 13, rgrave }, /* Russian yo grave */ - { 18, rgrave }, /* Russian I grave */ - { 19, rgrave }, /* Russian i grave */ - { 30, rgrave }, /* Russian O grave */ - { 31, rgrave }, /* Russian o grave */ - { 40, rgrave }, /* Russian U grave */ - { 41, rgrave }, /* Russian u grave */ - { 56, rgrave }, /* Russian YERI grave */ - { 57, rgrave }, /* Russian yeri grave */ - { 60, rgrave }, /* Russian REVERSED E grave */ - { 61, rgrave }, /* Russian reversed e grave */ - { 62, rgrave }, /* Russian IU grave */ - { 63, rgrave }, /* Russian iu grave */ - { 64, rgrave }, /* Russian IA grave */ - { 65, rgrave} /* Russian ia grave */ -}; - -static BASE_DIACRIT fwp_rus_c = { - 120, /* # of characters in table. */ - 156, /* start char. */ - fwp_rus_c_table, -}; - - -/*table of pointers to character component tables.*/ -/*order of equates in charset.inc*/ -BASE_DIACRIT *fwp_car60_c[NCHSETS] = { - (BASE_DIACRIT*)0, /* no composed characters for ascii. */ - &fwp_ml1c, - (BASE_DIACRIT*)0, /* no composed characters for multinational 2 */ - (BASE_DIACRIT*)0, /* no composed characters for line draw. */ - (BASE_DIACRIT*)0, /* no composed characters for typographic. */ - (BASE_DIACRIT*)0, /* no composed characters for icons. */ - (BASE_DIACRIT*)0, /* no composed characters for math. */ - (BASE_DIACRIT*)0, /* no composed characters for math extension. */ - &fwp_grk_c, /* Greek */ - (BASE_DIACRIT*)0, /* Hebrew */ - &fwp_rus_c, /* Cyrillic - Russian */ - (BASE_DIACRIT*)0, /* Hiragana or Katakana (Japanese) */ - (BASE_DIACRIT*)0, /* no composed characters for user. */ - (BASE_DIACRIT*)0, /* no composed characters for Arabic. */ - (BASE_DIACRIT*)0, /* no composed characters for Arabic Script . */ -}; - -FLMBYTE fwp_max_car60_size = NCHSETS; - -/*# of characters in each character set (see charset.inc)*/ - -FLMBYTE fwp_c60_max[] = { - ASC_N, /* ascii */ - ML1_N, /* multinational 1 */ - ML2_N, /* multinational 2 */ - BOX_N, /* line draw */ - TYP_N, /* typographic */ - ICN_N, /* icons */ - MTH_N, /* math */ - MTX_N, /* math extension */ - GRK_N, /* Greek */ - HEB_N, /* Hebrew */ - CYR_N, /* Cyrillic - Russian */ - KAN_N, /* Kana */ - USR_N, /* user */ - ARB_N, /* Arabic */ - ARS_N, /* Arabic Script */ -}; - - -FLMUINT16 * WP60toUni[] = { - 0, - WPCH_WP60UNI1, - WPCH_WP60UNI2, - WPCH_WPUNI3, - WPCH_WPUNI4, - WPCH_WP60UNI5, - WPCH_WPUNI6, - WPCH_WPUNI7, - WPCH_WP60UNI8, - WPCH_WP60UNI9, - WPCH_WP60UNI10, - WPCH_WP60UNI11, - 0, - WPCH_WPUNI13, - WPCH_WPUNI14 -}; - -FLMUINT16 * WP60toCpxUni[] = { - 0, - (FLMUINT16 *)WPCH_CPXTAB1, - 0, - 0, - 0, - 0, - 0, - 0, - (FLMUINT16 *)WPCH_CPXGREEK, - (FLMUINT16 *)WPCH_CPXHEBREW, - (FLMUINT16 *)WPCH_CPXCYRILLIC, - (FLMUINT16 *)WPCH_CPXARABIC, - (FLMUINT16 *)WPCH_CPXARABIC2 -}; - - -/********************************************************************************************************************************************************************** -* UNICODE to WP6 -* Unicode character -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -**********************************************************************************************************************************************************************/ - -/* UTOWP_ENTRIES is defined in wpchu._h as 2042 (Oct98). - This define absolutely needs to - be updated if any additions or deletions are made to the following table */ - -FLMUINT16 WP_UTOWP60[UTOWP60_ENTRIES][2] = { -{ 0x00A1, 0x0407 }, /* 7 , 4, */ -{ 0x00A2, 0x0413 }, /* 19 , 4, */ -{ 0x00A3, 0x040b }, /* 11 , 4, */ -{ 0x00A4, 0x0418 }, /* 24 , 4, */ -{ 0x00A5, 0x040c }, /* 12 , 4, */ -{ 0x00A7, 0x0406 }, /* 6 , 4, */ -{ 0x00A9, 0x0417 }, /* 23 , 4, */ -{ 0x00AA, 0x040f }, /* 15 , 4, */ -{ 0x00AB, 0x0409 }, /* 9 , 4, */ -{ 0x00AC, 0x0614 }, /* 20 , 6, */ -{ 0x00AE, 0x0416 }, /* 22 , 4, */ -{ 0x00B0, 0x0624 }, /* 36 , 6, */ -{ 0x00B1, 0x0601 }, /* 1 , 6, */ -{ 0x00B2, 0x0414 }, /* 20 , 4, */ -{ 0x00B3, 0x041a }, /* 26 , 4, */ -{ 0x00B5, 0x0625 }, /* 37 , 6, */ -{ 0x00B6, 0x0405 }, /* 5 , 4, */ -{ 0x00B7, 0x0101 }, /* 101, 1, */ -{ 0x00B9, 0x044e }, /* 78 , 4, */ -{ 0x00BA, 0x0410 }, /* 16 , 4, */ -{ 0x00BB, 0x040a }, /* 10 , 4, */ -{ 0x00BC, 0x0412 }, /* 18 , 4, */ -{ 0x00BD, 0x0411 }, /* 17 , 4, */ -{ 0x00BE, 0x0419 }, /* 25 , 4, */ -{ 0x00BF, 0x0408 }, /* 8 , 4, */ -{ 0x00C0, 0x0120 }, /* 32 , 1, */ -{ 0x00C1, 0x011a }, /* 26 , 1, */ -{ 0x00C2, 0x011c }, /* 28 , 1, */ -{ 0x00C3, 0x014c }, /* 76 , 1, */ -{ 0x00C4, 0x011e }, /* 30 , 1, */ -{ 0x00C5, 0x0122 }, /* 34 , 1, */ -{ 0x00C6, 0x0124 }, /* 36 , 1, */ -{ 0x00C7, 0x0126 }, /* 38 , 1, */ -{ 0x00C8, 0x012e }, /* 46 , 1, */ -{ 0x00C9, 0x0128 }, /* 40 , 1, */ -{ 0x00CA, 0x012a }, /* 42 , 1, */ -{ 0x00CB, 0x012c }, /* 44 , 1, */ -{ 0x00CC, 0x0136 }, /* 54 , 1, */ -{ 0x00CD, 0x0130 }, /* 48 , 1, */ -{ 0x00CE, 0x0132 }, /* 50 , 1, */ -{ 0x00CF, 0x0134 }, /* 52 , 1, */ -{ 0x00D0, 0x0156 }, /* 86 , 1, */ -{ 0x00D1, 0x0138 }, /* 56 , 1, */ -{ 0x00D2, 0x0140 }, /* 64 , 1, */ -{ 0x00D3, 0x013a }, /* 58 , 1, */ -{ 0x00D4, 0x013c }, /* 60 , 1, */ -{ 0x00D5, 0x0152 }, /* 82 , 1, */ -{ 0x00D6, 0x013e }, /* 62 , 1, */ -{ 0x00D7, 0x0627 }, /* 39 , 6, */ -{ 0x00D8, 0x0150 }, /* 80 , 1, */ -{ 0x00D9, 0x0148 }, /* 72 , 1, */ -{ 0x00DA, 0x0142 }, /* 66 , 1, */ -{ 0x00DB, 0x0144 }, /* 68 , 1, */ -{ 0x00DC, 0x0146 }, /* 70 , 1, */ -{ 0x00DD, 0x0154 }, /* 84 , 1, */ -{ 0x00DE, 0x0158 }, /* 88 , 1, */ -{ 0x00DF, 0x0117 }, /* 23 , 1, */ -{ 0x00E0, 0x0121 }, /* 33 , 1, */ -{ 0x00E1, 0x011b }, /* 27 , 1, */ -{ 0x00E2, 0x011d }, /* 29 , 1, */ -{ 0x00E3, 0x014d }, /* 77 , 1, */ -{ 0x00E4, 0x011f }, /* 31 , 1, */ -{ 0x00E5, 0x0123 }, /* 35 , 1, */ -{ 0x00E6, 0x0125 }, /* 37 , 1, */ -{ 0x00E7, 0x0127 }, /* 39 , 1, */ -{ 0x00E8, 0x012f }, /* 47 , 1, */ -{ 0x00E9, 0x0129 }, /* 41 , 1, */ -{ 0x00EA, 0x012b }, /* 43 , 1, */ -{ 0x00EB, 0x012d }, /* 45 , 1, */ -{ 0x00EC, 0x0137 }, /* 55 , 1, */ -{ 0x00ED, 0x0131 }, /* 49 , 1, */ -{ 0x00EE, 0x0133 }, /* 51 , 1, */ -{ 0x00EF, 0x0135 }, /* 53 , 1, */ -{ 0x00F0, 0x0157 }, /* 87 , 1, */ -{ 0x00F1, 0x0139 }, /* 57 , 1, */ -{ 0x00F2, 0x0141 }, /* 65 , 1, */ -{ 0x00F3, 0x013b }, /* 59 , 1, */ -{ 0x00F4, 0x013d }, /* 61 , 1, */ -{ 0x00F5, 0x0153 }, /* 83 , 1, */ -{ 0x00F6, 0x013f }, /* 63 , 1, */ -{ 0x00F7, 0x0608 }, /* 8 , 6, */ -{ 0x00F8, 0x0151 }, /* 81 , 1, */ -{ 0x00F9, 0x0149 }, /* 73 , 1, */ -{ 0x00FA, 0x0143 }, /* 67 , 1, */ -{ 0x00FB, 0x0145 }, /* 69 , 1, */ -{ 0x00FC, 0x0147 }, /* 71 , 1, */ -{ 0x00FD, 0x0155 }, /* 85 , 1, */ -{ 0x00FE, 0x0159 }, /* 89 , 1, */ -{ 0x00FF, 0x014b }, /* 75 , 1, */ -{ 0x0100, 0x015c }, /* 92 , 1, */ -{ 0x0101, 0x015d }, /* 93 , 1, */ -{ 0x0102, 0x015a }, /* 90 , 1, */ -{ 0x0103, 0x015b }, /* 91 , 1, */ -{ 0x0104, 0x015e }, /* 94 , 1, */ -{ 0x0105, 0x015f }, /* 95 , 1, */ -{ 0x0106, 0x0160 }, /* 96 , 1, */ -{ 0x0107, 0x0161 }, /* 97 , 1, */ -{ 0x0108, 0x0164 }, /* 100, 1, */ -{ 0x0109, 0x0165 }, /* 101, 1, */ -{ 0x010A, 0x0166 }, /* 102, 1, */ -{ 0x010B, 0x0167 }, /* 103, 1, */ -{ 0x010C, 0x0162 }, /* 98 , 1, */ -{ 0x010D, 0x0163 }, /* 99 , 1, */ -{ 0x010E, 0x0168 }, /* 104, 1, */ -{ 0x010F, 0x0169 }, /* 105, 1, */ -{ 0x0110, 0x014e }, /* 78 , 1, */ -{ 0x0111, 0x014f }, /* 79 , 1, */ -{ 0x0112, 0x016e }, /* 110, 1, */ -{ 0x0113, 0x016f }, /* 111, 1, */ -{ 0x0114, 0x01ea }, /* 234, 1, */ -{ 0x0115, 0x01eb }, /* 235, 1, */ -{ 0x0116, 0x016c }, /* 108, 1, */ -{ 0x0117, 0x016d }, /* 109, 1, */ -{ 0x0118, 0x0170 }, /* 112, 1, */ -{ 0x0119, 0x0171 }, /* 113, 1, */ -{ 0x011A, 0x016a }, /* 106, 1, */ -{ 0x011B, 0x016b }, /* 107, 1, */ -{ 0x011C, 0x017a }, /* 122, 1, */ -{ 0x011D, 0x017b }, /* 123, 1, */ -{ 0x011E, 0x0174 }, /* 116, 1, */ -{ 0x011F, 0x0175 }, /* 117, 1, */ -{ 0x0120, 0x017c }, /* 124, 1, */ -{ 0x0121, 0x017d }, /* 125, 1, */ -{ 0x0122, 0x0178 }, /* 120, 1, */ -{ 0x0123, 0x0179 }, /* 121, 1, */ -{ 0x0124, 0x017e }, /* 126, 1, */ -{ 0x0125, 0x017f }, /* 127, 1, */ -{ 0x0126, 0x0180 }, /* 128, 1, */ -{ 0x0127, 0x0181 }, /* 129, 1, */ -{ 0x0128, 0x0188 }, /* 136, 1, */ -{ 0x0129, 0x0189 }, /* 137, 1, */ -{ 0x012A, 0x0184 }, /* 132, 1, */ -{ 0x012B, 0x0185 }, /* 133, 1, */ -{ 0x012C, 0x01ec }, /* 236, 1, */ -{ 0x012D, 0x01ed }, /* 237, 1, */ -{ 0x012E, 0x0186 }, /* 134, 1, */ -{ 0x012F, 0x0187 }, /* 135, 1, */ -{ 0x0130, 0x0182 }, /* 130, 1, */ -{ 0x0131, 0x01ef }, /* 239, 1, */ -{ 0x0132, 0x018a }, /* 138, 1, */ -{ 0x0133, 0x018b }, /* 139, 1, */ -{ 0x0134, 0x018c }, /* 140, 1, */ -{ 0x0135, 0x018d }, /* 141, 1, */ -{ 0x0136, 0x018e }, /* 142, 1, */ -{ 0x0137, 0x018f }, /* 143, 1, */ -{ 0x0138, 0x0118 }, /* 24 , 1, */ -{ 0x0139, 0x0190 }, /* 144, 1, */ -{ 0x013A, 0x0191 }, /* 145, 1, */ -{ 0x013B, 0x0194 }, /* 148, 1, */ -{ 0x013C, 0x0195 }, /* 149, 1, */ -{ 0x013D, 0x0192 }, /* 146, 1, */ -{ 0x013E, 0x0193 }, /* 147, 1, */ -{ 0x013F, 0x0196 }, /* 150, 1, */ -{ 0x0140, 0x0197 }, /* 151, 1, */ -{ 0x0141, 0x0198 }, /* 152, 1, */ -{ 0x0142, 0x0199 }, /* 153, 1, */ -{ 0x0143, 0x019a }, /* 154, 1, */ -{ 0x0144, 0x019b }, /* 155, 1, */ -{ 0x0145, 0x01a0 }, /* 160, 1, */ -{ 0x0146, 0x01a1 }, /* 161, 1, */ -{ 0x0147, 0x019e }, /* 158, 1, */ -{ 0x0148, 0x019f }, /* 159, 1, */ -{ 0x0149, 0x019d }, /* 157, 1, */ -{ 0x014A, 0x01d2 }, /* 210, 1, */ -{ 0x014B, 0x01d3 }, /* 211, 1, */ -{ 0x014C, 0x01a4 }, /* 164, 1, */ -{ 0x014D, 0x01a5 }, /* 165, 1, */ -{ 0x014E, 0x01f0 }, /* 240, 1, */ -{ 0x014F, 0x01f1 }, /* 241, 1, */ -{ 0x0150, 0x01a2 }, /* 162, 1, */ -{ 0x0151, 0x01a3 }, /* 163, 1, */ -{ 0x0152, 0x01a6 }, /* 166, 1, */ -{ 0x0153, 0x01a7 }, /* 167, 1, */ -{ 0x0154, 0x01a8 }, /* 168, 1, */ -{ 0x0155, 0x01a9 }, /* 169, 1, */ -{ 0x0156, 0x01ac }, /* 172, 1, */ -{ 0x0157, 0x01ad }, /* 173, 1, */ -{ 0x0158, 0x01aa }, /* 170, 1, */ -{ 0x0159, 0x01ab }, /* 171, 1, */ -{ 0x015A, 0x01ae }, /* 174, 1, */ -{ 0x015B, 0x01af }, /* 175, 1, */ -{ 0x015C, 0x01b4 }, /* 180, 1, */ -{ 0x015D, 0x01b5 }, /* 181, 1, */ -{ 0x015E, 0x01b2 }, /* 178, 1, */ -{ 0x015F, 0x01b3 }, /* 179, 1, */ -{ 0x0160, 0x01b0 }, /* 176, 1, */ -{ 0x0161, 0x01b1 }, /* 177, 1, */ -{ 0x0162, 0x01b8 }, /* 184, 1, */ -{ 0x0163, 0x01b9 }, /* 185, 1, */ -{ 0x0164, 0x01b6 }, /* 182, 1, */ -{ 0x0165, 0x01b7 }, /* 183, 1, */ -{ 0x0166, 0x01ba }, /* 186, 1, */ -{ 0x0167, 0x01bb }, /* 187, 1, */ -{ 0x0168, 0x01c6 }, /* 198, 1, */ -{ 0x0169, 0x01c7 }, /* 199, 1, */ -{ 0x016A, 0x01c0 }, /* 192, 1, */ -{ 0x016B, 0x01c1 }, /* 193, 1, */ -{ 0x016C, 0x01bc }, /* 188, 1, */ -{ 0x016D, 0x01bd }, /* 189, 1, */ -{ 0x016E, 0x01c4 }, /* 196, 1, */ -{ 0x016F, 0x01c5 }, /* 197, 1, */ -{ 0x0170, 0x01be }, /* 190, 1, */ -{ 0x0171, 0x01bf }, /* 191, 1, */ -{ 0x0172, 0x01c2 }, /* 194, 1, */ -{ 0x0173, 0x01c3 }, /* 195, 1, */ -{ 0x0174, 0x01c8 }, /* 200, 1, */ -{ 0x0175, 0x01c9 }, /* 201, 1, */ -{ 0x0176, 0x01ca }, /* 202, 1, */ -{ 0x0177, 0x01cb }, /* 203, 1, */ -{ 0x0178, 0x014a }, /* 74 , 1, */ -{ 0x0179, 0x01cc }, /* 204, 1, */ -{ 0x017A, 0x01cd }, /* 205, 1, */ -{ 0x017B, 0x01d0 }, /* 208, 1, */ -{ 0x017C, 0x01d1 }, /* 209, 1, */ -{ 0x017D, 0x01ce }, /* 206, 1, */ -{ 0x017E, 0x01cf }, /* 207, 1, */ -{ 0x0192, 0x040e }, /* 14 , 4, */ -{ 0x0194, 0x0a7c }, /* 124, 10, */ -{ 0x01A0, 0x01e6 }, /* 230, 1, */ -{ 0x01A1, 0x01e7 }, /* 231, 1, */ -{ 0x01AF, 0x01e8 }, /* 232, 1, */ -{ 0x01B0, 0x01e9 }, /* 233, 1, */ -{ 0x01C0, 0x0605 }, /* 5 , 6, */ -{ 0x0250, 0x0237 }, /* 55 , 2, */ -{ 0x0251, 0x0238 }, /* 56 , 2, */ -{ 0x0252, 0x0239 }, /* 57 , 2, */ -{ 0x0253, 0x023a }, /* 58 , 2, */ -{ 0x0254, 0x023c }, /* 60 , 2, */ -{ 0x0255, 0x023d }, /* 61 , 2, */ -{ 0x0256, 0x023f }, /* 63 , 2, */ -{ 0x0257, 0x0240 }, /* 64 , 2, */ -{ 0x0258, 0x0241 }, /* 65 , 2, */ -{ 0x0259, 0x0242 }, /* 66 , 2, */ -{ 0x025A, 0x0243 }, /* 67 , 2, */ -{ 0x025B, 0x0244 }, /* 68 , 2, */ -{ 0x025C, 0x0245 }, /* 69 , 2, */ -{ 0x025D, 0x0246 }, /* 70 , 2, */ -{ 0x025E, 0x0248 }, /* 72 , 2, */ -{ 0x025F, 0x0249 }, /* 73 , 2, */ -{ 0x0260, 0x024c }, /* 76 , 2, */ -{ 0x0261, 0x024b }, /* 75 , 2, */ -{ 0x0262, 0x024d }, /* 77 , 2, */ -{ 0x0263, 0x024f }, /* 79 , 2, */ -{ 0x0264, 0x0250 }, /* 80 , 2, */ -{ 0x0265, 0x0251 }, /* 81 , 2, */ -{ 0x0266, 0x0252 }, /* 82 , 2, */ -{ 0x0267, 0x0253 }, /* 83 , 2, */ -{ 0x0268, 0x0255 }, /* 85 , 2, */ -{ 0x0269, 0x0257 }, /* 87 , 2, */ -{ 0x026A, 0x0256 }, /* 86 , 2, */ -{ 0x026B, 0x025a }, /* 90 , 2, */ -{ 0x026C, 0x025b }, /* 91 , 2, */ -{ 0x026D, 0x025c }, /* 92 , 2, */ -{ 0x026E, 0x025e }, /* 94 , 2, */ -{ 0x026F, 0x0260 }, /* 96 , 2, */ -{ 0x0270, 0x0261 }, /* 97 , 2, */ -{ 0x0271, 0x0262 }, /* 98 , 2, */ -{ 0x0272, 0x0263 }, /* 99 , 2, */ -{ 0x0273, 0x0264 }, /* 100, 2, */ -{ 0x0274, 0x0265 }, /* 101, 2, */ -{ 0x0275, 0x0279 }, /* 121, 2, */ -{ 0x0276, 0x0266 }, /* 102, 2, */ -{ 0x0277, 0x0267 }, /* 103, 2, */ -{ 0x0278, 0x024a }, /* 74 , 2, */ -{ 0x0279, 0x0269 }, /* 105, 2, */ -{ 0x027A, 0x026a }, /* 106, 2, */ -{ 0x027B, 0x026b }, /* 107, 2, */ -{ 0x027C, 0x026c }, /* 108, 2, */ -{ 0x027D, 0x026d }, /* 109, 2, */ -{ 0x027E, 0x026e }, /* 110, 2, */ -{ 0x027F, 0x026f }, /* 111, 2, */ -{ 0x0280, 0x0270 }, /* 112, 2, */ -{ 0x0281, 0x0271 }, /* 113, 2, */ -{ 0x0282, 0x0272 }, /* 114, 2, */ -{ 0x0283, 0x0273 }, /* 115, 2, */ -{ 0x0284, 0x0274 }, /* 116, 2, */ -{ 0x0285, 0x0275 }, /* 117, 2, */ -{ 0x0286, 0x0276 }, /* 118, 2, */ -{ 0x0287, 0x0277 }, /* 119, 2, */ -{ 0x0288, 0x0278 }, /* 120, 2, */ -{ 0x0289, 0x027a }, /* 122, 2, */ -{ 0x028A, 0x027b }, /* 123, 2, */ -{ 0x028B, 0x027d }, /* 125, 2, */ -{ 0x028C, 0x027c }, /* 124, 2, */ -{ 0x028D, 0x027e }, /* 126, 2, */ -{ 0x028E, 0x025f }, /* 95 , 2, */ -{ 0x028F, 0x0280 }, /* 128, 2, */ -{ 0x0290, 0x0281 }, /* 129, 2, */ -{ 0x0291, 0x0282 }, /* 130, 2, */ -{ 0x0292, 0x0283 }, /* 131, 2, */ -{ 0x0293, 0x0284 }, /* 132, 2, */ -{ 0x0294, 0x0285 }, /* 133, 2, */ -{ 0x0295, 0x0286 }, /* 134, 2, */ -{ 0x0296, 0x0287 }, /* 135, 2, */ -{ 0x0297, 0x023e }, /* 62 , 2, */ -{ 0x0298, 0x028a }, /* 138, 2, */ -{ 0x0299, 0x023b }, /* 59 , 2, */ -{ 0x029A, 0x0247 }, /* 71 , 2, */ -{ 0x029B, 0x024e }, /* 78 , 2, */ -{ 0x029C, 0x0254 }, /* 84 , 2, */ -{ 0x029D, 0x0258 }, /* 88 , 2, */ -{ 0x029E, 0x0259 }, /* 89 , 2, */ -{ 0x029F, 0x025d }, /* 93 , 2, */ -{ 0x02A0, 0x0268 }, /* 104, 2, */ -{ 0x02A1, 0x0288 }, /* 136, 2, */ -{ 0x02A2, 0x0289 }, /* 137, 2, */ -{ 0x02A3, 0x028b }, /* 139, 2, */ -{ 0x02A4, 0x028c }, /* 140, 2, */ -{ 0x02A5, 0x028d }, /* 141, 2, */ -{ 0x02A6, 0x028e }, /* 142, 2, */ -{ 0x02A7, 0x028f }, /* 143, 2, */ -{ 0x02A8, 0x0290 }, /* 144, 2, */ -{ 0x02B0, 0x0235 }, /* 53 , 2, */ -{ 0x02B6, 0x0236 }, /* 54 , 2, */ -{ 0x02B9, 0x0200 }, /* 0 , 2, */ -{ 0x02BA, 0x0201 }, /* 1 , 2, */ -{ 0x02BB, 0x0202 }, /* 2 , 2, */ -{ 0x02BC, 0x0205 }, /* 5 , 2, */ -{ 0x02BD, 0x0204 }, /* 4 , 2, */ -{ 0x02BE, 0x0207 }, /* 7 , 2, */ -{ 0x02BF, 0x0208 }, /* 8 , 2, */ -{ 0x02C6, 0x0217 }, /* 23 , 2, */ -{ 0x02C7, 0x0218 }, /* 24 , 2, */ -{ 0x02C8, 0x020f }, /* 15 , 2, */ -{ 0x02C9, 0x0211 }, /* 17 , 2, */ -{ 0x02CA, 0x0212 }, /* 18 , 2, */ -{ 0x02CB, 0x0213 }, /* 19 , 2, */ -{ 0x02CC, 0x0210 }, /* 16 , 2, */ -{ 0x02CD, 0x0214 }, /* 20 , 2, */ -{ 0x02CE, 0x0215 }, /* 21 , 2, */ -{ 0x02CF, 0x0216 }, /* 22 , 2, */ -{ 0x02D0, 0x020a }, /* 10 , 2, */ -{ 0x02D1, 0x020b }, /* 11 , 2, */ -{ 0x02D2, 0x022a }, /* 42 , 2, */ -{ 0x02D3, 0x022b }, /* 43 , 2, */ -{ 0x02DA, 0x021b }, /* 27 , 2, */ -{ 0x02DB, 0x0231 }, /* 49 , 2, */ -{ 0x02DC, 0x0219 }, /* 25 , 2, */ -{ 0x02DE, 0x0233 }, /* 51 , 2, */ -{ 0x0300, 0x0100 }, /* 0 , 1, */ -{ 0x0301, 0x0106 }, /* 6 , 1, */ -{ 0x0302, 0x0103 }, /* 3 , 1, */ -{ 0x0303, 0x0102 }, /* 2 , 1, */ -{ 0x0304, 0x0108 }, /* 8 , 1, */ -{ 0x0305, 0x0115 }, /* 21 , 1, */ -{ 0x0306, 0x0116 }, /* 22 , 1, */ -{ 0x0307, 0x010f }, /* 15 , 1, */ -{ 0x0308, 0x0107 }, /* 7 , 1, */ -{ 0x030A, 0x010e }, /* 14 , 1, */ -{ 0x030B, 0x0110 }, /* 16 , 1, */ -{ 0x030C, 0x0113 }, /* 19 , 1, */ -{ 0x0310, 0x0209 }, /* 9 , 2, */ -{ 0x0311, 0x0858 }, /* 88 , 8, */ -{ 0x0313, 0x0109 }, /* 9 , 1, */ -{ 0x0314, 0x085a }, /* 90 , 8, */ -{ 0x0315, 0x010a }, /* 10 , 1, */ -{ 0x031C, 0x0221 }, /* 33 , 2, */ -{ 0x031D, 0x0222 }, /* 34 , 2, */ -{ 0x031E, 0x0223 }, /* 35 , 2, */ -{ 0x031F, 0x0224 }, /* 36 , 2, */ -{ 0x0320, 0x0225 }, /* 37 , 2, */ -{ 0x0321, 0x0226 }, /* 38 , 2, */ -{ 0x0322, 0x0227 }, /* 39 , 2, */ -{ 0x0323, 0x021e }, /* 30 , 2, */ -{ 0x0324, 0x0220 }, /* 32 , 2, */ -{ 0x0325, 0x021a }, /* 26 , 2, */ -{ 0x0326, 0x010c }, /* 12 , 1, */ -{ 0x0327, 0x0111 }, /* 17 , 1, */ -{ 0x0328, 0x0112 }, /* 18 , 1, */ -{ 0x0329, 0x020e }, /* 14 , 2, */ -{ 0x032A, 0x0228 }, /* 40 , 2, */ -{ 0x032B, 0x0229 }, /* 41 , 2, */ -{ 0x032C, 0x021d }, /* 29 , 2, */ -{ 0x032D, 0x021c }, /* 28 , 2, */ -{ 0x032E, 0x020d }, /* 13 , 2, */ -{ 0x0335, 0x0104 }, /* 4 , 1, */ -{ 0x0337, 0x0114 }, /* 20 , 1, */ -{ 0x0338, 0x0105 }, /* 5 , 1, */ -{ 0x033E, 0x0230 }, /* 48 , 2, */ -{ 0x0345, 0x085b }, /* 91 , 8, */ -{ 0x0374, 0x0851 }, /* 81 , 8, */ -{ 0x0375, 0x0852 }, /* 82 , 8, */ -{ 0x0391, 0x0800 }, /* 0 , 8, */ -{ 0x0392, 0x0802 }, /* 2 , 8, */ -{ 0x0393, 0x0806 }, /* 6 , 8, */ -{ 0x0394, 0x0808 }, /* 8 , 8, */ -{ 0x0395, 0x080a }, /* 10 , 8, */ -{ 0x0396, 0x080c }, /* 12 , 8, */ -{ 0x0397, 0x080e }, /* 14 , 8, */ -{ 0x0398, 0x0810 }, /* 16 , 8, */ -{ 0x0399, 0x0812 }, /* 18 , 8, */ -{ 0x039A, 0x0814 }, /* 20 , 8, */ -{ 0x039B, 0x0816 }, /* 22 , 8, */ -{ 0x039C, 0x0818 }, /* 24 , 8, */ -{ 0x039D, 0x081a }, /* 26 , 8, */ -{ 0x039E, 0x081c }, /* 28 , 8, */ -{ 0x039F, 0x081e }, /* 30 , 8, */ -{ 0x03A0, 0x0820 }, /* 32 , 8, */ -{ 0x03A1, 0x0822 }, /* 34 , 8, */ -{ 0x03A3, 0x0824 }, /* 36 , 8, */ -{ 0x03A4, 0x0828 }, /* 40 , 8, */ -{ 0x03A5, 0x082a }, /* 42 , 8, */ -{ 0x03A6, 0x082c }, /* 44 , 8, */ -{ 0x03A7, 0x082e }, /* 46 , 8, */ -{ 0x03A8, 0x0830 }, /* 48 , 8, */ -{ 0x03A9, 0x0832 }, /* 50 , 8, */ -{ 0x03AA, 0x083c }, /* 60 , 8, */ -{ 0x03AB, 0x0842 }, /* 66 , 8, */ -{ 0x03AC, 0x0835 }, /* 53 , 8, */ -{ 0x03AD, 0x0837 }, /* 55 , 8, */ -{ 0x03AE, 0x0839 }, /* 57 , 8, */ -{ 0x03AF, 0x083b }, /* 59 , 8, */ -{ 0x03B1, 0x0801 }, /* 1 , 8, */ -{ 0x03B2, 0x0803 }, /* 3 , 8, */ -{ 0x03B3, 0x0807 }, /* 7 , 8, */ -{ 0x03B4, 0x0809 }, /* 9 , 8, */ -{ 0x03B5, 0x080b }, /* 11 , 8, */ -{ 0x03B6, 0x080d }, /* 13 , 8, */ -{ 0x03B7, 0x080f }, /* 15 , 8, */ -{ 0x03B8, 0x0811 }, /* 17 , 8, */ -{ 0x03B9, 0x0813 }, /* 19 , 8, */ -{ 0x03BA, 0x0815 }, /* 21 , 8, */ -{ 0x03BB, 0x0817 }, /* 23 , 8, */ -{ 0x03BC, 0x0819 }, /* 25 , 8, */ -{ 0x03BD, 0x081b }, /* 27 , 8, */ -{ 0x03BE, 0x081d }, /* 29 , 8, */ -{ 0x03BF, 0x081f }, /* 31 , 8, */ -{ 0x03C0, 0x0821 }, /* 33 , 8, */ -{ 0x03C1, 0x0823 }, /* 35 , 8, */ -{ 0x03C2, 0x0827 }, /* 39 , 8, */ -{ 0x03C3, 0x0825 }, /* 37 , 8, */ -{ 0x03C4, 0x0829 }, /* 41 , 8, */ -{ 0x03C5, 0x082b }, /* 43 , 8, */ -{ 0x03C6, 0x082d }, /* 45 , 8, */ -{ 0x03C7, 0x082f }, /* 47 , 8, */ -{ 0x03C8, 0x0831 }, /* 49 , 8, */ -{ 0x03C9, 0x0833 }, /* 51 , 8, */ -{ 0x03CA, 0x083d }, /* 61 , 8, */ -{ 0x03CB, 0x0843 }, /* 67 , 8, */ -{ 0x03CC, 0x083f }, /* 63 , 8, */ -{ 0x03CD, 0x0841 }, /* 65 , 8, */ -{ 0x03CE, 0x0845 }, /* 69 , 8, */ -{ 0x03D0, 0x0805 }, /* 5 , 8, */ -{ 0x03D1, 0x0847 }, /* 71 , 8, */ -{ 0x03D2, 0x084c }, /* 76 , 8, */ -{ 0x03D5, 0x084d }, /* 77 , 8, */ -{ 0x03D6, 0x0849 }, /* 73 , 8, */ -{ 0x03D7, 0x084f }, /* 79 , 8, */ -{ 0x03DA, 0x08d7 }, /* 215, 8, */ -{ 0x03DB, 0x084B }, /* 75 , 8, */ -{ 0x03DC, 0x08d8 }, /* 216, 8, */ -{ 0x03DE, 0x08d9 }, /* 217, 8, */ -{ 0x03E0, 0x08da }, /* 218, 8, */ -{ 0x03F0, 0x0848 }, /* 72 , 8, */ -{ 0x03F1, 0x084a }, /* 74 , 8, */ -{ 0x0401, 0x0a0c }, /* 12 , 10, */ -{ 0x0402, 0x0a4a }, /* 74 , 10, */ -{ 0x0403, 0x0a44 }, /* 68 , 10, */ -{ 0x0404, 0x0a4e }, /* 78 , 10, */ -{ 0x0405, 0x0a52 }, /* 82 , 10, */ -{ 0x0406, 0x0a58 }, /* 88 , 10, */ -{ 0x0407, 0x0a5a }, /* 90 , 10, */ -{ 0x0408, 0x0a5e }, /* 94 , 10, */ -{ 0x0409, 0x0a68 }, /* 104, 10, */ -{ 0x040A, 0x0a6c }, /* 108, 10, */ -{ 0x040B, 0x0a72 }, /* 114, 10, */ -{ 0x040C, 0x0a60 }, /* 96 , 10, */ -{ 0x040E, 0x0a74 }, /* 116, 10, */ -{ 0x040F, 0x0a86 }, /* 134, 10, */ -{ 0x0410, 0x0a00 }, /* 0 , 10, */ -{ 0x0411, 0x0a02 }, /* 2 , 10, */ -{ 0x0412, 0x0a04 }, /* 4 , 10, */ -{ 0x0413, 0x0a06 }, /* 6 , 10, */ -{ 0x0414, 0x0a08 }, /* 8 , 10, */ -{ 0x0415, 0x0a0a }, /* 10 , 10, */ -{ 0x0416, 0x0a0e }, /* 14 , 10, */ -{ 0x0417, 0x0a10 }, /* 16 , 10, */ -{ 0x0418, 0x0a12 }, /* 18 , 10, */ -{ 0x0419, 0x0a14 }, /* 20 , 10, */ -{ 0x041A, 0x0a16 }, /* 22 , 10, */ -{ 0x041B, 0x0a18 }, /* 24 , 10, */ -{ 0x041C, 0x0a1a }, /* 26 , 10, */ -{ 0x041D, 0x0a1c }, /* 28 , 10, */ -{ 0x041E, 0x0a1e }, /* 30 , 10, */ -{ 0x041F, 0x0a20 }, /* 32 , 10, */ -{ 0x0420, 0x0a22 }, /* 34 , 10, */ -{ 0x0421, 0x0a24 }, /* 36 , 10, */ -{ 0x0422, 0x0a26 }, /* 38 , 10, */ -{ 0x0423, 0x0a28 }, /* 40 , 10, */ -{ 0x0424, 0x0a2a }, /* 42 , 10, */ -{ 0x0425, 0x0a2c }, /* 44 , 10, */ -{ 0x0426, 0x0a2e }, /* 46 , 10, */ -{ 0x0427, 0x0a30 }, /* 48 , 10, */ -{ 0x0428, 0x0a32 }, /* 50 , 10, */ -{ 0x0429, 0x0a34 }, /* 52 , 10, */ -{ 0x042A, 0x0a36 }, /* 54 , 10, */ -{ 0x042B, 0x0a38 }, /* 56 , 10, */ -{ 0x042C, 0x0a3a }, /* 58 , 10, */ -{ 0x042D, 0x0a3c }, /* 60 , 10, */ -{ 0x042E, 0x0a3e }, /* 62 , 10, */ -{ 0x042F, 0x0a40 }, /* 64 , 10, */ -{ 0x0430, 0x0a01 }, /* 1 , 10, */ -{ 0x0431, 0x0a03 }, /* 3 , 10, */ -{ 0x0432, 0x0a05 }, /* 5 , 10, */ -{ 0x0433, 0x0a07 }, /* 7 , 10, */ -{ 0x0434, 0x0a09 }, /* 9 , 10, */ -{ 0x0435, 0x0a0b }, /* 11 , 10, */ -{ 0x0436, 0x0a0f }, /* 15 , 10, */ -{ 0x0437, 0x0a11 }, /* 17 , 10, */ -{ 0x0438, 0x0a13 }, /* 19 , 10, */ -{ 0x0439, 0x0a15 }, /* 21 , 10, */ -{ 0x043A, 0x0a17 }, /* 23 , 10, */ -{ 0x043B, 0x0a19 }, /* 25 , 10, */ -{ 0x043C, 0x0a1b }, /* 27 , 10, */ -{ 0x043D, 0x0a1d }, /* 29 , 10, */ -{ 0x043E, 0x0a1f }, /* 31 , 10, */ -{ 0x043F, 0x0a21 }, /* 33 , 10, */ -{ 0x0440, 0x0a23 }, /* 35 , 10, */ -{ 0x0441, 0x0a25 }, /* 37 , 10, */ -{ 0x0442, 0x0a27 }, /* 39 , 10, */ -{ 0x0443, 0x0a29 }, /* 41 , 10, */ -{ 0x0444, 0x0a2b }, /* 43 , 10, */ -{ 0x0445, 0x0a2d }, /* 45 , 10, */ -{ 0x0446, 0x0a2f }, /* 47 , 10, */ -{ 0x0447, 0x0a31 }, /* 49 , 10, */ -{ 0x0448, 0x0a33 }, /* 51 , 10, */ -{ 0x0449, 0x0a35 }, /* 53 , 10, */ -{ 0x044A, 0x0a37 }, /* 55 , 10, */ -{ 0x044B, 0x0a39 }, /* 57 , 10, */ -{ 0x044C, 0x0a3b }, /* 59 , 10, */ -{ 0x044D, 0x0a3d }, /* 61 , 10, */ -{ 0x044E, 0x0a3f }, /* 63 , 10, */ -{ 0x044F, 0x0a41 }, /* 65 , 10, */ -{ 0x0451, 0x0a0d }, /* 13 , 10, */ -{ 0x0452, 0x0a4b }, /* 75 , 10, */ -{ 0x0453, 0x0a45 }, /* 69 , 10, */ -{ 0x0454, 0x0a4f }, /* 79 , 10, */ -{ 0x0455, 0x0a53 }, /* 83 , 10, */ -{ 0x0456, 0x0a59 }, /* 89 , 10, */ -{ 0x0457, 0x0a5b }, /* 91 , 10, */ -{ 0x0458, 0x0a5f }, /* 95 , 10, */ -{ 0x0459, 0x0a69 }, /* 105, 10, */ -{ 0x045A, 0x0a6d }, /* 109, 10, */ -{ 0x045B, 0x0a73 }, /* 115, 10, */ -{ 0x045C, 0x0a61 }, /* 97 , 10, */ -{ 0x045E, 0x0a75 }, /* 117, 10, */ -{ 0x045F, 0x0a87 }, /* 135, 10, */ -{ 0x0460, 0x0a70 }, /* 112, 10, */ -{ 0x0461, 0x0a71 }, /* 113, 10, */ -{ 0x0462, 0x0a8e }, /* 142, 10, */ -{ 0x0463, 0x0a8f }, /* 143, 10, */ -{ 0x0466, 0x0a90 }, /* 144, 10, */ -{ 0x0467, 0x0a91 }, /* 145, 10, */ -{ 0x046A, 0x0a92 }, /* 146, 10, */ -{ 0x046B, 0x0a93 }, /* 147, 10, */ -{ 0x046E, 0x0a94 }, /* 148, 10, */ -{ 0x046F, 0x0a95 }, /* 149, 10, */ -{ 0x0470, 0x0a96 }, /* 150, 10, */ -{ 0x0471, 0x0a97 }, /* 151, 10, */ -{ 0x0472, 0x0a98 }, /* 152, 10, */ -{ 0x0473, 0x0a99 }, /* 153, 10, */ -{ 0x0474, 0x0a9a }, /* 154, 10, */ -{ 0x0475, 0x0a9b }, /* 155, 10, */ -{ 0x047A, 0x0a6e }, /* 110, 10, */ -{ 0x047B, 0x0a6f }, /* 111, 10, */ -{ 0x047E, 0x0a84 }, /* 132, 10, */ -{ 0x047F, 0x0a85 }, /* 133, 10, */ -{ 0x0490, 0x0a46 }, /* 70 , 10, */ -{ 0x0491, 0x0a47 }, /* 71 , 10, */ -{ 0x0492, 0x0a48 }, /* 72 , 10, */ -{ 0x0493, 0x0a49 }, /* 73 , 10, */ -{ 0x0496, 0x0a50 }, /* 80 , 10, */ -{ 0x0497, 0x0a51 }, /* 81 , 10, */ -{ 0x049A, 0x0a62 }, /* 98 , 10, */ -{ 0x049B, 0x0a63 }, /* 99 , 10, */ -{ 0x049C, 0x0a66 }, /* 102, 10, */ -{ 0x049D, 0x0a67 }, /* 103, 10, */ -{ 0x04A2, 0x0a6a }, /* 106, 10, */ -{ 0x04A3, 0x0a6b }, /* 107, 10, */ -{ 0x04AE, 0x0a78 }, /* 120, 10, */ -{ 0x04AF, 0x0a79 }, /* 121, 10, */ -{ 0x04B0, 0x0a7a }, /* 122, 10, */ -{ 0x04B1, 0x0a7b }, /* 123, 10, */ -{ 0x04B2, 0x0a7e }, /* 126, 10, */ -{ 0x04B3, 0x0a7f }, /* 127, 10, */ -{ 0x04B6, 0x0a88 }, /* 136, 10, */ -{ 0x04B7, 0x0a89 }, /* 137, 10, */ -{ 0x04B8, 0x0a8a }, /* 138, 10, */ -{ 0x04B9, 0x0a8b }, /* 139, 10, */ -{ 0x04BA, 0x0a82 }, /* 130, 10, */ -{ 0x04BB, 0x0a83 }, /* 131, 10, */ -{ 0x04D8, 0x0a42 }, /* 66 , 10, */ -{ 0x04D9, 0x0a43 }, /* 67 , 10, */ -{ 0x04EE, 0x0a76 }, /* 118, 10, */ -{ 0x04EF, 0x0a77 }, /* 119, 10, */ -{ 0x05B0, 0x0920 }, /* 32 , 9, */ -{ 0x05B1, 0x0921 }, /* 33 , 9, */ -{ 0x05B2, 0x0922 }, /* 34 , 9, */ -{ 0x05B3, 0x0923 }, /* 35 , 9, */ -{ 0x05B4, 0x0924 }, /* 36 , 9, */ -{ 0x05B5, 0x0925 }, /* 37 , 9, */ -{ 0x05B6, 0x0926 }, /* 38 , 9, */ -{ 0x05B7, 0x0927 }, /* 39 , 9, */ -{ 0x05B8, 0x0928 }, /* 40 , 9, */ -{ 0x05B9, 0x0929 }, /* 41 , 9, */ -{ 0x05BB, 0x092b }, /* 43 , 9, */ -{ 0x05BC, 0x092c }, /* 44 , 9, */ -{ 0x05BD, 0x092d }, /* 45 , 9, */ -{ 0x05BF, 0x092e }, /* 46 , 9, */ -{ 0x05C0, 0x091c }, /* 28 , 9, */ -{ 0x05C3, 0x091d }, /* 29 , 9, */ -{ 0x05D0, 0x0900 }, /* 0 , 9, */ -{ 0x05D1, 0x0901 }, /* 1 , 9, */ -{ 0x05D2, 0x0902 }, /* 2 , 9, */ -{ 0x05D3, 0x0903 }, /* 3 , 9, */ -{ 0x05D4, 0x0904 }, /* 4 , 9, */ -{ 0x05D5, 0x0905 }, /* 5 , 9, */ -{ 0x05D6, 0x0906 }, /* 6 , 9, */ -{ 0x05D7, 0x0907 }, /* 7 , 9, */ -{ 0x05D8, 0x0908 }, /* 8 , 9, */ -{ 0x05D9, 0x0909 }, /* 9 , 9, */ -{ 0x05DA, 0x090a }, /* 10 , 9, */ -{ 0x05DB, 0x090b }, /* 11 , 9, */ -{ 0x05DC, 0x090c }, /* 12 , 9, */ -{ 0x05DD, 0x090d }, /* 13 , 9, */ -{ 0x05DE, 0x090e }, /* 14 , 9, */ -{ 0x05DF, 0x090f }, /* 15 , 9, */ -{ 0x05E0, 0x0910 }, /* 16 , 9, */ -{ 0x05E1, 0x0911 }, /* 17 , 9, */ -{ 0x05E2, 0x0912 }, /* 18 , 9, */ -{ 0x05E3, 0x0913 }, /* 19 , 9, */ -{ 0x05E4, 0x0914 }, /* 20 , 9, */ -{ 0x05E5, 0x0915 }, /* 21 , 9, */ -{ 0x05E6, 0x0916 }, /* 22 , 9, */ -{ 0x05E7, 0x0917 }, /* 23 , 9, */ -{ 0x05E8, 0x0918 }, /* 24 , 9, */ -{ 0x05E9, 0x0919 }, /* 25 , 9, */ -{ 0x05EA, 0x091a }, /* 26 , 9, */ -{ 0x05F0, 0x0931 }, /* 49 , 9, */ -{ 0x05F1, 0x0932 }, /* 50 , 9, */ -{ 0x05F2, 0x0933 }, /* 51 , 9, */ -{ 0x05F3, 0x091e }, /* 30 , 9, */ -{ 0x05F4, 0x091f }, /* 31 , 9, */ -{ 0x060C, 0x0d26 }, /* 38 , 13, */ -{ 0x061B, 0x0d27 }, /* 39 , 13, */ -{ 0x061F, 0x0d28 }, /* 40 , 13, */ -{ 0x0621, 0x0da4 }, /* 164, 13, */ -{ 0x0622, 0x0db1 }, /* 177, 13, */ -{ 0x0623, 0x0da5 }, /* 165, 13, */ -{ 0x0624, 0x0da9 }, /* 169, 13, */ -{ 0x0625, 0x0da7 }, /* 167, 13, */ -{ 0x0626, 0x0dab }, /* 171, 13, */ -{ 0x0627, 0x0d3a }, /* 58 , 13, */ -{ 0x0628, 0x0d3c }, /* 60 , 13, */ -{ 0x0629, 0x0d98 }, /* 152, 13, */ -{ 0x062A, 0x0d40 }, /* 64 , 13, */ -{ 0x062B, 0x0d44 }, /* 68 , 13, */ -{ 0x062C, 0x0d48 }, /* 72 , 13, */ -{ 0x062D, 0x0d4c }, /* 76 , 13, */ -{ 0x062E, 0x0d50 }, /* 80 , 13, */ -{ 0x062F, 0x0d54 }, /* 84 , 13, */ -{ 0x0630, 0x0d56 }, /* 86 , 13, */ -{ 0x0631, 0x0d58 }, /* 88 , 13, */ -{ 0x0632, 0x0d5a }, /* 90 , 13, */ -{ 0x0633, 0x0d5c }, /* 92 , 13, */ -{ 0x0634, 0x0d60 }, /* 96 , 13, */ -{ 0x0635, 0x0d64 }, /* 100, 13, */ -{ 0x0636, 0x0d68 }, /* 104, 13, */ -{ 0x0637, 0x0d6c }, /* 108, 13, */ -{ 0x0638, 0x0d70 }, /* 112, 13, */ -{ 0x0639, 0x0d74 }, /* 116, 13, */ -{ 0x063A, 0x0d78 }, /* 120, 13, */ -{ 0x0640, 0x0dc2 }, /* 194, 13, */ -{ 0x0641, 0x0d7c }, /* 124, 13, */ -{ 0x0642, 0x0d80 }, /* 128, 13, */ -{ 0x0643, 0x0d84 }, /* 132, 13, */ -{ 0x0644, 0x0d88 }, /* 136, 13, */ -{ 0x0645, 0x0d8c }, /* 140, 13, */ -{ 0x0646, 0x0d90 }, /* 144, 13, */ -{ 0x0647, 0x0d94 }, /* 148, 13, */ -{ 0x0648, 0x0d9a }, /* 154, 13, */ -{ 0x0649, 0x0da0 }, /* 160, 13, */ -{ 0x064A, 0x0d9c }, /* 156, 13, */ -{ 0x064B, 0x0d10 }, /* 16 , 13, */ -{ 0x064C, 0x0d11 }, /* 17 , 13, */ -{ 0x064E, 0x0d0a }, /* 10 , 13, */ -{ 0x064F, 0x0d0c }, /* 12 , 13, */ -{ 0x0650, 0x0d0e }, /* 14 , 13, */ -{ 0x0651, 0x0d16 }, /* 22 , 13, */ -{ 0x0652, 0x0d14 }, /* 20 , 13, */ -{ 0x0660, 0x0d38 }, /* 56 , 13, */ -{ 0x0661, 0x0d2f }, /* 47 , 13, */ -{ 0x0662, 0x0d30 }, /* 48 , 13, */ -{ 0x0663, 0x0d31 }, /* 49 , 13, */ -{ 0x0664, 0x0d32 }, /* 50 , 13, */ -{ 0x0665, 0x0d33 }, /* 51 , 13, */ -{ 0x0666, 0x0d34 }, /* 52 , 13, */ -{ 0x0667, 0x0d35 }, /* 53 , 13, */ -{ 0x0668, 0x0d36 }, /* 54 , 13, */ -{ 0x0669, 0x0d37 }, /* 55 , 13, */ -{ 0x066A, 0x0d2a }, /* 42 , 13, */ -{ 0x0671, 0x0db3 }, /* 179, 13, */ -{ 0x0674, 0x0d24 }, /* 36 , 13, */ -{ 0x0679, 0x0e3c }, /* 60 , 14, */ -{ 0x067A, 0x0e4c }, /* 76 , 14, */ -{ 0x067B, 0x0e30 }, /* 48 , 14, */ -{ 0x067C, 0x0e40 }, /* 64 , 14, */ -{ 0x067D, 0x0e48 }, /* 72 , 14, */ -{ 0x067E, 0x0e38 }, /* 56 , 14, */ -{ 0x067F, 0x0e44 }, /* 68 , 14, */ -{ 0x0680, 0x0e34 }, /* 52 , 14, */ -{ 0x0681, 0x0e64 }, /* 100, 14, */ -{ 0x0683, 0x0e54 }, /* 84 , 14, */ -{ 0x0684, 0x0e50 }, /* 80 , 14, */ -{ 0x0685, 0x0e60 }, /* 96 , 14, */ -{ 0x0686, 0x0e58 }, /* 88 , 14, */ -{ 0x0687, 0x0e5c }, /* 92 , 14, */ -{ 0x0688, 0x0e68 }, /* 104, 14, */ -{ 0x0689, 0x0e6a }, /* 106, 14, */ -{ 0x068A, 0x0e70 }, /* 112, 14, */ -{ 0x068C, 0x0e6c }, /* 108, 14, */ -{ 0x068D, 0x0e72 }, /* 114, 14, */ -{ 0x068E, 0x0e6e }, /* 110, 14, */ -{ 0x0691, 0x0e76 }, /* 118, 14, */ -{ 0x0692, 0x0e7C }, /* 124, 14, */ -{ 0x0693, 0x0e74 }, /* 116, 14, */ -{ 0x0695, 0x0e7a }, /* 122, 14, */ -{ 0x0696, 0x0e80 }, /* 128, 14, */ -{ 0x0698, 0x0e7e }, /* 126, 14, */ -{ 0x0699, 0x0e78 }, /* 120, 14, */ -{ 0x069A, 0x0e84 }, /* 132, 14, */ -{ 0x06A0, 0x0e88 }, /* 136, 14, */ -{ 0x06A4, 0x0e8c }, /* 140, 14, */ -{ 0x06A6, 0x0e90 }, /* 144, 14, */ -{ 0x06A9, 0x0e94 }, /* 148, 14, */ -{ 0x06AA, 0x0e9c }, /* 156, 14, */ -{ 0x06AB, 0x0ea8 }, /* 168, 14, */ -{ 0x06AF, 0x0ea0 }, /* 160, 14, */ -{ 0x06B1, 0x0eac }, /* 172, 14, */ -{ 0x06B3, 0x0eb0 }, /* 176, 14, */ -{ 0x06B5, 0x0eb4 }, /* 180, 14, */ -{ 0x06BA, 0x0eba }, /* 186, 14, */ -{ 0x06BB, 0x0ec2 }, /* 194, 14, */ -{ 0x06BC, 0x0ebe }, /* 190, 14, */ -{ 0x06C0, 0x0eda }, /* 218, 14, */ -{ 0x06C6, 0x0ec6 }, /* 198, 14, */ -{ 0x06CA, 0x0ec8 }, /* 200, 14, */ -{ 0x06CE, 0x0ed0 }, /* 208, 14, */ -{ 0x06D1, 0x0ed6 }, /* 214, 14, */ -{ 0x06D2, 0x0ed4 }, /* 212, 14, */ -{ 0x06D6, 0x0d25 }, /* 37 , 13, */ -{ 0x06E4, 0x0d22 }, /* 34 , 13, */ -{ 0x06F4, 0x0e29 }, /* 41 , 14, */ -{ 0x06F5, 0x0e2b }, /* 43 , 14, */ -{ 0x06F6, 0x0e2c }, /* 44 , 14, */ -{ 0x06F7, 0x0e2e }, /* 46 , 14, */ -{ 0x06F8, 0x0e2f }, /* 47 , 14, */ -{ 0x10D0, 0x0ad2 }, /* 210, 10, */ -{ 0x10D1, 0x0ad3 }, /* 211, 10, */ -{ 0x10D2, 0x0ad4 }, /* 212, 10, */ -{ 0x10D3, 0x0ad5 }, /* 213, 10, */ -{ 0x10D4, 0x0ad6 }, /* 214, 10, */ -{ 0x10D5, 0x0ad7 }, /* 215, 10, */ -{ 0x10D6, 0x0ad8 }, /* 216, 10, */ -{ 0x10D7, 0x0ada }, /* 218, 10, */ -{ 0x10D8, 0x0adb }, /* 219, 10, */ -{ 0x10D9, 0x0adc }, /* 220, 10, */ -{ 0x10DA, 0x0add }, /* 221, 10, */ -{ 0x10DB, 0x0ade }, /* 222, 10, */ -{ 0x10DC, 0x0adf }, /* 223, 10, */ -{ 0x10DD, 0x0ae1 }, /* 225, 10, */ -{ 0x10DE, 0x0ae2 }, /* 226, 10, */ -{ 0x10DF, 0x0ae3 }, /* 227, 10, */ -{ 0x10E0, 0x0ae4 }, /* 228, 10, */ -{ 0x10E1, 0x0ae5 }, /* 229, 10, */ -{ 0x10E2, 0x0ae6 }, /* 230, 10, */ -{ 0x10E3, 0x0ae7 }, /* 231, 10, */ -{ 0x10E4, 0x0ae9 }, /* 233, 10, */ -{ 0x10E5, 0x0aea }, /* 234, 10, */ -{ 0x10E6, 0x0aeb }, /* 235, 10, */ -{ 0x10E7, 0x0aec }, /* 236, 10, */ -{ 0x10E8, 0x0aed }, /* 237, 10, */ -{ 0x10E9, 0x0aee }, /* 238, 10, */ -{ 0x10EA, 0x0aef }, /* 239, 10, */ -{ 0x10EB, 0x0af0 }, /* 240, 10, */ -{ 0x10EC, 0x0af1 }, /* 241, 10, */ -{ 0x10ED, 0x0af2 }, /* 242, 10, */ -{ 0x10EE, 0x0af3 }, /* 243, 10, */ -{ 0x10EF, 0x0af5 }, /* 245, 10, */ -{ 0x10F0, 0x0af6 }, /* 246, 10, */ -{ 0x10F1, 0x0ad9 }, /* 217, 10, */ -{ 0x10F2, 0x0ae0 }, /* 224, 10, */ -{ 0x10F3, 0x0ae8 }, /* 232, 10, */ -{ 0x10F4, 0x0af4 }, /* 244, 10, */ -{ 0x10F5, 0x0af7 }, /* 247, 10, */ -{ 0x10F6, 0x0af8 }, /* 248, 10, */ -{ 0x1F00, 0x0873 }, /* 115, 8, */ -{ 0x1F01, 0x087b }, /* 123, 8, */ -{ 0x1F02, 0x0875 }, /* 117, 8, */ -{ 0x1F03, 0x087d }, /* 125, 8, */ -{ 0x1F04, 0x0874 }, /* 116, 8, */ -{ 0x1F05, 0x087c }, /* 124, 8, */ -{ 0x1F10, 0x0884 }, /* 132, 8, */ -{ 0x1F11, 0x0887 }, /* 135, 8, */ -{ 0x1F12, 0x0886 }, /* 134, 8, */ -{ 0x1F13, 0x0889 }, /* 137, 8, */ -{ 0x1F14, 0x0885 }, /* 133, 8, */ -{ 0x1F15, 0x0888 }, /* 136, 8, */ -{ 0x1F20, 0x0890 }, /* 144, 8, */ -{ 0x1F21, 0x0898 }, /* 152, 8, */ -{ 0x1F22, 0x0892 }, /* 146, 8, */ -{ 0x1F23, 0x089a }, /* 154, 8, */ -{ 0x1F24, 0x0891 }, /* 145, 8, */ -{ 0x1F25, 0x0899 }, /* 153, 8, */ -{ 0x1F30, 0x08a4 }, /* 164, 8, */ -{ 0x1F31, 0x08a8 }, /* 168, 8, */ -{ 0x1F32, 0x08a6 }, /* 166, 8, */ -{ 0x1F33, 0x08aa }, /* 170, 8, */ -{ 0x1F34, 0x08a5 }, /* 165, 8, */ -{ 0x1F35, 0x08a9 }, /* 169, 8, */ -{ 0x1F40, 0x08ad }, /* 173, 8, */ -{ 0x1F41, 0x08b0 }, /* 176, 8, */ -{ 0x1F42, 0x08af }, /* 175, 8, */ -{ 0x1F43, 0x08b2 }, /* 178, 8, */ -{ 0x1F44, 0x08ae }, /* 174, 8, */ -{ 0x1F45, 0x08b1 }, /* 177, 8, */ -{ 0x1F50, 0x08b9 }, /* 185, 8, */ -{ 0x1F51, 0x08bd }, /* 189, 8, */ -{ 0x1F52, 0x08bb }, /* 187, 8, */ -{ 0x1F53, 0x08bf }, /* 191, 8, */ -{ 0x1F54, 0x08ba }, /* 186, 8, */ -{ 0x1F55, 0x08be }, /* 190, 8, */ -{ 0x1F60, 0x08c7 }, /* 199, 8, */ -{ 0x1F61, 0x08cf }, /* 207, 8, */ -{ 0x1F62, 0x08c9 }, /* 201, 8, */ -{ 0x1F63, 0x08d1 }, /* 209, 8, */ -{ 0x1F64, 0x08c8 }, /* 200, 8, */ -{ 0x1F65, 0x08d0 }, /* 208, 8, */ -{ 0x1F70, 0x086d }, /* 109, 8, */ -{ 0x1F72, 0x0883 }, /* 131, 8, */ -{ 0x1F74, 0x088a }, /* 138, 8, */ -{ 0x1F76, 0x08a0 }, /* 160, 8, */ -{ 0x1F78, 0x08ac }, /* 172, 8, */ -{ 0x1F7A, 0x08b5 }, /* 181, 8, */ -{ 0x1F7C, 0x08c1 }, /* 193, 8, */ -{ 0x1F80, 0x0877 }, /* 119, 8, */ -{ 0x1F81, 0x087f }, /* 127, 8, */ -{ 0x1F82, 0x0879 }, /* 121, 8, */ -{ 0x1F83, 0x0881 }, /* 129, 8, */ -{ 0x1F84, 0x0878 }, /* 120, 8, */ -{ 0x1F85, 0x0880 }, /* 128, 8, */ -{ 0x1F90, 0x0894 }, /* 148, 8, */ -{ 0x1F91, 0x089c }, /* 156, 8, */ -{ 0x1F92, 0x0896 }, /* 150, 8, */ -{ 0x1F93, 0x089e }, /* 158, 8, */ -{ 0x1F94, 0x0895 }, /* 149, 8, */ -{ 0x1F95, 0x089d }, /* 157, 8, */ -{ 0x1FA0, 0x08cb }, /* 203, 8, */ -{ 0x1FA1, 0x08d3 }, /* 211, 8, */ -{ 0x1FA2, 0x08cd }, /* 205, 8, */ -{ 0x1FA3, 0x08d5 }, /* 213, 8, */ -{ 0x1FA4, 0x08cc }, /* 204, 8, */ -{ 0x1FA5, 0x08d4 }, /* 212, 8, */ -{ 0x1FB2, 0x0871 }, /* 113, 8, */ -{ 0x1FB3, 0x086f }, /* 111, 8, */ -{ 0x1FB4, 0x0870 }, /* 112, 8, */ -{ 0x1FC2, 0x088e }, /* 142, 8, */ -{ 0x1FC3, 0x088c }, /* 140, 8, */ -{ 0x1FC4, 0x088d }, /* 141, 8, */ -{ 0x1FCD, 0x085e }, /* 94 , 8, */ -{ 0x1FCE, 0x085c }, /* 92 , 8, */ -{ 0x1FDD, 0x085f }, /* 95 , 8, */ -{ 0x1FDE, 0x085d }, /* 93 , 8, */ -{ 0x1FE4, 0x08B4 }, /* 180, 8, */ -{ 0x1FE5, 0x08B3 }, /* 179, 8, */ -{ 0x1FF2, 0x08c5 }, /* 197, 8, */ -{ 0x1FF3, 0x08c3 }, /* 195, 8, */ -{ 0x1FF4, 0x08c4 }, /* 196, 8, */ -{ 0x2007, 0x0517 }, /* 23 , 5, */ -{ 0x2012, 0x0432 }, /* 50 , 4, */ -{ 0x2013, 0x0421 }, /* 33 , 4, */ -{ 0x2014, 0x0422 }, /* 34 , 4, */ -{ 0x2017, 0x022f }, /* 47 , 2, */ -{ 0x2018, 0x041d }, /* 29 , 4, */ -{ 0x2019, 0x041c }, /* 28 , 4, */ -{ 0x201A, 0x043e }, /* 62 , 4, */ -{ 0x201B, 0x041b }, /* 27 , 4, */ -{ 0x201C, 0x0420 }, /* 32 , 4, */ -{ 0x201D, 0x041f }, /* 31 , 4, */ -{ 0x201E, 0x043f }, /* 63 , 4, */ -{ 0x201F, 0x041e }, /* 30 , 4, */ -{ 0x2020, 0x0427 }, /* 39 , 4, */ -{ 0x2021, 0x0428 }, /* 40 , 4, */ -{ 0x2022, 0x0403 }, /* 3 , 4, */ -{ 0x2026, 0x0438 }, /* 56 , 4, */ -{ 0x2030, 0x044b }, /* 75 , 4, */ -{ 0x2033, 0x0580 }, /* 128, 5, */ -{ 0x2034, 0x0671 }, /* 113, 6, */ -{ 0x2036, 0x057f }, /* 127, 5, */ -{ 0x2039, 0x0423 }, /* 35 , 4, */ -{ 0x203A, 0x0424 }, /* 36 , 4, */ -{ 0x203C, 0x050d }, /* 13 , 5, */ -{ 0x203E, 0x0626 }, /* 38 , 6, */ -{ 0x207F, 0x0415 }, /* 21 , 4, */ -{ 0x20A0, 0x043c }, /* 60 , 4, */ -{ 0x20A2, 0x043b }, /* 59 , 4, */ -{ 0x20A3, 0x043a }, /* 58 , 4, */ -{ 0x20A4, 0x043d }, /* 61 , 4, */ -{ 0x20A6, 0x0457 }, /* 87 , 4, */ -{ 0x20A7, 0x040d }, /* 13 , 4, */ -{ 0x20A8, 0x0458 }, /* 88 , 4, */ -{ 0x20A9, 0x0456 }, /* 86 , 4, */ -{ 0x20AA, 0x097A }, /* 122, 9, */ -{ 0x20AC, 0x0466 }, /* 102, 4, Euro Sign - GW assigned x448 [4,72] */ -{ 0x20DD, 0x066d }, /* 109, 6, */ -{ 0x20E1, 0x06e1 }, /* 225, 6, */ -{ 0x2102, 0x06d5 }, /* 213, 6, */ -{ 0x2104, 0x0515 }, /* 21 , 5, */ -{ 0x2105, 0x0449 }, /* 73 , 4, */ -{ 0x2106, 0x044a }, /* 74 , 4, */ -{ 0x210C, 0x06e9 }, /* 233, 6, */ -{ 0x210F, 0x0632 }, /* 50 , 6, */ -{ 0x2111, 0x0633 }, /* 51 , 6, */ -{ 0x2112, 0x0669 }, /* 105, 6, */ -{ 0x2113, 0x0631 }, /* 49 , 6, */ -{ 0x2115, 0x06d7 }, /* 215, 6, */ -{ 0x2116, 0x044c }, /* 76 , 4, */ -{ 0x2118, 0x0635 }, /* 53 , 6, */ -{ 0x211C, 0x0634 }, /* 52 , 6, */ -{ 0x211D, 0x06d8 }, /* 216, 6, */ -{ 0x211E, 0x042b }, /* 43 , 4, */ -{ 0x2120, 0x042a }, /* 42 , 4, */ -{ 0x2122, 0x0429 }, /* 41 , 4, */ -{ 0x2127, 0x06a7 }, /* 167, 6, */ -{ 0x2128, 0x066b }, /* 107, 6, */ -{ 0x212B, 0x0623 }, /* 35 , 6, */ -{ 0x212D, 0x066a }, /* 106, 6, */ -{ 0x212F, 0x0630 }, /* 48 , 6, */ -{ 0x2130, 0x06d3 }, /* 211, 6, */ -{ 0x2131, 0x06d4 }, /* 212, 6, */ -{ 0x2153, 0x0440 }, /* 64 , 4, */ -{ 0x2154, 0x0441 }, /* 65 , 4, */ -{ 0x215B, 0x0442 }, /* 66 , 4, */ -{ 0x215C, 0x0443 }, /* 67 , 4, */ -{ 0x215D, 0x0444 }, /* 68 , 4, */ -{ 0x215E, 0x0445 }, /* 69 , 4, */ -{ 0x2190, 0x0590 }, /* 144, 5, */ -{ 0x2191, 0x0617 }, /* 23 , 6, */ -{ 0x2192, 0x05d5 }, /* 213, 5, */ -{ 0x2193, 0x0618 }, /* 24 , 6, */ -{ 0x2194, 0x05d6 }, /* 214, 5, */ -{ 0x2195, 0x05d7 }, /* 215, 5, */ -{ 0x2196, 0x0640 }, /* 64 , 6, */ -{ 0x2197, 0x063e }, /* 62 , 6, */ -{ 0x2198, 0x063f }, /* 63 , 6, */ -{ 0x2199, 0x0641 }, /* 65 , 6, */ -{ 0x219D, 0x0690 }, /* 144, 6, */ -{ 0x21A3, 0x0693 }, /* 147, 6, */ -{ 0x21A8, 0x050f }, /* 15 , 5, */ -{ 0x21A9, 0x0691 }, /* 145, 6, */ -{ 0x21AA, 0x0692 }, /* 146, 6, */ -{ 0x21B5, 0x0514 }, /* 20 , 5, */ -{ 0x21BC, 0x0694 }, /* 148, 6, */ -{ 0x21BD, 0x0695 }, /* 149, 6, */ -{ 0x21BE, 0x069b }, /* 155, 6, */ -{ 0x21BF, 0x069a }, /* 154, 6, */ -{ 0x21C0, 0x0696 }, /* 150, 6, */ -{ 0x21C1, 0x0697 }, /* 151, 6, */ -{ 0x21C2, 0x069d }, /* 157, 6, */ -{ 0x21C3, 0x069c }, /* 156, 6, */ -{ 0x21C4, 0x0636 }, /* 54 , 6, */ -{ 0x21C6, 0x0637 }, /* 55 , 6, */ -{ 0x21C7, 0x069f }, /* 159, 6, */ -{ 0x21C9, 0x069e }, /* 158, 6, */ -{ 0x21CB, 0x0699 }, /* 153, 6, */ -{ 0x21CC, 0x0698 }, /* 152, 6, */ -{ 0x21D0, 0x0639 }, /* 57 , 6, */ -{ 0x21D1, 0x063a }, /* 58 , 6, */ -{ 0x21D2, 0x0638 }, /* 56 , 6, */ -{ 0x21D3, 0x063b }, /* 59 , 6, */ -{ 0x21D4, 0x063c }, /* 60 , 6, */ -{ 0x21D5, 0x063d }, /* 61 , 6, */ -{ 0x21E6, 0x0597 }, /* 151, 5, */ -{ 0x21E8, 0x0596 }, /* 150, 5, */ -{ 0x2200, 0x067a }, /* 122, 6, */ -{ 0x2202, 0x062c }, /* 44 , 6, */ -{ 0x2203, 0x0679 }, /* 121, 6, */ -{ 0x2204, 0x06d0 }, /* 208, 6, */ -{ 0x2205, 0x0648 }, /* 72 , 6, */ -{ 0x2207, 0x062b }, /* 43 , 6, */ -{ 0x2208, 0x060f }, /* 15 , 6, */ -{ 0x2209, 0x06d1 }, /* 209, 6, */ -{ 0x220B, 0x06db }, /* 219, 6, */ -{ 0x220D, 0x0647 }, /* 71 , 6, */ -{ 0x220F, 0x0629 }, /* 41 , 6, */ -{ 0x2210, 0x0672 }, /* 114, 6, */ -{ 0x2211, 0x0612 }, /* 18 , 6, */ -{ 0x2212, 0x0600 }, /* 0 , 6, */ -{ 0x2213, 0x062a }, /* 42 , 6, */ -{ 0x2214, 0x06ae }, /* 174, 6, */ -{ 0x2215, 0x0606 }, /* 6 , 6, */ -{ 0x2216, 0x0607 }, /* 7 , 6, */ -{ 0x2218, 0x0621 }, /* 33 , 6, */ -{ 0x2219, 0x0622 }, /* 34 , 6, */ -{ 0x221A, 0x0704 }, /* 4 , 7, */ -{ 0x221D, 0x0604 }, /* 4 , 6, */ -{ 0x221E, 0x0613 }, /* 19 , 6, */ -{ 0x221F, 0x06da }, /* 218, 6, */ -{ 0x2220, 0x064f }, /* 79 , 6, */ -{ 0x2221, 0x06a8 }, /* 168, 6, */ -{ 0x2222, 0x06a9 }, /* 169, 6, */ -{ 0x2223, 0x0609 }, /* 9 , 6, */ -{ 0x2224, 0x06ce }, /* 206, 6, */ -{ 0x2225, 0x0611 }, /* 17 , 6, */ -{ 0x2226, 0x06cd }, /* 205, 6, */ -{ 0x2227, 0x0655 }, /* 85 , 6, */ -{ 0x2228, 0x0656 }, /* 86 , 6, */ -{ 0x2229, 0x0610 }, /* 16 , 6, */ -{ 0x222A, 0x0642 }, /* 66 , 6, */ -{ 0x222B, 0x0628 }, /* 40 , 6, */ -{ 0x222E, 0x0668 }, /* 104, 6, */ -{ 0x2234, 0x0666 }, /* 102, 6, */ -{ 0x2235, 0x0665 }, /* 101, 6, */ -{ 0x2237, 0x0667 }, /* 103, 6, */ -{ 0x223C, 0x060c }, /* 12 , 6, */ -{ 0x2241, 0x06bd }, /* 189, 6, */ -{ 0x2243, 0x0673 }, /* 115, 6, */ -{ 0x2244, 0x06be }, /* 190, 6, */ -{ 0x2245, 0x0674 }, /* 116, 6, */ -{ 0x2247, 0x06bf }, /* 191, 6, */ -{ 0x2248, 0x060d }, /* 13 , 6, */ -{ 0x2249, 0x06c0 }, /* 192, 6, */ -{ 0x224D, 0x06b3 }, /* 179, 6, */ -{ 0x224E, 0x06b2 }, /* 178, 6, */ -{ 0x2250, 0x06af }, /* 175, 6, */ -{ 0x2252, 0x06b0 }, /* 176, 6, */ -{ 0x2253, 0x06b1 }, /* 177, 6, */ -{ 0x225F, 0x06d9 }, /* 217, 6, */ -{ 0x2260, 0x0663 }, /* 99 , 6, */ -{ 0x2261, 0x060e }, /* 14 , 6, */ -{ 0x2262, 0x0664 }, /* 100, 6, */ -{ 0x2264, 0x0602 }, /* 2 , 6, */ -{ 0x2265, 0x0603 }, /* 3 , 6, */ -{ 0x226A, 0x064d }, /* 77 , 6, */ -{ 0x226B, 0x064e }, /* 78 , 6, */ -{ 0x226C, 0x06b6 }, /* 182, 6, */ -{ 0x226D, 0x06cf }, /* 207, 6, */ -{ 0x226E, 0x06b9 }, /* 185, 6, */ -{ 0x226F, 0x06bb }, /* 187, 6, */ -{ 0x2270, 0x06ba }, /* 186, 6, */ -{ 0x2271, 0x06bc }, /* 188, 6, */ -{ 0x2272, 0x06eb }, /* 235, 6, */ -{ 0x2273, 0x06ec }, /* 236, 6, */ -{ 0x227A, 0x0675 }, /* 117, 6, */ -{ 0x227B, 0x0677 }, /* 119, 6, */ -{ 0x227C, 0x0676 }, /* 118, 6, */ -{ 0x227D, 0x0678 }, /* 120, 6, */ -{ 0x2280, 0x06c1 }, /* 193, 6, */ -{ 0x2281, 0x06c3 }, /* 195, 6, */ -{ 0x2282, 0x0643 }, /* 67 , 6, */ -{ 0x2283, 0x0644 }, /* 68 , 6, */ -{ 0x2284, 0x06c5 }, /* 197, 6, */ -{ 0x2285, 0x06c6 }, /* 198, 6, */ -{ 0x2286, 0x0645 }, /* 69 , 6, */ -{ 0x2287, 0x0646 }, /* 70 , 6, */ -{ 0x2288, 0x06c7 }, /* 199, 6, */ -{ 0x2289, 0x06c8 }, /* 200, 6, */ -{ 0x228A, 0x067e }, /* 126, 6, */ -{ 0x228B, 0x067f }, /* 127, 6, */ -{ 0x228E, 0x067d }, /* 125, 6, */ -{ 0x228F, 0x0682 }, /* 130, 6, */ -{ 0x2290, 0x0685 }, /* 133, 6, */ -{ 0x2291, 0x0683 }, /* 131, 6, */ -{ 0x2292, 0x0686 }, /* 134, 6, */ -{ 0x2293, 0x0680 }, /* 128, 6, */ -{ 0x2294, 0x0681 }, /* 129, 6, */ -{ 0x2295, 0x0651 }, /* 81 , 6, */ -{ 0x2296, 0x0652 }, /* 82 , 6, */ -{ 0x2297, 0x0650 }, /* 80 , 6, */ -{ 0x2299, 0x0654 }, /* 84 , 6, */ -{ 0x229A, 0x06a4 }, /* 164, 6, */ -{ 0x229B, 0x06a5 }, /* 165, 6, */ -{ 0x229D, 0x06a6 }, /* 166, 6, */ -{ 0x22A2, 0x065b }, /* 91 , 6, */ -{ 0x22A3, 0x065c }, /* 92 , 6, */ -{ 0x22A4, 0x0658 }, /* 88 , 6, */ -{ 0x22A5, 0x0659 }, /* 89 , 6, */ -{ 0x22A8, 0x06b4 }, /* 180, 6, */ -{ 0x22BB, 0x0657 }, /* 87 , 6, */ -{ 0x22C5, 0x061f }, /* 31 , 6, */ -{ 0x22C6, 0x0670 }, /* 112, 6, */ -{ 0x22C8, 0x068c }, /* 140, 6, */ -{ 0x22D0, 0x06a2 }, /* 162, 6, */ -{ 0x22D1, 0x06a3 }, /* 163, 6, */ -{ 0x22D2, 0x06a1 }, /* 161, 6, */ -{ 0x22D3, 0x06a0 }, /* 160, 6, */ -{ 0x22D8, 0x067b }, /* 123, 6, */ -{ 0x22D9, 0x067c }, /* 124, 6, */ -{ 0x22E0, 0x06c2 }, /* 194, 6, */ -{ 0x22E1, 0x06c4 }, /* 196, 6, */ -{ 0x22E2, 0x06cb }, /* 203, 6, */ -{ 0x22E3, 0x06cc }, /* 204, 6, */ -{ 0x22E4, 0x0684 }, /* 132, 6, */ -{ 0x22E5, 0x0687 }, /* 135, 6, */ -{ 0x22EE, 0x06de }, /* 222, 6, */ -{ 0x22EF, 0x06dc }, /* 220, 6, */ -{ 0x22F1, 0x06df }, /* 223, 6, */ -{ 0x2302, 0x050c }, /* 12 , 5, */ -{ 0x2308, 0x0649 }, /* 73 , 6, */ -{ 0x2309, 0x064a }, /* 74 , 6, */ -{ 0x230A, 0x064b }, /* 75 , 6, */ -{ 0x230B, 0x064c }, /* 76 , 6, */ -{ 0x2310, 0x0510 }, /* 16 , 5, */ -{ 0x2312, 0x065a }, /* 90 , 6, */ -{ 0x2319, 0x0511 }, /* 17 , 5, */ -{ 0x231A, 0x051f }, /* 31 , 5, */ -{ 0x231B, 0x0520 }, /* 32 , 5, */ -{ 0x2320, 0x0700 }, /* 0 , 7, */ -{ 0x2321, 0x0701 }, /* 1 , 7, */ -{ 0x2322, 0x068e }, /* 142, 6, */ -{ 0x2323, 0x068d }, /* 141, 6, */ -{ 0x2329, 0x060a }, /* 10 , 6, */ -{ 0x232A, 0x060b }, /* 11 , 6, */ -{ 0x2409, 0x044f }, /* 79 , 4, */ -{ 0x240A, 0x0452 }, /* 82 , 4, */ -{ 0x240B, 0x0454 }, /* 84 , 4, */ -{ 0x240C, 0x0450 }, /* 80 , 4, */ -{ 0x240D, 0x0451 }, /* 81 , 4, */ -{ 0x2424, 0x0453 }, /* 83 , 4, */ -{ 0x24C2, 0x0446 }, /* 70 , 4, */ -{ 0x24C5, 0x0447 }, /* 71 , 4, */ -{ 0x24CA, 0x0448 }, /* 72 , 4, - circled U */ -{ 0x2500, 0x0308 }, /* 8 , 3, */ -{ 0x2502, 0x0309 }, /* 9 , 3, */ -{ 0x250C, 0x030a }, /* 10 , 3, */ -{ 0x2510, 0x030b }, /* 11 , 3, */ -{ 0x2514, 0x030d }, /* 13 , 3, */ -{ 0x2518, 0x030c }, /* 12 , 3, */ -{ 0x251C, 0x030e }, /* 14 , 3, */ -{ 0x251E, 0x033e }, /* 62 , 3, */ -{ 0x251F, 0x033c }, /* 60 , 3, */ -{ 0x2521, 0x033f }, /* 63 , 3, */ -{ 0x2522, 0x033d }, /* 61 , 3, */ -{ 0x2524, 0x0310 }, /* 16 , 3, */ -{ 0x2526, 0x0345 }, /* 69 , 3, */ -{ 0x2527, 0x0344 }, /* 68 , 3, */ -{ 0x2529, 0x0347 }, /* 71 , 3, */ -{ 0x252A, 0x0346 }, /* 70 , 3, */ -{ 0x252C, 0x030f }, /* 15 , 3, */ -{ 0x252D, 0x0342 }, /* 66 , 3, */ -{ 0x252E, 0x0340 }, /* 64 , 3, */ -{ 0x2531, 0x0343 }, /* 67 , 3, */ -{ 0x2532, 0x0341 }, /* 65 , 3, */ -{ 0x2534, 0x0311 }, /* 17 , 3, */ -{ 0x2535, 0x034a }, /* 74 , 3, */ -{ 0x2536, 0x0348 }, /* 72 , 3, */ -{ 0x2539, 0x034b }, /* 75 , 3, */ -{ 0x253A, 0x0349 }, /* 73 , 3, */ -{ 0x253C, 0x0312 }, /* 18 , 3, */ -{ 0x253D, 0x0352 }, /* 82 , 3, */ -{ 0x253E, 0x034e }, /* 78 , 3, */ -{ 0x2540, 0x034f }, /* 79 , 3, */ -{ 0x2541, 0x034c }, /* 76 , 3, */ -{ 0x2543, 0x0355 }, /* 85 , 3, */ -{ 0x2544, 0x0350 }, /* 80 , 3, */ -{ 0x2545, 0x0353 }, /* 83 , 3, */ -{ 0x2546, 0x034d }, /* 77 , 3, */ -{ 0x2547, 0x0357 }, /* 87 , 3, */ -{ 0x2548, 0x0354 }, /* 84 , 3, */ -{ 0x2549, 0x0356 }, /* 86 , 3, */ -{ 0x254A, 0x0351 }, /* 81 , 3, */ -{ 0x2550, 0x0313 }, /* 19 , 3, */ -{ 0x2551, 0x0314 }, /* 20 , 3, */ -{ 0x2552, 0x031e }, /* 30 , 3, */ -{ 0x2553, 0x0322 }, /* 34 , 3, */ -{ 0x2554, 0x0315 }, /* 21 , 3, */ -{ 0x2555, 0x031f }, /* 31 , 3, */ -{ 0x2556, 0x0323 }, /* 35 , 3, */ -{ 0x2557, 0x0316 }, /* 22 , 3, */ -{ 0x2558, 0x0321 }, /* 33 , 3, */ -{ 0x2559, 0x0325 }, /* 37 , 3, */ -{ 0x255A, 0x0318 }, /* 24 , 3, */ -{ 0x255B, 0x0320 }, /* 32 , 3, */ -{ 0x255C, 0x0324 }, /* 36 , 3, */ -{ 0x255D, 0x0317 }, /* 23 , 3, */ -{ 0x255E, 0x0326 }, /* 38 , 3, */ -{ 0x255F, 0x032a }, /* 42 , 3, */ -{ 0x2560, 0x0319 }, /* 25 , 3, */ -{ 0x2561, 0x0328 }, /* 40 , 3, */ -{ 0x2562, 0x032c }, /* 44 , 3, */ -{ 0x2563, 0x031b }, /* 27 , 3, */ -{ 0x2564, 0x032b }, /* 43 , 3, */ -{ 0x2565, 0x0327 }, /* 39 , 3, */ -{ 0x2566, 0x031a }, /* 26 , 3, */ -{ 0x2567, 0x032d }, /* 45 , 3, */ -{ 0x2568, 0x0329 }, /* 41 , 3, */ -{ 0x2569, 0x031c }, /* 28 , 3, */ -{ 0x256A, 0x032f }, /* 47 , 3, */ -{ 0x256B, 0x032e }, /* 46 , 3, */ -{ 0x256C, 0x031d }, /* 29 , 3, */ -{ 0x2574, 0x0330 }, /* 48 , 3, */ -{ 0x2575, 0x0331 }, /* 49 , 3, */ -{ 0x2576, 0x0332 }, /* 50 , 3, */ -{ 0x2577, 0x0333 }, /* 51 , 3, */ -{ 0x2578, 0x0334 }, /* 52 , 3, */ -{ 0x2579, 0x0335 }, /* 53 , 3, */ -{ 0x257A, 0x0336 }, /* 54 , 3, */ -{ 0x257B, 0x0337 }, /* 55 , 3, */ -{ 0x257C, 0x0338 }, /* 56 , 3, */ -{ 0x257D, 0x033a }, /* 58 , 3, */ -{ 0x257E, 0x0339 }, /* 57 , 3, */ -{ 0x257F, 0x033b }, /* 59 , 3, */ -{ 0x2580, 0x0305 }, /* 5 , 3, */ -{ 0x2584, 0x0307 }, /* 7 , 3, */ -{ 0x2588, 0x0303 }, /* 3 , 3, */ -{ 0x258C, 0x0304 }, /* 4 , 3, */ -{ 0x2590, 0x0306 }, /* 6 , 3, */ -{ 0x2591, 0x0300 }, /* 0 , 3, */ -{ 0x2592, 0x0301 }, /* 1 , 3, */ -{ 0x2593, 0x0302 }, /* 2 , 3, */ -{ 0x25A0, 0x0402 }, /* 2 , 4, */ -{ 0x25A1, 0x0426 }, /* 38 , 4, */ -{ 0x25AA, 0x042f }, /* 47 , 4, */ -{ 0x25AB, 0x0431 }, /* 49 , 4, */ -{ 0x25AC, 0x050b }, /* 11 , 5, */ -{ 0x25B2, 0x0573 }, /* 115, 5, */ -{ 0x25B3, 0x0688 }, /* 136, 6, */ -{ 0x25B4, 0x061d }, /* 29 , 6, */ -{ 0x25B5, 0x06ac }, /* 172, 6, */ -{ 0x25B8, 0x061b }, /* 27 , 6, */ -{ 0x25B9, 0x068b }, /* 139, 6, */ -{ 0x25BC, 0x0574 }, /* 116, 5, */ -{ 0x25BD, 0x0689 }, /* 137, 6, */ -{ 0x25BE, 0x061e }, /* 30 , 6, */ -{ 0x25BF, 0x06ad }, /* 173, 6, */ -{ 0x25C2, 0x061c }, /* 28 , 6, */ -{ 0x25C3, 0x068a }, /* 138, 6, */ -{ 0x25C6, 0x0575 }, /* 117, 5, */ -{ 0x25C7, 0x066f }, /* 111, 6, */ -{ 0x25CA, 0x065f }, /* 95 , 6, */ -{ 0x25CB, 0x0401 }, /* 1 , 4, */ -{ 0x25CF, 0x0400 }, /* 0 , 4, */ -{ 0x25D6, 0x059e }, /* 158, 5, */ -{ 0x25D7, 0x0577 }, /* 119, 5, */ -{ 0x25D8, 0x0512 }, /* 18 , 5, */ -{ 0x25D9, 0x0513 }, /* 19 , 5, */ -{ 0x25E6, 0x042d }, /* 45 , 4, */ -{ 0x2605, 0x0548 }, /* 72, 5, */ -/*{ 0x2606, 0x0549 }, Removed 10/98 use 0x2729 value. */ /* 73 , 5, */ -{ 0x260E, 0x051e }, /* 30 , 5, */ -{ 0x2610, 0x0518 }, /* 24 , 5, */ -{ 0x2612, 0x0519 }, /* 25 , 5, */ -{ 0x261B, 0x052a }, /* 42 , 5, */ -{ 0x261C, 0x0516 }, /* 22 , 5, */ -{ 0x261E, 0x052b }, /* 43 , 5, */ -{ 0x2639, 0x051a }, /* 26 , 5, */ -{ 0x263A, 0x0507 }, /* 7 , 5, */ -{ 0x263B, 0x0508 }, /* 8 , 5, */ -{ 0x263C, 0x0506 }, /* 6 , 5, */ -{ 0x2640, 0x0505 }, /* 5 , 5, */ -{ 0x2642, 0x0504 }, /* 4 , 5, */ -{ 0x2660, 0x05ab }, /* 171, 5, */ -{ 0x2661, 0x0500 }, /* 0 , 5, */ -{ 0x2662, 0x0501 }, /* 1 , 5, */ -{ 0x2663, 0x05a8 }, /* 168, 5, */ -{ 0x2664, 0x0503 }, /* 3 , 5, */ -{ 0x2665, 0x05aa }, /* 170, 5, */ -{ 0x2666, 0x05a9 }, /* 169, 5, */ -{ 0x2667, 0x0502 }, /* 2 , 5, */ -{ 0x266A, 0x0509 }, /* 9 , 5, */ -{ 0x266C, 0x050a }, /* 10 , 5, */ -{ 0x266D, 0x051c }, /* 28 , 5, */ -{ 0x266E, 0x051d }, /* 29 , 5, */ -{ 0x266F, 0x051b }, /* 27 , 5, */ -{ 0x2701, 0x0521 }, /* 33 , 5, */ -{ 0x2702, 0x0522 }, /* 34 , 5, */ -{ 0x2703, 0x0523 }, /* 35 , 5, */ -{ 0x2704, 0x0524 }, /* 36 , 5, */ -{ 0x2706, 0x0526 }, /* 38 , 5, */ -{ 0x2707, 0x0527 }, /* 39 , 5, */ -{ 0x2708, 0x0528 }, /* 40 , 5, */ -{ 0x2709, 0x0529 }, /* 41 , 5, */ -{ 0x270C, 0x052c }, /* 44 , 5, */ -{ 0x270D, 0x052d }, /* 45 , 5, */ -{ 0x270E, 0x052e }, /* 46 , 5, */ -{ 0x270F, 0x052f }, /* 47 , 5, */ -{ 0x2710, 0x0530 }, /* 48 , 5, */ -{ 0x2711, 0x0531 }, /* 49 , 5, */ -{ 0x2712, 0x0532 }, /* 50 , 5, */ -{ 0x2713, 0x0533 }, /* 51 , 5, */ -{ 0x2714, 0x0534 }, /* 52 , 5, */ -{ 0x2715, 0x0535 }, /* 53 , 5, */ -{ 0x2716, 0x0536 }, /* 54 , 5, */ -{ 0x2717, 0x0537 }, /* 55 , 5, */ -{ 0x2718, 0x0538 }, /* 56 , 5, */ -{ 0x2719, 0x0539 }, /* 57 , 5, */ -{ 0x271A, 0x053a }, /* 58 , 5, */ -{ 0x271B, 0x053b }, /* 59 , 5, */ -{ 0x271C, 0x053c }, /* 60 , 5, */ -{ 0x271D, 0x053d }, /* 61 , 5, */ -{ 0x271E, 0x053e }, /* 62 , 5, */ -{ 0x271F, 0x053f }, /* 63 , 5, */ -{ 0x2720, 0x0540 }, /* 64 , 5, */ -{ 0x2721, 0x0541 }, /* 65 , 5, */ -{ 0x2722, 0x0542 }, /* 66 , 5, */ -{ 0x2723, 0x0543 }, /* 67 , 5, */ -{ 0x2724, 0x0544 }, /* 68 , 5, */ -{ 0x2725, 0x0545 }, /* 69 , 5, */ -{ 0x2726, 0x0546 }, /* 70 , 5, */ -{ 0x2727, 0x0547 }, /* 71 , 5, */ -{ 0x2729, 0x0549 }, /* 73 , 5, */ -{ 0x272A, 0x054a }, /* 74 , 5, */ -{ 0x272B, 0x054b }, /* 75 , 5, */ -{ 0x272C, 0x054c }, /* 76 , 5, */ -{ 0x272D, 0x054d }, /* 77 , 5, */ -{ 0x272E, 0x054e }, /* 78 , 5, */ -{ 0x272F, 0x054f }, /* 79 , 5, */ -{ 0x2730, 0x0550 }, /* 80 , 5, */ -{ 0x2731, 0x0551 }, /* 81 , 5, */ -{ 0x2732, 0x0552 }, /* 82 , 5, */ -{ 0x2733, 0x0553 }, /* 83 , 5, */ -{ 0x2734, 0x0554 }, /* 84 , 5, */ -{ 0x2735, 0x0555 }, /* 85 , 5, */ -{ 0x2736, 0x0556 }, /* 86 , 5, */ -{ 0x2737, 0x0557 }, /* 87 , 5, */ -{ 0x2738, 0x0558 }, /* 88 , 5, */ -{ 0x2739, 0x0559 }, /* 89 , 5, */ -{ 0x273A, 0x055a }, /* 90 , 5, */ -{ 0x273B, 0x055b }, /* 91 , 5, */ -{ 0x273C, 0x055c }, /* 92 , 5, */ -{ 0x273D, 0x055d }, /* 93 , 5, */ -{ 0x273E, 0x055e }, /* 94 , 5, */ -{ 0x273F, 0x055f }, /* 95 , 5, */ -{ 0x2740, 0x0560 }, /* 96 , 5, */ -{ 0x2741, 0x0561 }, /* 97 , 5, */ -{ 0x2742, 0x0562 }, /* 98 , 5, */ -{ 0x2743, 0x0563 }, /* 99 , 5, */ -{ 0x2744, 0x0564 }, /* 100, 5, */ -{ 0x2745, 0x0565 }, /* 101, 5, */ -{ 0x2746, 0x0566 }, /* 102, 5, */ -{ 0x2747, 0x0567 }, /* 103, 5, */ -{ 0x2748, 0x0568 }, /* 104, 5, */ -{ 0x2749, 0x0569 }, /* 105, 5, */ -{ 0x274A, 0x056a }, /* 106, 5, */ -{ 0x274B, 0x056b }, /* 107, 5, */ -{ 0x274D, 0x056d }, /* 109, 5, */ -{ 0x274F, 0x056f }, /* 111, 5, */ -{ 0x2750, 0x0570 }, /* 112, 5, */ -{ 0x2751, 0x0571 }, /* 113, 5, */ -{ 0x2752, 0x0572 }, /* 114, 5, */ -{ 0x2756, 0x0576 }, /* 118, 5, */ -{ 0x2758, 0x0578 }, /* 120, 5, */ -{ 0x2759, 0x0579 }, /* 121, 5, */ -{ 0x275A, 0x057a }, /* 122, 5, */ -{ 0x275B, 0x057b }, /* 123, 5, */ -{ 0x275C, 0x057c }, /* 124, 5, */ -{ 0x275D, 0x057d }, /* 125, 5, */ -{ 0x275E, 0x057e }, /* 126, 5, */ -{ 0x2761, 0x05a1 }, /* 161, 5, */ -{ 0x2762, 0x05a2 }, /* 162, 5, */ -{ 0x2763, 0x05a3 }, /* 163, 5, */ -{ 0x2764, 0x05a4 }, /* 164, 5, */ -{ 0x2765, 0x05a5 }, /* 165, 5, */ -{ 0x2766, 0x05a6 }, /* 166, 5, */ -{ 0x2767, 0x05a7 }, /* 167, 5, */ -{ 0x2776, 0x05b6 }, /* 182, 5, */ -{ 0x2777, 0x05b7 }, /* 183, 5, */ -{ 0x2778, 0x05b8 }, /* 184, 5, */ -{ 0x2779, 0x05b9 }, /* 185, 5, */ -{ 0x277A, 0x05ba }, /* 186, 5, */ -{ 0x277B, 0x05bb }, /* 187, 5, */ -{ 0x277C, 0x05bc }, /* 188, 5, */ -{ 0x277D, 0x05bd }, /* 189, 5, */ -{ 0x277E, 0x05be }, /* 190, 5, */ -{ 0x277F, 0x05bf }, /* 191, 5, */ -{ 0x2780, 0x05c0 }, /* 192, 5, */ -{ 0x2781, 0x05c1 }, /* 193, 5, */ -{ 0x2782, 0x05c2 }, /* 194, 5, */ -{ 0x2783, 0x05c3 }, /* 195, 5, */ -{ 0x2784, 0x05c4 }, /* 196, 5, */ -{ 0x2785, 0x05c5 }, /* 197, 5, */ -{ 0x2786, 0x05c6 }, /* 198, 5, */ -{ 0x2787, 0x05c7 }, /* 199, 5, */ -{ 0x2788, 0x05c8 }, /* 200, 5, */ -{ 0x2789, 0x05c9 }, /* 201, 5, */ -{ 0x278A, 0x05ca }, /* 202, 5, */ -{ 0x278B, 0x05cb }, /* 203, 5, */ -{ 0x278C, 0x05cc }, /* 204, 5, */ -{ 0x278D, 0x05cd }, /* 205, 5, */ -{ 0x278E, 0x05ce }, /* 206, 5, */ -{ 0x278F, 0x05cf }, /* 207, 5, */ -{ 0x2790, 0x05d0 }, /* 208, 5, */ -{ 0x2791, 0x05d1 }, /* 209, 5, */ -{ 0x2792, 0x05d2 }, /* 210, 5, */ -{ 0x2793, 0x05d3 }, /* 211, 5, */ -{ 0x2794, 0x05d4 }, /* 212, 5, */ -{ 0x2798, 0x05d8 }, /* 216, 5, */ -{ 0x2799, 0x05d9 }, /* 217, 5, */ -{ 0x279A, 0x05da }, /* 218, 5, */ -{ 0x279B, 0x05db }, /* 219, 5, */ -{ 0x279C, 0x05dc }, /* 220, 5, */ -{ 0x279D, 0x05dd }, /* 221, 5, */ -{ 0x279E, 0x05de }, /* 222, 5, */ -{ 0x279F, 0x05df }, /* 223, 5, */ -{ 0x27A0, 0x05e0 }, /* 224, 5, */ -{ 0x27A1, 0x05e1 }, /* 225, 5, */ -{ 0x27A2, 0x05e2 }, /* 226, 5, */ -{ 0x27A3, 0x05e3 }, /* 227, 5, */ -{ 0x27A4, 0x05e4 }, /* 228, 5, */ -{ 0x27A5, 0x05e5 }, /* 229, 5, */ -{ 0x27A6, 0x05e6 }, /* 230, 5, */ -{ 0x27A7, 0x05e7 }, /* 231, 5, */ -{ 0x27A8, 0x05e8 }, /* 232, 5, */ -{ 0x27A9, 0x05e9 }, /* 233, 5, */ -{ 0x27AA, 0x05ea }, /* 234, 5, */ -{ 0x27AB, 0x05eb }, /* 235, 5, */ -{ 0x27AC, 0x05ec }, /* 236, 5, */ -{ 0x27AD, 0x05ed }, /* 237, 5, */ -{ 0x27AE, 0x05ee }, /* 238, 5, */ -{ 0x27AF, 0x05ef }, /* 239, 5, */ -{ 0x27B1, 0x05f1 }, /* 241, 5, */ -{ 0x27B2, 0x05f2 }, /* 242, 5, */ -{ 0x27B3, 0x05f3 }, /* 243, 5, */ -{ 0x27B4, 0x05f4 }, /* 244, 5, */ -{ 0x27B5, 0x05f5 }, /* 245, 5, */ -{ 0x27B6, 0x05f6 }, /* 246, 5, */ -{ 0x27B7, 0x05f7 }, /* 247, 5, */ -{ 0x27B8, 0x05f8 }, /* 248, 5, */ -{ 0x27B9, 0x05f9 }, /* 249, 5, */ -{ 0x27BA, 0x05fa }, /* 250, 5, */ -{ 0x27BB, 0x05fb }, /* 251, 5, */ -{ 0x27BC, 0x05fc }, /* 252, 5, */ -{ 0x27BD, 0x05fd }, /* 253, 5, */ -{ 0x27BE, 0x05fe }, /* 254, 5, */ - -/* Range 0xE000 through 0xF8FF is reserved for private use. - We cannot try to interpret characters in this range nor - assign any default collation or meaning. -*/ - -{ 0xFB00, 0x0433 }, /* 51 , 4, */ -{ 0xFB01, 0x0436 }, /* 54 , 4, */ -{ 0xFB02, 0x0437 }, /* 55 , 4, */ -{ 0xFB03, 0x0434 }, /* 52 , 4, */ -{ 0xFB04, 0x0435 }, /* 53 , 4, */ -{ 0xFB1E, 0x0930 }, /* 48 , 9, */ -{ 0xFF61, 0x0b00 }, /* 0 , 11, */ -{ 0xFF62, 0x0b01 }, /* 1 , 11, */ -{ 0xFF63, 0x0b02 }, /* 2 , 11, */ -{ 0xFF64, 0x0b03 }, /* 3 , 11, */ -{ 0xFF65, 0x0b04 }, /* 4 , 11, */ -{ 0xFF66, 0x0b05 }, /* 5 , 11, */ -{ 0xFF67, 0x0b06 }, /* 6 , 11, */ -{ 0xFF68, 0x0b07 }, /* 7 , 11, */ -{ 0xFF69, 0x0b08 }, /* 8 , 11, */ -{ 0xFF6A, 0x0b09 }, /* 9 , 11, */ -{ 0xFF6B, 0x0b0a }, /* 10 , 11, */ -{ 0xFF6C, 0x0b0b }, /* 11 , 11, */ -{ 0xFF6D, 0x0b0c }, /* 12 , 11, */ -{ 0xFF6E, 0x0b0d }, /* 13 , 11, */ -{ 0xFF6F, 0x0b0e }, /* 14 , 11, */ -{ 0xFF70, 0x0b0f }, /* 15 , 11, */ -{ 0xFF71, 0x0b10 }, /* 16 , 11, */ -{ 0xFF72, 0x0b11 }, /* 17 , 11, */ -{ 0xFF73, 0x0b12 }, /* 18 , 11, */ -{ 0xFF74, 0x0b13 }, /* 19 , 11, */ -{ 0xFF75, 0x0b14 }, /* 20 , 11, */ -{ 0xFF76, 0x0b15 }, /* 21 , 11, */ -{ 0xFF77, 0x0b16 }, /* 22 , 11, */ -{ 0xFF78, 0x0b17 }, /* 23 , 11, */ -{ 0xFF79, 0x0b18 }, /* 24 , 11, */ -{ 0xFF7A, 0x0b19 }, /* 25 , 11, */ -{ 0xFF7B, 0x0b1a }, /* 26 , 11, */ -{ 0xFF7C, 0x0b1b }, /* 27 , 11, */ -{ 0xFF7D, 0x0b1c }, /* 28 , 11, */ -{ 0xFF7E, 0x0b1d }, /* 29 , 11, */ -{ 0xFF7F, 0x0b1e }, /* 30 , 11, */ -{ 0xFF80, 0x0b1f }, /* 31 , 11, */ -{ 0xFF81, 0x0b20 }, /* 32 , 11, */ -{ 0xFF82, 0x0b21 }, /* 33 , 11, */ -{ 0xFF83, 0x0b22 }, /* 34 , 11, */ -{ 0xFF84, 0x0b23 }, /* 35 , 11, */ -{ 0xFF85, 0x0b24 }, /* 36 , 11, */ -{ 0xFF86, 0x0b25 }, /* 37 , 11, */ -{ 0xFF87, 0x0b26 }, /* 38 , 11, */ -{ 0xFF88, 0x0b27 }, /* 39 , 11, */ -{ 0xFF89, 0x0b28 }, /* 40 , 11, */ -{ 0xFF8A, 0x0b29 }, /* 41 , 11, */ -{ 0xFF8B, 0x0b2a }, /* 42 , 11, */ -{ 0xFF8C, 0x0b2b }, /* 43 , 11, */ -{ 0xFF8D, 0x0b2c }, /* 44 , 11, */ -{ 0xFF8E, 0x0b2d }, /* 45 , 11, */ -{ 0xFF8F, 0x0b2e }, /* 46 , 11, */ -{ 0xFF90, 0x0b2f }, /* 47 , 11, */ -{ 0xFF91, 0x0b30 }, /* 48 , 11, */ -{ 0xFF92, 0x0b31 }, /* 49 , 11, */ -{ 0xFF93, 0x0b32 }, /* 50 , 11, */ -{ 0xFF94, 0x0b33 }, /* 51 , 11, */ -{ 0xFF95, 0x0b34 }, /* 52 , 11, */ -{ 0xFF96, 0x0b35 }, /* 53 , 11, */ -{ 0xFF97, 0x0b36 }, /* 54 , 11, */ -{ 0xFF98, 0x0b37 }, /* 55 , 11, */ -{ 0xFF99, 0x0b38 }, /* 56 , 11, */ -{ 0xFF9A, 0x0b39 }, /* 57 , 11, */ -{ 0xFF9B, 0x0b3a }, /* 58 , 11, */ -{ 0xFF9C, 0x0b3b }, /* 59 , 11, */ -{ 0xFF9D, 0x0b3c }, /* 60 , 11, */ -{ 0xFF9E, 0x0b3d }, /* 61 , 11, */ -{ 0xFF9F, 0x0b3e } /* 62 , 11, */ -}; - -/**************************************************************************** -* TABLE 1: WP60 to Unicode - Multinational 1 -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI1[] = { - 0x0300, 0x00B7, 0x0303, 0x0302, 0x0335, - 0x0338, 0x0301, 0x0308, 0x0304, 0x0313, -/*10*/ 0x0315, 0x02BC, 0x0326, 0x0315, 0x030A, - 0x0307, 0x030B, 0x0327, 0x0328, 0x030C, -/*20*/ 0x0337, 0x0305, 0x0306, 0x00DF, 0x0138, - 0xF801, 0x00C1, 0x00E1, 0x00C2, 0x00E2, -/*30*/ 0x00C4, 0x00E4, 0x00C0, 0x00E0, 0x00C5, - 0x00E5, 0x00C6, 0x00E6, 0x00C7, 0x00E7, -/*40*/ 0x00C9, 0x00E9, 0x00CA, 0x00EA, 0x00CB, - 0x00EB, 0x00C8, 0x00E8, 0x00CD, 0x00ED, -/*50*/ 0x00CE, 0x00EE, 0x00CF, 0x00EF, 0x00CC, - 0x00EC, 0x00D1, 0x00F1, 0x00D3, 0x00F3, -/*60*/ 0x00D4, 0x00F4, 0x00D6, 0x00F6, 0x00D2, - 0x00F2, 0x00DA, 0x00FA, 0x00DB, 0x00FB, -/*70*/ 0x00DC, 0x00FC, 0x00D9, 0x00F9, 0x0178, - 0x00FF, 0x00C3, 0x00E3, 0x0110, 0x0111, -/*80*/ 0x00D8, 0x00F8, 0x00D5, 0x00F5, 0x00DD, - 0x00FD, 0x00D0, 0x00F0, 0x00DE, 0x00FE, -/*90*/ 0x0102, 0x0103, 0x0100, 0x0101, 0x0104, - 0x0105, 0x0106, 0x0107, 0x010C, 0x010D, -/*100*/ 0x0108, 0x0109, 0x010A, 0x010B, 0x010E, - 0x010F, 0x011A, 0x011B, 0x0116, 0x0117, -/*110*/ 0x0112, 0x0113, 0x0118, 0x0119, 0x0047, - 0x0067, 0x011E, 0x011F, 0x0047, 0x0067, -/*120*/ 0x0122, 0x0123, 0x011C, 0x011D, 0x0120, - 0x0121, 0x0124, 0x0125, 0x0126, 0x0127, -/*130*/ 0x0130, 0x0069, 0x012A, 0x012B, 0x012E, - 0x012F, 0x0128, 0x0129, 0x0132, 0x0133, -/*140*/ 0x0134, 0x0135, 0x0136, 0x0137, 0x0139, - 0x013A, 0x013D, 0x013E, 0x013B, 0x013C, -/*150*/ 0x013F, 0x0140, 0x0141, 0x0142, 0x0143, - 0x0144, 0xF802, 0x0149, 0x0147, 0x0148, -/*160*/ 0x0145, 0x0146, 0x0150, 0x0151, 0x014C, - 0x014D, 0x0152, 0x0153, 0x0154, 0x0155, -/*170*/ 0x0158, 0x0159, 0x0156, 0x0157, 0x015A, - 0x015B, 0x0160, 0x0161, 0x015E, 0x015F, -/*180*/ 0x015C, 0x015D, 0x0164, 0x0165, 0x0162, - 0x0163, 0x0166, 0x0167, 0x016C, 0x016D, -/*190*/ 0x0170, 0x0171, 0x016A, 0x016B, 0x0172, - 0x0173, 0x016E, 0x016F, 0x0168, 0x0169, -/*200*/ 0x0174, 0x0175, 0x0176, 0x0177, 0x0179, - 0x017A, 0x017D, 0x017E, 0x017B, 0x017C, -/*210*/ 0x014A, 0x014B, 0xF000, 0xF001, 0xF002, - 0xF003, 0xF004, 0xF005, 0xF006, 0xF007, -/*220*/ 0xF008, 0xF009, 0xF00A, 0xF00B, 0xF00C, - 0xF00D, 0xF00E, 0xF00F, 0x010E, 0x010F, -/*230*/ 0x01A0, 0x01A1, 0x01AF, 0x01B0, 0x0114, - 0x0115, 0x012C, 0x012D, 0x0049, 0x0131, -/*240*/ 0x014E, 0x014F -}; - -/********************************************************************** -* TABLE 2: WP60 to Unicode - Standard Phonetic -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI2[] = { - 0x02B9, 0x02BA, 0x02BB, 0xF813, 0x02BD, - 0x02BC, 0xF814, 0x02BE, 0x02BF, 0x0310, -/*10*/ 0x02D0, 0x02D1, 0x0306, 0x032E, 0x0329, /* 10/98 [14] was 0x2CC */ - 0x02C8, 0x02CC, 0x02C9, 0x02CA, 0x02CB, -/*20*/ 0x02CD, 0x02CE, 0x02CF, 0x02C6, 0x02C7, - 0x02DC, 0x0325, 0x02DA, 0x032D, 0x032C, -/*30*/ 0x0323, 0x0308, 0x0324, 0x031C, 0x031D, - 0x031E, 0x031F, 0x0320, 0x0321, 0x0322, -/*40*/ 0x032A, 0x032B, 0x02D2, 0x02D3, 0xF815, - 0xF816, 0x005F, 0x2017, 0x033E, 0x02DB, -/*50*/ 0x0327, 0x02DE, 0x02C8, 0x02B0, 0x02B6, - 0x0250, 0x0251, 0x0252, 0x0253, 0x0299, -/*60*/ 0x0254, 0x0255, 0x0297, 0x0256, 0x0257, - 0x0258, 0x0259, 0x025A, 0x025B, 0x025C, -/*70*/ 0x025D, 0x029A, 0x025E, 0x025F, 0x0278, - 0x0261, 0x0260, 0x0262, 0x029B, 0x0263, -/*80*/ 0x0264, 0x0265, 0x0266, 0x0267, 0x029C, - 0x0268, 0x026A, 0x0269, 0x029D, 0x029E, -/*90*/ 0x026B, 0x026C, 0x026D, 0x029F, 0x026E, - 0x028E, 0x026F, 0x0270, 0x0271, 0x0272, -/*100*/ 0x0273, 0x0274, 0x0276, 0x0277, 0x02A0, - 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, -/*110*/ 0x027E, 0x027F, 0x0280, 0x0281, 0x0282, - 0x0283, 0x0284, 0x0285, 0x0286, 0x0287, -/*120*/ 0x0288, 0x0275, 0x0289, 0x028A, 0x028C, - 0x028B, 0x028D, 0x0058, 0x028F, 0x0290, -/*130*/ 0x0291, 0x0292, 0x0293, 0x0294, 0x0295, - 0x0296, 0x02A1, 0x02A2, 0x0298, 0x02A3, -/*140*/ 0x02A4, 0x02A5, 0x02A6, 0x02A7, 0x02A8 -}; - -/***************************************************************************** -* TABLE 3: WP51/WP60 to Unicode - Box Drawing -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -******************************************************************************/ - -FLMUINT16 WPCH_WPUNI3[] = { - 0x2591, 0x2592, 0x2593, 0x2588, 0x258C, - 0x2580, 0x2590, 0x2584, 0x2500, 0x2502, -/*10*/ 0x250C, 0x2510, 0x2518, 0x2514, 0x251C, - 0x252C, 0x2524, 0x2534, 0x253C, 0x2550, -/*20*/ 0x2551, 0x2554, 0x2557, 0x255D, 0x255A, - 0x2560, 0x2566, 0x2563, 0x2569, 0x256C, -/*30*/ 0x2552, 0x2555, 0x255B, 0x2558, 0x2553, - 0x2556, 0x255C, 0x2559, 0x255E, 0x2565, -/*40*/ 0x2561, 0x2568, 0x255F, 0x2564, 0x2562, - 0x2567, 0x256B, 0x256A, 0x2574, 0x2575, -/*50*/ 0x2576, 0x2577, 0x2578, 0x2579, 0x257A, - 0x257B, 0x257C, 0x257E, 0x257D, 0x257F, -/*60*/ 0x251F, 0x2522, 0x251E, 0x2521, 0x252E, - 0x2532, 0x252D, 0x2531, 0x2527, 0x2526, -/*70*/ 0x252A, 0x2529, 0x2536, 0x253A, 0x2535, - 0x2539, 0x2541, 0x2546, 0x253E, 0x2540, -/*80*/ 0x2544, 0x254A, 0x253D, 0x2545, 0x2548, - 0x2543, 0x2549, 0x2547 -}; - - -/**************************************************************************** -* TABLE 4: WP51/WP60 to Unicode - Typographic Symbols -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WPUNI4[] = { - 0x25CF, 0x25CB, 0x25A0, 0x2022, 0xF817, - 0x00B6, 0x00A7, 0x00A1, 0x00BF, 0x00AB, -/*10*/ 0x00BB, 0x00A3, 0x00A5, 0x20A7, 0x0192, - 0x00AA, 0x00BA, 0x00BD, 0x00BC, 0x00A2, -/*20*/ 0x00B2, 0x207F, 0x00AE, 0x00A9, 0x00A4, - 0x00BE, 0x00B3, 0x201B, 0x2019, 0x2018, -/*30*/ 0x201F, 0x201D, 0x201C, 0x2013, 0x2014, - 0x2039, 0x203A, 0x25CB, 0x25A1, 0x2020, -/*40*/ 0x2021, 0x2122, 0x2120, 0x211E, 0x25CF, - 0x25E6, 0x25A0, 0x25AA, 0x25A1, 0x25AB, -/*50*/ 0x2012, 0xFB00, 0xFB03, 0xFB04, 0xFB01, - 0xFB02, 0x2026, 0x0024, 0x20A3, 0x20A2, -/*60*/ 0x20A0, 0x20A4, 0x201A, 0x201E, 0x2153, - 0x2154, 0x215B, 0x215C, 0x215D, 0x215E, -/*70*/ 0x24C2, 0x24C5, 0x24CA, 0x2105, 0x2106, - 0x2030, 0x2116, 0xF818, 0x00B9, 0x2409, -/*80*/ 0x240C, 0x240D, 0x240A, 0x2424, 0x240B, - 0xF819, 0x20A9, 0x20A6, 0x20A8, 0xF81A, -/*90*/ 0xF81B, 0xF81C, 0xF81D, 0xF81E, 0xF81F, - 0xF820, 0xF821, 0xF822, 0xF823, 0xF824, -/*100*/ 0xF825, 0xF826, 0x20AC /* [102] Euro Sign */ -}; - - -/**************************************************************************** -* TABLE 5: WP60 to Unicode - Iconic Symbols -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI5[] = { - 0x2661, 0x2662, 0x2667, 0x2664, 0x2642, - 0x2640, 0x263C, 0x263A, 0x263B, 0x266A, -/*10*/ 0x266C, 0x25AC, 0x2302, 0x203C, 0x221A, - 0x21A8, 0x2310, 0x2319, 0x25D8, 0x25D9, -/*20*/ 0x21B5, 0x2104, 0x261C, 0x2007, 0x2610, - 0x2612, 0x2639, 0x266F, 0x266D, 0x266E, -/*30*/ 0x260E, 0x231A, 0x231B, 0x2701, 0x2702, - 0x2703, 0x2704, 0x260E, 0x2706, 0x2707, -/*40*/ 0x2708, 0x2709, 0x261B, 0x261E, 0x270C, - 0x270D, 0x270E, 0x270F, 0x2710, 0x2711, -/*50*/ 0x2712, 0x2713, 0x2714, 0x2715, 0x2716, - 0x2717, 0x2718, 0x2719, 0x271A, 0x271B, -/*60*/ 0x271C, 0x271D, 0x271E, 0x271F, 0x2720, - 0x2721, 0x2722, 0x2723, 0x2724, 0x2725, -/*70*/ 0x2726, 0x2727, 0x2605, 0x2729, 0x272A, // 10/98 - [73] was 0x2606 - 0x272B, 0x272C, 0x272D, 0x272E, 0x272F, -/*80*/ 0x2730, 0x2731, 0x2732, 0x2733, 0x2734, - 0x2735, 0x2736, 0x2737, 0x2738, 0x2739, -/*90*/ 0x273A, 0x273B, 0x273C, 0x273D, 0x273E, - 0x273F, 0x2740, 0x2741, 0x2742, 0x2743, -/*100*/ 0x2744, 0x2745, 0x2746, 0x2747, 0x2748, - 0x2749, 0x274A, 0x274B, 0x25CF, 0x274D, -/*110*/ 0x25A0, 0x274F, 0x2750, 0x2751, 0x2752, - 0x25B2, 0x25BC, 0x25C6, 0x2756, 0x25D7, -/*120*/ 0x2758, 0x2759, 0x275A, 0x275B, 0x275C, - 0x275D, 0x275E, 0x2036, 0x2033, 0xF827, -/*130*/ 0xF828, 0xF829, 0xF82A, 0x2329, 0x232A, - 0x005B, 0x005D, 0xF82B, 0xF82C, 0xF82D, -/*140*/ 0xF82E, 0xF82F, 0xF830, 0xF831, 0x2190, - 0xF832, 0xF833, 0xF834, 0xF835, 0xF836, -/*150*/ 0x21E8, 0x21E6, 0x2794, 0xF838, 0xF839, - 0xF83A, 0xF83B, 0xF83C, 0x25D6, 0xF83D, -/*160*/ 0xF83E, 0x2761, 0x2762, 0x2763, 0x2764, - 0x2765, 0x2766, 0x2767, 0x2663, 0x2666, -/*170*/ 0x2665, 0x2660, 0x2780, 0x2781, 0x2782, - 0x2783, 0x2784, 0x2785, 0x2786, 0x2787, -/*180*/ 0x2788, 0x2789, 0x2776, 0x2777, 0x2778, - 0x2779, 0x277A, 0x277B, 0x277C, 0x277D, -/*190*/ 0x277E, 0x277F, 0x2780, 0x2781, 0x2782, - 0x2783, 0x2784, 0x2785, 0x2786, 0x2787, -/*200*/ 0x2788, 0x2789, 0x278A, 0x278B, 0x278C, - 0x278D, 0x278E, 0x278F, 0x2790, 0x2791, -/*210*/ 0x2792, 0x2793, 0x2794, 0x2192, 0x2194, - 0x2195, 0x2798, 0x2799, 0x279A, 0x279B, -/*220*/ 0x279C, 0x279D, 0x279E, 0x279F, 0x27A0, - 0x27A1, 0x27A2, 0x27A3, 0x27A4, 0x27A5, -/*230*/ 0x27A6, 0x27A7, 0x27A8, 0x27A9, 0x27AA, - 0x27AB, 0x27AC, 0x27AD, 0x27AE, 0x27AF, -/*240*/ 0xF83F, 0x27B1, 0x27B2, 0x27B3, 0x27B4, - 0x27B5, 0x27B6, 0x27B7, 0x27B8, 0x27B9, -/*250*/ 0x27BA, 0x27BB, 0x27BC, 0x27BD, 0x27BE -}; - -/**************************************************************************** -* TABLE 6A: WP51/WP60 to Unicode - Math/Scientific -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WPUNI6[] = { - 0x2212, 0x00B1, 0x2264, 0x2265, 0x221D, - 0x01C0, 0x2215, 0x2216, 0x00F7, 0x2223, -/*10*/ 0x2329, 0x232A, 0x223C, 0x2248, 0x2261, - 0x2208, 0x2229, 0x2225, 0x2211, 0x221E, -/*20*/ 0x00AC, 0x2192, 0x2190, 0x2191, 0x2193, - 0x2194, 0x2195, 0x25B8, 0x25C2, 0x25B4, -/*30*/ 0x25BE, 0x22C5, 0xF850, 0x2218, 0x2219, - 0x212B, 0x00B0, 0x00B5, 0x203E, 0x00D7, -/*40*/ 0x222B, 0x220F, 0x2213, 0x2207, 0x2202, - 0x02B9, 0x02BA, 0x2192, 0x212F, 0x2113, -/*50*/ 0x210F, 0x2111, 0x211C, 0x2118, 0x21C4, - 0x21C6, 0x21D2, 0x21D0, 0x21D1, 0x21D3, -/*60*/ 0x21D4, 0x21D5, 0x2197, 0x2198, 0x2196, - 0x2199, 0x222A, 0x2282, 0x2283, 0x2286, -/*70*/ 0x2287, 0x220D, 0x2205, 0x2308, 0x2309, - 0x230A, 0x230B, 0x226A, 0x226B, 0x2220, -/*80*/ 0x2297, 0x2295, 0x2296, 0xF851, 0x2299, - 0x2227, 0x2228, 0x22BB, 0x22A4, 0x22A5, -/*90*/ 0x2312, 0x22A2, 0x22A3, 0x25A1, 0x25A0, - 0x25CA, 0xF852, 0xF853, 0xF854, 0x2260, -/*100*/ 0x2262, 0x2235, 0x2234, 0x2237, 0x222E, - 0x2112, 0x212D, 0x2128, 0x2118, 0x20DD, -/*110*/ 0xF855, 0x25C7, 0x22C6, 0x2034, 0x2210, - 0x2243, 0x2245, 0x227A, 0x227C, 0x227B, -/*120*/ 0x227D, 0x2203, 0x2200, 0x22D8, 0x22D9, - 0x228E, 0x228A, 0x228B, 0x2293, 0x2294, -/*130*/ 0x228F, 0x2291, 0x22E4, 0x2290, 0x2292, - 0x22E5, 0x25B3, 0x25BD, 0x25C3, 0x25B9, -/*140*/ 0x22C8, 0x2323, 0x2322, 0xF856, 0x219D, - 0x21A9, 0x21AA, 0x21A3, 0x21BC, 0x21BD, -/*150*/ 0x21C0, 0x21C1, 0x21CC, 0x21CB, 0x21BF, - 0x21BE, 0x21C3, 0x21C2, 0x21C9, 0x21C7, -/*160*/ 0x22D3, 0x22D2, 0x22D0, 0x22D1, 0x229A, - 0x229B, 0x229D, 0x2127, 0x2221, 0x2222, -/*170*/ 0x25C3, 0x25B9, 0x25B5, 0x25BF, 0x2214, - 0x2250, 0x2252, 0x2253, 0x224E, 0x224D, -/*180*/ 0x22A8, 0xF857, 0x226C, 0x0285, 0x2605, - 0x226E, 0x2270, 0x226F, 0x2271, 0x2241, -/*190*/ 0x2244, 0x2247, 0x2249, 0x2280, 0x22E0, - 0x2281, 0x22E1, 0x2284, 0x2285, 0x2288, -/*200*/ 0x2289, 0xF858, 0xF859, 0x22E2, 0x22E3, - 0x2226, 0x2224, 0x226D, 0x2204, 0x2209, -/*210*/ 0xF85A, 0x2130, 0x2131, 0x2102, 0xF85B, - 0x2115, 0x211D, 0x225F, 0x221F, 0x220B, -/*220*/ 0x22EF, 0xF85C, 0x22EE, 0x22F1, 0xF85D, - 0x20E1, 0x002B, 0x002D, 0x003D, 0x002A, -/*230*/ 0xF85E, 0xF85F, 0xF860, 0x210C, 0x2118, - 0x2272, 0x2273, 0xF861 -}; - -/**************************************************************************** -* TABLE 7: WP51/WP60 to Unicode - Math/Science Extension -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -* -* Note: Characters 2-3,5-6,9-62,63-end are mapped to 0xE900-E9FF -****************************************************************************/ - -FLMUINT16 WPCH_WPUNI7[] = { - 0x2320, 0x2321, 0xF702, 0xF703, 0x221A, - 0xF705, 0xF706, 0xF707, 0xF708, 0xF709, -/*10*/ 0xF70A, 0xF70B, 0xF70C, 0xF70D, 0xF70E, - 0xF70F, 0xF710, 0xF711, 0xF712, 0xF713, -/*20*/ 0xF714, 0xF715, 0xF716, 0xF717, 0xF718, - 0xF719, 0xF71A, 0xF71B, 0xF71C, 0xF71D, -/*30*/ 0xF71E, 0xF71F, 0xF720, 0xF721, 0xF722, - 0xF723, 0xF724, 0xF725, 0xF726, 0xF727, -/*40*/ 0xF728, 0xF729, 0xF72A, 0xF72B, 0xF72C, - 0xF72D, 0xF72E, 0xF72F, 0xF730, 0xF731, -/*50*/ 0xF732, 0xF733, 0xF734, 0xF735, 0xF736, - 0xF737, 0xF738, 0xF739, 0xF73A, 0xF73B, -/*60*/ 0xF73C, 0xF73D, 0xF73E, 0xF73F, 0xF740, - 0xF741, 0xF742, 0xF743, 0xF744, 0xF745, -/*70*/ 0xF746, 0xF747, 0xF748, 0xF749, 0xF74A, - 0xF74B, 0xF74C, 0xF74D, 0xF74E, 0xF74F, -/*80*/ 0xF750, 0xF751, 0xF752, 0xF753, 0xF754, - 0xF755, 0xF756, 0xF757, 0xF758, 0xF759, -/*90*/ 0xF75A, 0xF75B, 0xF75C, 0xF75D, 0xF75E, - 0xF75F, 0xF760, 0xF761, 0xF762, 0xF763, -/*100*/ 0xF764, 0xF765, 0xF766, 0xF767, 0xF768, - 0xF769, 0xF76A, 0xF76B, 0xF76C, 0xF76D, -/*110*/ 0xF76E, 0xF76F, 0xF770, 0xF771, 0xF772, - 0xF773, 0xF774, 0xF775, 0xF776, 0xF777, -/*120*/ 0xF778, 0xF779, 0xF77A, 0xF77B, 0xF77C, - 0xF77D, 0xF77E, 0xF77F, 0xF780, 0xF781, -/*130*/ 0xF782, 0xF783, 0xF784, 0xF785, 0xF786, - 0xF787, 0xF788, 0xF789, 0xF78A, 0xF78B, -/*140*/ 0xF78C, 0xF78D, 0xF78E, 0xF78F, 0xF790, - 0xF791, 0xF792, 0xF793, 0xF794, 0xF795, -/*150*/ 0xF796, 0xF797, 0xF798, 0xF799, 0xF79A, - 0xF79B, 0xF79C, 0xF79D, 0xF79E, 0xF79F, -/*160*/ 0xF7A0, 0xF7A1, 0xF7A2, 0xF7A3, 0xF7A4, - 0xF7A5, 0xF7A6, 0xF7A7, 0xF7A8, 0xF7A9, -/*170*/ 0xF7AA, 0xF7AB, 0xF7AC, 0xF7AD, 0xF7AE, - 0xF7AF, 0xF7B0, 0xF7B1, 0xF7B2, 0xF7B3, -/*180*/ 0xF7B4, 0xF7B5, 0xF7B6, 0xF7B7, 0xF7B8, - 0xF7B9, 0xF7BA, 0xF7BB, 0xF7BC, 0xF7BD, -/*190*/ 0xF7BE, 0xF7BF, 0xF7C0, 0xF7C1, 0xF7C2, - 0xF7C3, 0xF7C4, 0xF7C5, 0xF7C6, 0xF7C7, -/*200*/ 0xF7C8, 0xF7C9, 0xF7CA, 0xF7CB, 0xF7CC, - 0xF7CD, 0xF7CE, 0xF7CF, 0xF7D0, 0xF7D1, -/*210*/ 0xF7D2, 0xF7D3, 0xF7D4, 0xF7D5, 0xF7D6, - 0xF7D7, 0xF7D8, 0xF7D9, 0xF7DA, 0xF7DB, -/*220*/ 0xF7DC, 0xF7DD, 0xF7DE, 0xF7DF, 0xF7E0, - 0xF7E1, 0xF7E2, 0xF7E3, 0xF7E4 -}; - -/**************************************************************************** -* TABLE 8: WP60 to Unicode - Greek -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI8[] = { - 0x0391, 0x03B1, 0x0392, 0x03B2, 0x0392, - 0x03D0, 0x0393, 0x03B3, 0x0394, 0x03B4, - 0x0395, 0x03B5, 0x0396, 0x03B6, 0x0397, - 0x03B7, 0x0398, 0x03B8, 0x0399, 0x03B9, - 0x039A, 0x03BA, 0x039B, 0x03BB, 0x039C, - 0x03BC, 0x039D, 0x03BD, 0x039E, 0x03BE, - 0x039F, 0x03BF, 0x03A0, 0x03C0, 0x03A1, - 0x03C1, 0x03A3, 0x03C3, 0x03A3, 0x03C2, - 0x03A4, 0x03C4, 0x03A5, 0x03C5, 0x03A6, - 0x03C6, 0x03A7, 0x03C7, 0x03A8, 0x03C8, - 0x03A9, 0x03C9, 0xF106, 0x03AC, 0xF107, /* 50 - 54 */ - 0x03AD, 0xF108, 0x03AE, 0xF109, 0x03AF, - 0x03AA, 0x03CA, 0xF10A, 0x03CC, 0xF10B, /* 60 - 64 */ - 0x03CD, 0x03AB, 0x03CB, 0xF10C, 0x03CE, - 0x03B5, 0x03D1, 0x03F0, 0x03D6, 0x03F1, /* 70 - 74 */ - 0x03DB, 0x03D2, 0x03D5, 0x03D6, 0x03D7, - 0x00B7, 0x0374, 0x0375, 0x0301, 0x0308, /* 80 - 84 */ - 0xF216, 0xF217, 0x0300, 0x0311, 0x0313, - 0x0314, 0x0345, 0x1FCE, 0x1FDE, 0x1FCD, /* 90 - 94 */ - 0x1FDD, 0xF200, 0xF201, 0xF022, 0xF021, - 0xF202, 0xF203, 0xF204, 0xF300, 0xF301, /* 100 - 104 */ - 0xF302, 0xF303, 0xF304, 0xF305, 0x1F70, - 0xF100, 0x1FB3, 0x1FB4, 0x1FB2, 0xF205, /* 110 - 114 */ - 0x1F00, 0x1F04, 0x1F02, 0xF206, 0x1F80, - 0x1F84, 0x1F82, 0xF306, 0x1F01, 0x1F05, /* 120 - 124 */ - 0x1F03, 0xF207, 0x1F81, 0x1F85, 0x1F83, - 0xF307, 0x1F72, 0x1F10, 0x1F14, 0x1F12, /* 130 - 134 */ - 0x1F11, 0x1F15, 0x1F13, 0x1F74, 0xF101, - 0x1FC3, 0x1FC4, 0x1FC2, 0xF208, 0x1F20, /* 140 - 144 */ - 0x1F24, 0x1F22, 0xF209, 0x1F90, 0x1F94, - 0x1F92, 0xF308, 0x1F21, 0x1F25, 0x1F23, /* 150 - 154 */ - 0xF20A, 0x1F91, 0x1F95, 0x1F93, 0xF309, - 0x1F76, 0xF102, 0xF20B, 0xF20C, 0x1F30, /* 160 - 164 */ - 0x1F34, 0x1F32, 0xF20D, 0x1F31, 0x1F35, - 0x1F33, 0xF20E, 0x1F78, 0x1F40, 0x1F44, /* 170 - 174 */ - 0x1F42, 0x1F41, 0x1F45, 0x1F43, 0x1FE5, - 0x1FE4, 0x1F7A, 0xF103, 0xF20F, 0xF210, /* 180 - 184 */ - 0x1F50, 0x1F54, 0x1F52, 0xF211, 0x1F51, - 0x1F55, 0x1F53, 0xF212, 0x1F7C, 0xF104, /* 190 - 194 */ - 0x1FF3, 0x1FF4, 0x1FF2, 0xF213, 0x1F60, - 0x1F64, 0x1F62, 0xF214, 0x1FA0, 0x1FA4, /* 200 - 204 */ - 0x1FA2, 0xF30A, 0x1F61, 0x1F65, 0x1F63, - 0xF215, 0x1FA1, 0x1FA5, 0x1FA3, 0xF30B, /* 210 - 214 */ - 0x03DA, 0x03DC, 0x03DE, 0x03E0 -}; - -/***************************************************************************** -* TABLE 9: WP60 to Unicode - Hebrew -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI9[] = { - 0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, /* 0 - 4 */ - 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, - 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, /* 10 - 14 */ - 0x05DF, 0x05E0, 0x05E1, 0x05E2, 0x05E3, - 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, /* 20 - 24 */ - 0x05E9, 0x05EA, 0xF862, 0x05C0, 0x05C3, - 0x05F3, 0x05F4, 0x05B0, 0x05B1, 0x05B2, /* 30 - 34 */ - 0x05B3, 0x05B4, 0x05B5, 0x05B6, 0x05B7, - 0x05B8, 0x05B9, 0x05B9, 0x05BB, 0x05BC, /* 40 - 44 */ - 0x05BD, 0x05BF, 0x05B7, 0xFB1E, 0x05F0, - 0x05F1, 0x05F2, 0xF114, 0xF8B0, 0xF863, /* 50 - 54 */ - 0xF864, 0xF865, 0xF866, 0xF867, 0xF868, - 0xF869, 0xF86A, 0xF86B, 0xF86C, 0xF86D, /* 60 - 64 */ - 0xF86E, 0xF86F, 0xF870, 0xF871, 0xF872, - 0xF873, 0xF874, 0x05F3, 0x05F3, 0x05F4, /* 70 - 74 */ - 0xF876, 0xF877, 0xF878, 0xF879, 0xF87A, - 0xF87B, 0xF87C, 0xF87D, 0xF87E, 0xF115, /* 80 - 84 */ - 0xF116, 0xF87F, 0xF117, 0xF118, 0xF119, - 0xF11A, 0xF11B, 0xF11C, 0xF11D, 0xF11E, /* 90 - 94 */ - 0xF11F, 0xF120, 0xF121, 0xF122, 0xF123, - 0xF124, 0xF125, 0xF126, 0xF127, 0xF218, /* 100 - 104 */ - 0xF128, 0xF129, 0xF12A, 0xF12B, 0xF12C, - 0xF12D, 0xF880, 0xF12E, 0xF12F, 0xF130, /* 110 - 114 */ - 0xF219, 0x05E9, 0xF131, 0xF132, 0xF140, - 0xF141, 0xF142, 0x20AA -}; - -/**************************************************************************** -* TABLE 10: WP60 to Unicode - Cyrillic/Georgian -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI10[] = { - 0x0410, 0x0430, 0x0411, 0x0431, 0x0412, /* 0 - 4 */ - 0x0432, 0x0413, 0x0433, 0x0414, 0x0434, - 0x0415, 0x0435, 0x0401, 0x0451, 0x0416, /* 10 - 14 */ - 0x0436, 0x0417, 0x0437, 0x0418, 0x0438, - 0x0419, 0x0439, 0x041A, 0x043A, 0x041B, /* 20 - 24 */ - 0x043B, 0x041C, 0x043C, 0x041D, 0x043D, - 0x041E, 0x043E, 0x041F, 0x043F, 0x0420, /* 30 - 34 */ - 0x0440, 0x0421, 0x0441, 0x0422, 0x0442, - 0x0423, 0x0443, 0x0424, 0x0444, 0x0425, /* 40 - 44 */ - 0x0445, 0x0426, 0x0446, 0x0427, 0x0447, - 0x0428, 0x0448, 0x0429, 0x0449, 0x042A, /* 50 - 54 */ - 0x044A, 0x042B, 0x044B, 0x042C, 0x044C, - 0x042D, 0x044D, 0x042E, 0x044E, 0x042F, /* 60 - 64 */ - 0x044F, 0x04D8, 0x04D9, 0x0403, 0x0453, - 0x0490, 0x0491, 0x0492, 0x0493, 0x0402, /* 70 - 74 */ - 0x0452, 0x0404, 0x0454, 0x0404, 0x0454, - 0x0496, 0x0497, 0x0405, 0x0455, 0xF159, /* 80 - 84 */ - 0xF889, 0xF15E, 0xF15F, 0x0406, 0x0456, - 0x0407, 0x0457, 0xF88C, 0xF88D, 0x0408, /* 90 - 94 */ - 0x0458, 0x040C, 0x045C, 0x049A, 0x049B, - 0xF160, 0xF161, 0x049C, 0x049D, 0x0409, /* 100 - 104 */ - 0x0459, 0x04A2, 0x04A3, 0x040A, 0x045A, - 0x047A, 0x047B, 0x0460, 0x0461, 0x040B, /* 110 - 114 */ - 0x045B, 0x040E, 0x045E, 0x04EE, 0x04EF, - 0x04AE, 0x04AF, 0x04B0, 0x04B1, 0x0194, /* 120 - 124 */ - 0x0263, 0x04B2, 0x04B3, 0xF162, 0xF163, - 0x04BA, 0x04BB, 0x047E, 0x047F, 0x040F, /* 130 - 134 */ - 0x045F, 0x04B6, 0x04B7, 0x04B8, 0x04B9, - 0xF164, 0xF165, 0x0462, 0x0463, 0x0466, /* 140 - 144 */ - 0x0467, 0x046A, 0x046B, 0x046E, 0x046F, - 0x0470, 0x0471, 0x0472, 0x0473, 0x0474, /* 150 - 154 */ - 0x0475, 0xF400, 0xF401, 0xF402, 0xF403, - 0xF404, 0xF405, 0xF406, 0xF407, 0xF408, /* 160 - 164 */ - 0xF409, 0xF40A, 0xF40B, 0xF40C, 0xF40D, - 0xF40E, 0xF40F, 0xF410, 0xF411, 0xF412, /* 170 - 174 */ - 0xF413, 0xF414, 0xF415, 0xF416, 0xF417, - 0xF418, 0xF419, 0xF41A, 0xF41B, 0xF41C, /* 180 - 184 */ - 0xF41D, 0xF41E, 0xF41F, 0xF420, 0xF421, - 0xF422, 0xF423, 0xF424, 0xF425, 0xF426, /* 190 - 194 */ - 0xF427, 0xF428, 0xF429, 0xF42A, 0xF42B, - 0x0301, 0x0300, 0x0308, 0x0306, 0x0326, /* 200 - 204 */ - 0x0328, 0x0304, 0xF893, 0x201E, 0x201F, - 0x10D0, 0x10D1, 0x10D2, 0x10D3, 0x10D4, /* 210 - 214 */ - 0x10D5, 0x10D6, 0x10F1, 0x10D7, 0x10D8, - 0x10D9, 0x10DA, 0x10DB, 0x10DC, 0x10F2, /* 220 - 224 */ - 0x10DD, 0x10DE, 0x10DF, 0x10E0, 0x10E1, - 0x10E2, 0x10E3, 0x10F3, 0x10E4, 0x10E5, /* 230 - 234 */ - 0x10E6, 0x10E7, 0x10E8, 0x10E9, 0x10EA, - 0x10EB, 0x10EC, 0x10ED, 0x10EE, 0x10F4, /* 240 - 244 */ - 0x10EF, 0x10F0, 0x10F5, 0x10F6, 0xF42C -}; - -/**************************************************************************** -* TABLE 11: WP60 to Unicode - Japanese -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WP60UNI11[] = { - 0xFF61, 0xFF62, 0xFF63, 0xFF64, 0xFF65, // 0 - 4 - 0xFF66, 0xFF67, 0xFF68, 0xFF69, 0xFF6A, - 0xFF6B, 0xFF6C, 0xFF6D, 0xFF6E, 0xFF6F, // 10 - 14 - 0xFF70, 0xFF71, 0xFF72, 0xFF73, 0xFF74, - 0xFF75, 0xFF76, 0xFF77, 0xFF78, 0xFF79, // 20 - 24 - 0xFF7A, 0xFF7B, 0xFF7C, 0xFF7D, 0xFF7E, - 0xFF7F, 0xFF80, 0xFF81, 0xFF82, 0xFF83, // 30 - 34 - 0xFF84, 0xFF85, 0xFF86, 0xFF87, 0xFF88, - 0xFF89, 0xFF8A, 0xFF8B, 0xFF8C, 0xFF8D, // 40 - 44 - 0xFF8E, 0xFF8F, 0xFF90, 0xFF91, 0xFF92, - 0xFF93, 0xFF94, 0xFF95, 0xFF96, 0xFF97, // 50 - 54 - 0xFF98, 0xFF99, 0xFF9A, 0xFF9B, 0xFF9C, - 0xFF9D, 0xFF9E, 0xFF9F // 60 - 62 -}; - -/**************************************************************************** -* TABLE 13: WP60 to Unicode - Arabic -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WPUNI13[] = { - 0xF895, 0xF896, 0xF897, 0xF898, 0xF899, // 0 - 4 - 0xF89A, 0xF89B, 0xF89C, 0xF89D, 0xF89E, - 0x064E, 0x064E, 0x064F, 0x064F, 0x0650, // 10 - 14 - 0x0650, 0x064B, 0x064C, 0x064C, 0x0650, - 0x0652, 0x0652, 0x0651, 0xF503, 0xF502, // 20 - 24 - 0xF504, 0xF508, 0xF505, 0xF509, 0xF506, - 0xF50A, 0xF50B, 0xF507, 0xF50C, 0x06E4, // 30 - 34 - 0x06E4, 0x0674, 0x06D6, 0x060C, 0x061B, - 0x061F, 0x002A, 0x066A, 0x226B, 0x226A, // 40 - 44 - 0x0029, 0x0028, 0x0661, 0x0662, 0x0663, - 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, // 50 - 54 10/98 [54] was 0x0627 - 0x0669, 0x0660, 0x0662, 0x0627, 0x0628, - 0x0628, 0x0628, 0x0628, 0x0628, 0x062A, // 60 - 64 - 0x062A, 0x062A, 0x062A, 0x062B, 0x062B, - 0x062B, 0x062B, 0x062C, 0x062C, 0x062C, // 70 - 74 - 0x062C, 0x062D, 0x062D, 0x062D, 0x062D, - 0x062E, 0x062E, 0x062E, 0x062E, 0x062F, // 80 - 84 - 0x062F, 0x0630, 0x0630, 0x0631, 0x0631, - 0x0632, 0x0632, 0x0633, 0x0633, 0x0633, // 90 - 94 - 0x0633, 0x0634, 0x0634, 0x0634, 0x0634, - 0x0635, 0x0635, 0x0635, 0x0635, 0x0636, // 100 - 104 - 0x0636, 0x0636, 0x0636, 0x0637, 0x0637, - 0x0637, 0x0637, 0x0638, 0x0638, 0x0638, // 110 - 114 - 0x0638, 0x0639, 0x0639, 0x0639, 0x0639, - 0x063A, 0x063A, 0x063A, 0x063A, 0x0641, // 120 - 124 - 0x0641, 0x0641, 0x0641, 0x0642, 0x0642, - 0x0642, 0x0642, 0x0643, 0x0643, 0x0643, // 130 - 134 - 0x0643, 0x0644, 0x0644, 0x0644, 0x0644, - 0x0645, 0x0645, 0x0645, 0x0645, 0x0646, // 140 - 144 - 0x0646, 0x0646, 0x0646, 0x0647, 0x0647, - 0x0647, 0x0647, 0x0629, 0x0629, 0x0648, // 150 - 154 - 0x0648, 0x064A, 0x064A, 0x064A, 0x064A, - 0x0649, 0x0649, 0x0649, 0x0649, 0x0621, // 160 - 164 - 0x0623, 0x0623, 0x0625, 0x0625, 0x0624, - 0x0624, 0x0626, 0x0626, 0x0626, 0x0626, // 170 - 174 - 0xF50D, 0xF50D, 0x0622, 0x0622, 0x0671, - 0x0671, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, // 180 - 184 - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, - 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0x0640, // 190 - 194 - 0x0640 -}; - -/**************************************************************************** -* TABLE 14: WP60 to Unicode - Arabic Script -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_WPUNI14[] = { - 0xF8B6, 0xF8B7, 0xF8B8, 0xF8B9, 0xF8BA, // 0 - 4 - 0xF8BB, 0xF8BC, 0xF8BD, 0xF8BE, 0xF8BF, - 0xF8C0, 0xF8C1, 0xF8C2, 0xF8C3, 0xF8C4, // 10 - 14 - 0xF8C5, 0xF8C6, 0xF8C7, 0xF8C8, 0xF8C9, - 0xF8CA, 0xF8CB, 0xF8CC, 0xF8CD, 0xF8CE, // 20 - 24 - 0xF8CF, 0xF8D0, 0x064E, 0x0652, 0xF8D3, - 0xF8D4, 0xF8D5, 0xF8D6, 0xF8D7, 0xF8D8, // 30 - 34 - 0xF8D9, 0x0674, 0x064C, 0xF8B2, 0xF8DB, - 0xF8DC, 0x06F4, 0x06F4, 0x06F5, 0x06F6, // 40 - 44 - 0x06F6, 0x06F7, 0x06F8, 0x067B, 0x067B, - 0x067B, 0x067B, 0x0680, 0x0680, 0x0680, // 50 - 54 - 0x0680, 0x067E, 0x067E, 0x067E, 0x067E, - 0x0679, 0x0679, 0x0679, 0x0679, 0x067C, // 60 - 64 - 0x067C, 0x067C, 0x067C, 0x067F, 0x067F, - 0x067F, 0x067F, 0x067D, 0x067D, 0x067D, // 70 - 74 - 0x067D, 0x067A, 0x067A, 0x067A, 0x067A, - 0x0684, 0x0684, 0x0684, 0x0684, 0x0683, // 80 - 84 - 0x0683, 0x0683, 0x0683, 0x0686, 0x0686, - 0x0686, 0x0686, 0x0687, 0x0687, 0x0687, // 90 - 94 - 0x0687, 0x0685, 0x0685, 0x0685, 0x0685, - 0x0681, 0x0681, 0x0681, 0x0681, 0x0688, // 100 - 104 - 0x0688, 0x0689, 0x0689, 0x068C, 0x068C, - 0x068E, 0x068E, 0x068A, 0x068A, 0x068D, // 110 - 114 - 0x068D, 0x0693, 0x0693, 0x0691, 0x0691, - 0x0699, 0x0699, 0x0695, 0x0695, 0x0692, // 120 - 124 - 0x0692, 0x0698, 0x0698, 0x0696, 0x0696, - 0x0696, 0x0696, 0x069A, 0x069A, 0x069A, // 130 - 134 - 0x069A, 0x06A0, 0x06A0, 0x06A0, 0x06A0, - 0x06A4, 0x06A4, 0x06A4, 0x06A4, 0x06A6, // 140 - 144 - 0x06A6, 0x06A6, 0x06A6, 0x06A9, 0x06A9, - 0x06A9, 0x06A9, 0x06A9, 0x06A9, 0x06A9, // 150 - 154 - 0x06A9, 0x06AA, 0x06AA, 0x06AA, 0x06AA, - 0x06AF, 0x06AF, 0x06AF, 0x06AF, 0x06AF, // 160 - 164 - 0x06AF, 0x06AF, 0x06AF, 0x06AB, 0x06AB, - 0x06AB, 0x06AB, 0x06B1, 0x06B1, 0x06B1, // 170 - 174 - 0x06B1, 0x06B3, 0x06B3, 0x06B3, 0x06B3, - 0x06B5, 0x06B5, 0x06B5, 0x06B5, 0x0000, // 180 - 184 - 0x0000, 0x06BA, 0x06BA, 0x06BA, 0x06BA, - 0x06BC, 0x06BC, 0x06BC, 0x06BC, 0x06BB, // 190 - 194 - 0x06BB, 0x06BB, 0x06BB, 0x06C6, 0x06C6, - 0x06CA, 0x06CA, 0x06CA, 0x06CA, 0x0647, // 200 - 204 - 0x0647, 0x0647, 0x0647, 0x06CE, 0x06CE, - 0x06CE, 0x06CE, 0x06D2, 0x06D2, 0x06D1, // 210 - 214 - 0x06D1, 0x06D1, 0x06D1, 0x06C0, 0x06C0 -}; - -/**************************************************************************** -* WP60 to Unicode - Complex Character Unit Table Multinational 1 -* -* High-order byte: Unicode Character Set -* Low-order byte: Unicode Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_CPXTAB1[][5] = { - { 0x0044, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0063, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x004C, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x006C, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x004E, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x006E, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0052, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0072, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0053, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0073, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0054, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0074, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0059, 0x0306, 0x0000, 0x0000, 0x0000 }, - { 0x0079, 0x0306, 0x0000, 0x0000, 0x0000 }, - { 0x0059, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0079, 0x0300, 0x0000, 0x0000, 0x0000 } -}; - -/**************************************************************************** -* WP60 to Unicode - Complex Character Unit Table 8 -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_CPXGREEK[][5] = { -/* 8,92 */ { 0x0020, 0x0313, 0x0301, 0x0000, 0x0000 }, -/* 8,93 */ { 0x0020, 0x0314, 0x0301, 0x0000, 0x0000 }, -/* 8,94 */ { 0x0020, 0x0313, 0x0300, 0x0000, 0x0000 }, -/* 8,95 */ { 0x0020, 0x0314, 0x0300, 0x0000, 0x0000 }, -/* 8,96 */ { 0x0020, 0x0313, 0x0302, 0x0000, 0x0000 }, -/* 8,97 */ { 0x0020, 0x0314, 0x0302, 0x0000, 0x0000 }, -/* 8,98 */ { 0x0020, 0x0345, 0x0301, 0x0000, 0x0000 }, -/* 8,99 */ { 0x0020, 0x0345, 0x0300, 0x0000, 0x0000 }, -/* 8,100 */ { 0x0020, 0x0345, 0x0302, 0x0000, 0x0000 }, -/* 8,101 */ { 0x0020, 0x0313, 0x0345, 0x0000, 0x0000 }, -/* 8,102 */ { 0x0020, 0x0314, 0x0345, 0x0000, 0x0000 }, -/* 8,103 */ { 0x0020, 0x0313, 0x0301, 0x0345, 0x0000 }, -/* 8,104 */ { 0x0020, 0x0314, 0x0301, 0x0345, 0x0000 }, -/* 8,105 */ { 0x0020, 0x0313, 0x0300, 0x0345, 0x0000 }, -/* 8,106 */ { 0x0020, 0x0314, 0x0300, 0x0345, 0x0000 }, -/* 8,107 */ { 0x0020, 0x0313, 0x0302, 0x0345, 0x0000 }, -/* 8,108 */ { 0x0020, 0x0302, 0x0345, 0x0314, 0x0000 }, -/* 8,109 */ { 0x03B1, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,110 */ { 0x03B1, 0x0302, 0x0000, 0x0000, 0x0000 }, -/* 8,111 */ { 0x03B1, 0x0345, 0x0000, 0x0000, 0x0000 }, -/* 8,112 */ { 0x03B1, 0x0301, 0x0345, 0x0000, 0x0000 }, -/* 8,114 */ { 0x03B1, 0x0302, 0x0345, 0x0000, 0x0000 }, -/* 8,115 */ { 0x03B1, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,116 */ { 0x03B1, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,117 */ { 0x03B1, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,118 */ { 0x03B1, 0x0302, 0x0313, 0x0000, 0x0000 }, -/* 8,119 */ { 0x03B1, 0x0345, 0x0313, 0x0000, 0x0000 }, -/* 8,120 */ { 0x03B1, 0x0301, 0x0345, 0x0313, 0x0000 }, -/* 8,122 */ { 0x03B1, 0x0302, 0x0345, 0x0313, 0x0000 }, -/* 8,123 */ { 0x03B1, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,124 */ { 0x03B1, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,125 */ { 0x03B1, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,126 */ { 0x03B1, 0x0302, 0x0314, 0x0000, 0x0000 }, -/* 8,127 */ { 0x03B1, 0x0345, 0x0314, 0x0000, 0x0000 }, -/* 8,128 */ { 0x03B1, 0x0301, 0x0345, 0x0314, 0x0000 }, -/* 8,130 */ { 0x03B1, 0x0302, 0x0345, 0x0314, 0x0000 }, -/* 8,131 */ { 0x03B5, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,132 */ { 0x03B5, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,133 */ { 0x03B5, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,134 */ { 0x03B5, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,135 */ { 0x03B5, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,136 */ { 0x03B5, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,137 */ { 0x03B5, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,138 */ { 0x03B7, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,139 */ { 0x03B7, 0x0310, 0x0000, 0x0000, 0x0000 }, -/* 8,140 */ { 0x03B7, 0x0345, 0x0000, 0x0000, 0x0000 }, -/* 8,141 */ { 0x03B7, 0x0301, 0x0345, 0x0000, 0x0000 }, -/* 8,142 */ { 0x03B7, 0x0300, 0x0345, 0x0000, 0x0000 }, -/* 8,143 */ { 0x03B7, 0x0302, 0x0345, 0x0000, 0x0000 }, -/* 8,144 */ { 0x03B7, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,145 */ { 0x03B7, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,146 */ { 0x03B7, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,147 */ { 0x03B7, 0x0302, 0x0313, 0x0000, 0x0000 }, -/* 8,148 */ { 0x03B7, 0x0345, 0x0313, 0x0000, 0x0000 }, -/* 8,149 */ { 0x03B7, 0x0301, 0x0345, 0x0313, 0x0000 }, -/* 8,151 */ { 0x03B7, 0x0302, 0x0345, 0x0313, 0x0000 }, -/* 8,152 */ { 0x03B7, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,153 */ { 0x03B7, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,154 */ { 0x03B7, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,155 */ { 0x03B7, 0x0302, 0x0314, 0x0000, 0x0000 }, -/* 8,156 */ { 0x03B7, 0x0345, 0x0314, 0x0000, 0x0000 }, -/* 8,157 */ { 0x03B7, 0x0301, 0x0345, 0x0314, 0x0000 }, -/* 8,159 */ { 0x03B7, 0x0302, 0x0345, 0x0314, 0x0000 }, -/* 8,160 */ { 0x03B9, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,161 */ { 0x03B9, 0x0302, 0x0000, 0x0000, 0x0000 }, -/* 8,162 */ { 0x03B9, 0x0308, 0x0301, 0x0000, 0x0000 }, -/* 8,163 */ { 0x03B9, 0x0308, 0x0300, 0x0000, 0x0000 }, -/* 8,164 */ { 0x03B9, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,165 */ { 0x03B9, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,166 */ { 0x03B9, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,167 */ { 0x03B9, 0x0302, 0x0313, 0x0000, 0x0000 }, -/* 8,168 */ { 0x03B9, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,169 */ { 0x03B9, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,170 */ { 0x03B9, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,171 */ { 0x03B9, 0x0302, 0x0314, 0x0000, 0x0000 }, -/* 8,172 */ { 0x03BF, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,173 */ { 0x03BF, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,174 */ { 0x03BF, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,175 */ { 0x03BF, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,176 */ { 0x03BF, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,177 */ { 0x03BF, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,178 */ { 0x03BF, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,181 */ { 0x03C5, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,182 */ { 0x03C5, 0x0302, 0x0000, 0x0000, 0x0000 }, -/* 8,183 */ { 0x03C5, 0x0308, 0x0301, 0x0000, 0x0000 }, -/* 8,184 */ { 0x03C5, 0x0308, 0x0300, 0x0000, 0x0000 }, -/* 8,185 */ { 0x03C5, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,186 */ { 0x03C5, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,187 */ { 0x03C5, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,188 */ { 0x03C5, 0x0302, 0x0313, 0x0000, 0x0000 }, -/* 8,189 */ { 0x03C5, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,190 */ { 0x03C5, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,191 */ { 0x03C5, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,192 */ { 0x03C5, 0x0302, 0x0314, 0x0000, 0x0000 }, -/* 8,193 */ { 0x03C9, 0x0300, 0x0000, 0x0000, 0x0000 }, -/* 8,194 */ { 0x03C9, 0x0302, 0x0000, 0x0000, 0x0000 }, -/* 8,195 */ { 0x03C9, 0x0345, 0x0000, 0x0000, 0x0000 }, -/* 8,196 */ { 0x03C9, 0x0301, 0x0345, 0x0000, 0x0000 }, -/* 8,197 */ { 0x03C9, 0x0300, 0x0345, 0x0000, 0x0000 }, -/* 8,198 */ { 0x03C9, 0x0302, 0x0345, 0x0000, 0x0000 }, -/* 8,199 */ { 0x03C9, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,200 */ { 0x03C9, 0x0301, 0x0313, 0x0000, 0x0000 }, -/* 8,201 */ { 0x03C9, 0x0300, 0x0313, 0x0000, 0x0000 }, -/* 8,202 */ { 0x03C9, 0x0302, 0x0313, 0x0000, 0x0000 }, -/* 8,203 */ { 0x03C9, 0x0345, 0x0313, 0x0000, 0x0000 }, -/* 8,204 */ { 0x03C9, 0x0301, 0x0345, 0x0313, 0x0000 }, -/* 8,206 */ { 0x03C9, 0x0302, 0x0345, 0x0313, 0x0000 }, -/* 8,207 */ { 0x03C9, 0x0314, 0x0000, 0x0000, 0x0000 }, -/* 8,208 */ { 0x03C9, 0x0301, 0x0314, 0x0000, 0x0000 }, -/* 8,209 */ { 0x03C9, 0x0300, 0x0314, 0x0000, 0x0000 }, -/* 8,210 */ { 0x03C9, 0x0302, 0x0314, 0x0000, 0x0000 }, -/* 8,211 */ { 0x03C9, 0x0345, 0x0314, 0x0000, 0x0000 }, -/* 8,212 */ { 0x03C9, 0x0301, 0x0345, 0x0314, 0x0000 }, -/* 8,214 */ { 0x03C9, 0x0302, 0x0345, 0x0314, 0x0000 }, -/* 8,52 */ { 0x0391, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,54 */ { 0x0395, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,56 */ { 0x0397, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,58 */ { 0x0399, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,62 */ { 0x039F, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,64 */ { 0x03A5, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,68 */ { 0x03A9, 0x0301, 0x0000, 0x0000, 0x0000 }, -/* 8,179 */ { 0x03C1, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,113 */ { 0x03B1, 0x0300, 0x0345, 0x0000, 0x0000 }, -/* 8,121 */ { 0x03B1, 0x0300, 0x0313, 0x0345, 0x0000 }, -/* 8,129 */ { 0x03B1, 0x0300, 0x0314, 0x0345, 0x0000 }, -/* 8,150 */ { 0x03B7, 0x0300, 0x0313, 0x0345, 0x0000 }, -/* 8,158 */ { 0x03B7, 0x0300, 0x0314, 0x0345, 0x0000 }, -/* 8,180 */ { 0x03C1, 0x0313, 0x0000, 0x0000, 0x0000 }, -/* 8,205 */ { 0x03C9, 0x0300, 0x0313, 0x0345, 0x0000 }, -/* 8,213 */ { 0x03C9, 0x0300, 0x0314, 0x0345, 0x0000 }, -/* 8,85 */ { 0x0020, 0x0301, 0x0308, 0x0000, 0x0000 }, -/* 8,86 */ { 0x0020, 0x0300, 0x0308, 0x0000, 0x0000 } -/* ** NOT in Use Converted to New Unicode Characters */ -}; - -/**************************************************************************** -* WP60 to Unicode - Complex Character Unit Table - Hebrew -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_CPXHEBREW[][5] = { -/* 9,52 */ { 0x05F2, 0x05B7, 0x0000, 0x0000, 0x0000 }, -/* 9,84 */ { 0x05D0, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,85 */ { 0x05D1, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,87 */ { 0x05D2, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,88 */ { 0x05D3, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,89 */ { 0x05D4, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,90 */ { 0x05D5, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,91 */ { 0x05D5, 0x05B9, 0x0000, 0x0000, 0x0000 }, -/* 9,92 */ { 0x05D6, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,93 */ { 0x05D7, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,94 */ { 0x05D8, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,95 */ { 0x05D9, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,96 */ { 0x05D9, 0x05B4, 0x0000, 0x0000, 0x0000 }, -/* 9,97 */ { 0x05DB, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,98 */ { 0x05DA, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,99 */ { 0x05DA, 0x05B0, 0x0000, 0x0000, 0x0000 }, -/* 9,100 */ { 0x05DA, 0x05B5, 0x0000, 0x0000, 0x0000 }, -/* 9,101 */ { 0x05DA, 0x05B1, 0x0000, 0x0000, 0x0000 }, -/* 9,102 */ { 0x05DA, 0x05B7, 0x0000, 0x0000, 0x0000 }, -/* 9,103 */ { 0x05DA, 0x05B8, 0x0000, 0x0000, 0x0000 }, -/* 9,104 */ { 0x05DA, 0x05BC, 0x05B8, 0x0000, 0x0000 }, -/* 9,105 */ { 0x05DC, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,106 */ { 0x05DE, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,107 */ { 0x05E0, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,108 */ { 0x05DF, 0x05B8, 0x0000, 0x0000, 0x0000 }, -/* 9,109 */ { 0x05E1, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,110 */ { 0x05E4, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,112 */ { 0x05E6, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,113 */ { 0x05E7, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,114 */ { 0x05E9, 0x05B9, 0x0000, 0x0000, 0x0000 }, -/* 9,115 */ { 0x05E9, 0x05B9, 0x05BC, 0x0000, 0x0000 }, -/* 9,117 */ { 0x05E9, 0x05BC, 0x0000, 0x0000, 0x0000 }, -/* 9,118 */ { 0x05EA, 0x05BC, 0x0000, 0x0000, 0x0000 } -}; - -/**************************************************************************** -* WP60 to Unicode - Complex Character Unit Table - Arabic -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_CPXARABIC[][5] = { - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } -}; - -/**************************************************************************** -* WP60 to Unicode - Complex Character Unit Table - Arabic Script -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -****************************************************************************/ - -FLMUINT16 WPCH_CPXARABIC2[][5] = { - { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 } -}; - -/***************************************************************************** -* WP60 to Unicode - Complex Character Unit Table - Cyrillic / Georgian -* -* High-order byte: WP Character Set # -* Low-order byte: WP Character -* Offset: 0 -*****************************************************************************/ - -FLMUINT16 WPCH_CPXCYRILLIC[][5] = { - { 0x0410, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0430, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0415, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0435, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0404, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0454, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0418, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0438, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0406, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0456, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0407, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0457, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x041E, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x043E, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0423, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0443, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x042B, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x044B, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x042D, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x044D, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x042E, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x044E, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x042F, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x044F, 0x0301, 0x0000, 0x0000, 0x0000 }, - { 0x0410, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0430, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0415, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0435, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0401, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0451, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0418, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0438, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x041E, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x043E, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0423, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x0443, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x042B, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x044B, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x042D, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x044D, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x042E, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x044E, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x042F, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x044F, 0x0300, 0x0000, 0x0000, 0x0000 }, - { 0x10E3, 0x0302, 0x0000, 0x0000, 0x0000 }, - { 0x0037, 0x0339, 0x0000, 0x0000, 0x0000 }, - { 0x0428, 0x0329, 0x0000, 0x0000, 0x0000 }, - { 0x0448, 0x0329, 0x0000, 0x0000, 0x0000 }, - { 0x0406, 0x031C, 0x0000, 0x0000, 0x0000 }, - { 0x0446, 0x031C, 0x0000, 0x0000, 0x0000 }, - { 0x0418, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x0438, 0x0304, 0x0000, 0x0000, 0x0000 }, - { 0x041A, 0x0328, 0x0000, 0x0000, 0x0000 }, - { 0x043A, 0x0328, 0x0000, 0x0000, 0x0000 }, - { 0x0425, 0x0328, 0x0000, 0x0000, 0x0000 }, - { 0x0445, 0x0328, 0x0000, 0x0000, 0x0000 }, - { 0x0428, 0x0329, 0x0000, 0x0000, 0x0000 }, - { 0x0448, 0x0329, 0x0000, 0x0000, 0x0000 } -}; - - diff --git a/flaim/src/fwpcoll.cpp b/flaim/src/fwpcoll.cpp deleted file mode 100644 index a3b8a6c..0000000 --- a/flaim/src/fwpcoll.cpp +++ /dev/null @@ -1,1784 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: WP collation tables. -// Tabs: 3 -// -// Copyright (c) 1991-2001,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: fwpcoll.cpp 12301 2006-01-19 15:02:55 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FLMUINT16 fwp_indexi[] = {0,11,14,15,17,18,19,21,22,23,24,25,26,35,59}; - -FLMUINT16 fwp_indexj[] = { - /** DOUBLE CHAR AREA - LANGUAGES */ -/*0*/ CA_LANG, /* Catalan */ - CF_LANG, /* Canadian French */ - CZ_LANG, /* Czech */ - SL_LANG, /* Slovak */ - DE_LANG, /* German */ - SD_LANG, /* Swiss German */ - ES_LANG, /* Spanish (Spain) */ - FR_LANG, /* French */ - _NL_LANG, /* Netherlands */ - 0xFFFF, /* DK_LANG, Danish - support for 'aa' -> a-ring out */ - 0xFFFF, /* NO_LANG, Norwegian - support for 'aa' -> a-ring out */ -/*11*/0x0063, /* c */ /* DOUBLE CHARACTERS - STATE ENTRIES */ - 0x006c, /* l */ - 0x0197, /* l with center dot */ -/*14*/0x0063, /* c */ -/*15*/0x0125, /* ae digraph */ - 0x01a7, /* oe digraph */ -/*17*/0x0068, /* h */ -/*18*/0x0068, /* h */ -/*19*/0x006c, /* l */ - 0x0101, /* center dot alone */ -/*21*/0x006c, /* l */ -/*22*/0x0117, /* á (for German) */ -/*23*/0x018b, /* ij digraph */ - 0x0000, /* was 'a' - will no longer map 'aa' to a-ring */ - 0x0000, /* was 'a' */ - -/*26*/CZ_LANG, /* SINGLE CHARS - LANGUAGES */ - DK_LANG, - NO_LANG, - SL_LANG, - TK_LANG, - SU_LANG, - IS_LANG, - SV_LANG, - YK_LANG, - /* SINGLE CHARS */ -/*35*/0x011e, /* A Diaeresis */ /* alternate collating sequences */ - 0x011f, /* a Diaeresis */ - 0x0122, /* A Ring */ /* 2 */ - 0x0123, /* a Ring */ - 0x0124, /* AE Diagraph */ /* 4 */ - 0x0125, /* ae diagraph */ - 0x013e, /* O Diaeresis */ /* 6 */ - 0x013f, /* o Diaeresis */ - 0x0146, /* U Diaeresis */ /* 8 */ - 0x0147, /* u Diaeresis */ - 0x0150, /* O Slash */ /* 10 */ - 0x0151, /* o Slash */ - - 0x0A3a, /* CYRILLIC SOFT SIGN */ /* 12 */ - 0x0A3b, /* CYRILLIC soft sign */ - 0x01ee, /* dotless i - turkish */ /* 14 */ -/*50*/0x01ef, /* dotless I - turkish */ - 0x0162, /* C Hacek/caron - 1,98 */ /* 16 */ - 0x0163, /* c Hacek/caron - 1,99 */ - 0x01aa, /* R Hacek/caron - 1,170*/ /* 18 */ - 0x01ab, /* r Hacek/caron - 1,171*/ - 0x01b0, /* S Hacek/caron - 1,176*/ /* 20 */ - 0x01b1, /* s Hacek/caron - 1,177*/ - 0x01ce, /* Z Hacek/caron - 1,206*/ /* 22 */ -/*58*/0x01cf, /* z Hacek/caron - 1,207*/ - }; - - -FLMUINT16 fwp_valuea[] = { -/*00*/STATE1, /* DOUBLE CHAR STATE VALUES */ - STATE3, - STATE2, - STATE2, - STATE8, - STATE8, - STATE1, - STATE3, - STATE9, - STATE10, /* No longer in use */ -/*10*/STATE10, /* No longer in use */ - STATE4, - STATE6, - STATE6, - STATE5, - INSTAE, - INSTOE, - AFTERC, - AFTERH, - AFTERL, -/*20*/STATE7, - STATE6, - INSTSG, /* ss for German */ - INSTIJ, - STATE11, /* aa - no longer in use */ - WITHAA, /* aa - no longer in use */ - /* SINGLE CHARS - LANGUAGES */ -/*26*/START_CZ, /* Czech */ - START_DK, /* Danish */ - START_NO, /* Norwegian */ - START_SL, /* Slovak */ - START_TK, /* Turkish */ - START_SU, /* Finnish */ - START_IS, /* Icelandic */ - START_SV, /* Swedish */ - START_YK, /* Ukrainian */ - /* SINGLE CHARS FIXUP AREAS */ -/*35*/COLS9, COLS9, COLS9, COLS9, /* US & OTHERS */ - COLS9+1, COLS9+1, COLS9+21, COLS9+21, - COLS9+30, COLS9+30, COLS9+21, COLS9+21, - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9+45, COLS9+45, COLS9+55, COLS9+55, /* DANISH */ - COLS9+42, COLS9+42, COLS9+53, COLS9+53, - COLS9+30, COLS9+30, COLS9+49, COLS9+49, /* Oct98 U Diaer no longer to y Diaer */ - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9, COLS9, COLS9, COLS9, /* Icelandic */ - COLS9+46, COLS9+46, COLS9+50, COLS9+50, - COLS9+30, COLS9+30, COLS9+54, COLS9+54, - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9, COLS9, COLS9+51, COLS9+51, /* Norwegian */ - COLS9+43, COLS9+43, COLS9+21, COLS9+21, - COLS9+30, COLS9+30, COLS9+47, COLS9+47, - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9+48, COLS9+48, COLS9+44, COLS9+44, /* Finnish/Swedish*/ - COLS9+1, COLS9+1, COLS9+52, COLS9+52, - COLS9+30, COLS9+30, COLS9+21, COLS9+21, /* Oct98 U Diaer no longer to y Diaer */ - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9, COLS9, COLS9, COLS9, /* Ukrain */ - COLS9+1, COLS9+1, COLS9+21, COLS9+21, - COLS9+30, COLS9+30, COLS9+21, COLS9+21, - COLS10+48, COLS10+48, COLS9+12, COLS9+12, - COLS9+3, COLS9+3, COLS9+25, COLS9+25, - COLS9+27, COLS9+27, COLS9+35, COLS9+35, - - COLS9, COLS9, COLS9, COLS9, /* Turkish */ - COLS9+1, COLS9+1, COLS9+21, COLS9+21, - COLS9+30, COLS9+30, COLS9+21, COLS9+21, - COLS9+43, COLS9+43, COLS9+11, COLS9+11, /* dotless i same as */ - COLS9+3, COLS9+3, COLS9+25, COLS9+25, /* the "CH" in Czech */ - COLS9+27, COLS9+27, COLS9+35, COLS9+35, /* works because char*/ - /* fails brkcar() */ - - COLS9, COLS9, COLS9, COLS9, /* Czech / Slovak */ - COLS9+1, COLS9+1, COLS9+21, COLS9+21, - COLS9+30, COLS9+30, COLS9+21, COLS9+21, - COLS10+43, COLS10+43, COLS9+12, COLS9+12, - COLS9+5, COLS9+5, COLS9+26, COLS9+26, /* carons */ - COLS9+28, COLS9+28, COLS9+36, COLS9+36 - }; - -#define ASCTBLLEN 95 - -FLMBYTE fwp_asc60Tbl[ASCTBLLEN+2] = { - 0x20, /* initial character offset!! */ - ASCTBLLEN, /* len of this table */ - COLLS, /* */ - COLLS+5, /* ! */ - COLS1, /* " */ - COLS6+1, /* # */ - COLS3, /* $ */ - COLS6, /* % */ - COLS6+2, /* & */ - COLS1+1, /* ' */ - COLS2, /* ( */ - COLS2+1, /* ) */ - COLS4+2, /* * */ - COLS4, /* + */ - COLLS+2, /* , */ - COLS4+1, /* - */ - COLLS+1, /* . */ - COLS4+3, /* / */ - COLS8, /* 0 */ - COLS8+1, /* 1 */ - COLS8+2, /* 2 */ - COLS8+3, /* 3 */ - COLS8+4, /* 4 */ - COLS8+5, /* 5 */ - COLS8+6, /* 6 */ - COLS8+7, /* 7 */ - COLS8+8, /* 8 */ - COLS8+9, /* 9 */ - COLLS+3, /* : */ - COLLS+4, /* ; */ - COLS5, /* < */ - COLS5+2, /* = */ - COLS5+4, /* > */ - COLLS+7, /* ? */ - COLS6+3, /* @ */ - COLS9, /* A */ -/*COLS9+1 Holder for AE digraph */ - COLS9+2, /* B */ - COLS9+3, /* C */ -/*cols9+4 CH in spanish */ -/*cols9+5 Holder for C caron in Czech */ - COLS9+6, /* D */ - COLS9+7, /* E */ - COLS9+8, /* F */ - COLS9+9, /* G */ - COLS9+10, /* H */ -/*cols9+11 CH in czech */ - COLS9+12, /* I */ -/*cols9+13 Holder for IJ digraph */ - COLS9+14, /* J */ - COLS9+15, /* K */ - COLS9+16, /* L */ -/*cols9+17 LL in spanish */ - COLS9+18, /* M */ - COLS9+19, /* N */ -/*cols9+20 ¥ */ - COLS9+21, /* O */ -/*cols9+22 Holder for OE digraph */ - COLS9+23, /* P */ - COLS9+24, /* Q */ - COLS9+25, /* R */ -/*cols9+26 Holder for R caron in Czech */ - COLS9+27, /* S */ -/*cols9+28 Holder for S caron in Czech */ - COLS9+29, /* T */ - COLS9+30, /* U */ - COLS9+31, /* V */ - COLS9+32, /* W */ - COLS9+33, /* X */ - COLS9+34, /* Y */ - COLS9+35, /* Z */ -/*cols9+36 Holder for Z caron in Czech */ - COLS9+40, /* [ (note: alphabetic - end of list) */ - COLS6+4, /* \ */ - COLS9+41, /* ] (note: alphabetic - end of list) */ - COLS4+4, /* ^ */ - COLS6+5, /* _ */ - COLS1+2, /* ` */ - COLS9, /* a */ -/*cols9+1 Holder for ae digraph */ - COLS9+2, /* b */ - COLS9+3, /* c */ -/*cols9+4 ch in spanish */ -/*cols9+5 Holder for c caron in Czech */ - COLS9+6, /* d */ - COLS9+7, /* e */ - COLS9+8, /* f */ - COLS9+9, /* g */ - COLS9+10, /* h */ -/*cols9+11 ch in czech */ - COLS9+12, /* i */ -/*cols9+13 Holder for ij digraph */ - COLS9+14, /* j */ - COLS9+15, /* k */ - COLS9+16, /* l */ -/*cols9+17 ll in spanish */ - COLS9+18, /* m */ - COLS9+19, /* n */ -/*cols9+20 ¥ */ - COLS9+21, /* o */ -/*cols9+22 Holder for oe digraph */ - COLS9+23, /* p */ - COLS9+24, /* q */ - COLS9+25, /* r */ -/*cols9+26 Holder for r caron in Czech */ - COLS9+27, /* s */ -/*cols9+28 Holder for s caron in Czech */ - COLS9+29, /* t */ - COLS9+30, /* u */ - COLS9+31, /* v */ - COLS9+32, /* w */ - COLS9+33, /* x */ - COLS9+34, /* y */ - COLS9+35, /* z */ -/*cols9+36 Holder for Z caron in Czech */ - COLS2+4, /* { */ - COLS6+6, /* | */ - COLS2+5, /* } */ - COLS6+7 /* ~ */ -}; - -#define MNTBLLEN 219 - -FLMBYTE fwp_mn60Tbl[MNTBLLEN+2] = { /* multinational table */ - 23, /* initial character offset!! */ - MNTBLLEN, /* len of this table */ - COLS9+27, /* German Double s */ - COLS9+15, /* Icelandic k */ - COLS9+14, /* Dotless j */ - -/* IBM Charset */ - - COLS9, /* A Acute */ - COLS9, /* a Acute */ - COLS9, /* A Circumflex */ - COLS9, /* a Circumflex */ - COLS9, /* A Diaeresis or Umlaut */ - COLS9, /* a Diaeresis or Umlaut */ - COLS9, /* A Grave */ - COLS9, /* a Grave */ - COLS9, /* A Ring */ - COLS9, /* a Ring */ - COLS9+1, /* AE digraph */ - COLS9+1, /* ae digraph */ - COLS9+3, /* C Cedilla */ - COLS9+3, /* c Cedilla */ - COLS9+7, /* E Acute */ - COLS9+7, /* e Acute */ - COLS9+7, /* E Circumflex */ - COLS9+7, /* e Circumflex */ - COLS9+7, /* E Diaeresis or Umlaut */ - COLS9+7, /* e Diaeresis or Umlaut */ - COLS9+7, /* E Grave */ - COLS9+7, /* e Grave */ - COLS9+12, /* I Acute */ - COLS9+12, /* i Acute */ - COLS9+12, /* I Circumflex */ - COLS9+12, /* i Circumflex */ - COLS9+12, /* I Diaeresis or Umlaut */ - COLS9+12, /* i Diaeresis or Umlaut */ - COLS9+12, /* I Grave */ - COLS9+12, /* i Grave */ - COLS9+20, /* N Tilde */ - COLS9+20, /* n Tilde */ - COLS9+21, /* O Acute */ - COLS9+21, /* o Acute */ - COLS9+21, /* O Circumflex */ - COLS9+21, /* o Circumflex */ - COLS9+21, /* O Diaeresis or Umlaut */ - COLS9+21, /* o Diaeresis or Umlaut */ - COLS9+21, /* O Grave */ - COLS9+21, /* o Grave */ - COLS9+30, /* U Acute */ - COLS9+30, /* u Acute */ - COLS9+30, /* U Circumflex */ - COLS9+30, /* u Circumflex */ - COLS9+30, /* U Diaeresis or Umlaut */ - COLS9+30, /* u Diaeresis or Umlaut */ - COLS9+30, /* U Grave */ - COLS9+30, /* u Grave */ - COLS9+34, /* Y Diaeresis or Umlaut */ - COLS9+34, /* y Diaeresis or Umlaut */ - -/* IBM foreign */ - - COLS9, /* A Tilde */ - COLS9, /* a Tilde */ - COLS9+6, /* D Cross Bar */ - COLS9+6, /* d Cross Bar */ - COLS9+21, /* O Slash */ - COLS9+21, /* o Slash */ - COLS9+21, /* O Tilde */ - COLS9+21, /* o Tilde */ - COLS9+34, /* Y Acute */ - COLS9+34, /* y Acute */ - COLS9+6, /* Uppercase Eth */ - COLS9+6, /* Lowercase Eth */ - COLS9+37, /* Uppercase Thorn */ - COLS9+37, /* Lowercase Thorn */ - -/* Teletex chars */ - - COLS9, /* A Breve */ - COLS9, /* a Breve */ - COLS9, /* A Macron */ - COLS9, /* a Macron */ - COLS9, /* A Ogonek */ - COLS9, /* a Ogonek */ - COLS9+3, /* C Acute */ - COLS9+3, /* c Acute */ - COLS9+3, /* C Caron or Hachek */ - COLS9+3, /* c Caron or Hachek */ - COLS9+3, /* C Circumflex */ - COLS9+3, /* c Circumflex */ - COLS9+3, /* C Dot Above */ - COLS9+3, /* c Dot Above */ - COLS9+6, /* D Caron or Hachek (Apostrophe Beside) */ - COLS9+6, /* d Caron or Hachek (Apostrophe Beside) */ - COLS9+7, /* E Caron or Hachek */ - COLS9+7, /* e Caron or Hachek */ - COLS9+7, /* E Dot Above */ - COLS9+7, /* e Dot Above */ - COLS9+7, /* E Macron */ - COLS9+7, /* e Macron */ - COLS9+7, /* E Ogonek */ - COLS9+7, /* e Ogonek */ - COLS9+9, /* G Acute */ - COLS9+9, /* g Acute */ - COLS9+9, /* G Breve */ - COLS9+9, /* g Breve */ - COLS9+9, /* G Caron or Hachek */ - COLS9+9, /* g Caron or Hachek */ - COLS9+9, /* G Cedilla (Apostrophe Under) */ - COLS9+9, /* g Cedilla (Apostrophe Over) */ - COLS9+9, /* G Circumflex */ - COLS9+9, /* g Circumflex */ - COLS9+9, /* G Dot Above */ - COLS9+9, /* g Dot Above */ - COLS9+10, /* H Circumflex */ - COLS9+10, /* h Circumflex */ - COLS9+10, /* H Cross Bar */ - COLS9+10, /* h Cross Bar */ - COLS9+12, /* I Dot Above (Sharp Accent) */ - COLS9+12, /* i Dot Above (Sharp Accent) */ - COLS9+12, /* I Macron */ - COLS9+12, /* i Macron */ - COLS9+12, /* I Ogonek */ - COLS9+12, /* i Ogonek */ - COLS9+12, /* I Tilde */ - COLS9+12, /* i Tilde */ - COLS9+13, /* IJ Digraph */ - COLS9+13, /* ij Digraph */ - COLS9+14, /* J Circumflex */ - COLS9+14, /* j Circumflex */ - COLS9+15, /* K Cedilla (Apostrophe Under) */ - COLS9+15, /* k Cedilla (Apostrophe Under) */ - COLS9+16, /* L Acute */ - COLS9+16, /* l Acute */ - COLS9+16, /* L Caron or Hachek (Apostrophe Beside) */ - COLS9+16, /* l Caron or Hachek (Apostrophe Beside) */ - COLS9+16, /* L Cedilla (Apostrophe Under) */ - COLS9+16, /* l Cedilla (Apostrophe Under) */ - COLS9+16, /* L Center Dot */ - COLS9+16, /* l Center Dot */ - COLS9+16, /* L Stroke */ - COLS9+16, /* l Stroke */ - COLS9+19, /* N Acute */ - COLS9+19, /* n Acute */ - COLS9+19, /* N Apostrophe */ - COLS9+19, /* n Apostrophe */ - COLS9+19, /* N Caron or Hachek */ - COLS9+19, /* n Caron or Hachek */ - COLS9+19, /* N Cedilla (Apostrophe Under) */ - COLS9+19, /* n Cedilla (Apostrophe Under) */ - COLS9+21, /* O Double Acute */ - COLS9+21, /* o Double Acute */ - COLS9+21, /* O Macron */ - COLS9+21, /* o Macron */ - COLS9+22, /* OE digraph */ - COLS9+22, /* oe digraph */ - COLS9+25, /* R Acute */ - COLS9+25, /* r Acute */ - COLS9+25, /* R Caron or Hachek */ - COLS9+25, /* r Caron or Hachek */ - COLS9+25, /* R Cedilla (Apostrophe Under) */ - COLS9+25, /* r Cedilla (Apostrophe Under) */ - COLS9+27, /* S Acute */ - COLS9+27, /* s Acute */ - COLS9+27, /* S Caron or Hachek */ - COLS9+27, /* s Caron or Hachek */ - COLS9+27, /* S Cedilla */ - COLS9+27, /* s Cedilla */ - COLS9+27, /* S Circumflex */ - COLS9+27, /* s Circumflex */ - COLS9+29, /* T Caron or Hachek (Apostrophe Beside) */ - COLS9+29, /* t Caron or Hachek (Apostrophe Beside) */ - COLS9+29, /* T Cedilla (Apostrophe Under) */ - COLS9+29, /* t Cedilla (Apostrophe Under) */ - COLS9+29, /* T Cross Bar */ - COLS9+29, /* t Cross Bar */ - COLS9+30, /* U Breve */ - COLS9+30, /* u Breve */ - COLS9+30, /* U Double Acute */ - COLS9+30, /* u Double Acute */ - COLS9+30, /* U Macron */ - COLS9+30, /* u Macron */ - COLS9+30, /* U Ogonek */ - COLS9+30, /* u Ogonek */ - COLS9+30, /* U Ring */ - COLS9+30, /* u Ring */ - COLS9+30, /* U Tilde */ - COLS9+30, /* u Tilde */ - COLS9+32, /* W Circumflex */ - COLS9+32, /* w Circumflex */ - COLS9+34, /* Y Circumflex */ - COLS9+34, /* y Circumflex */ - COLS9+35, /* Z Acute */ - COLS9+35, /* z Acute */ - COLS9+35, /* Z Caron or Hachek */ - COLS9+35, /* z Caron or Hachek */ - COLS9+35, /* Z Dot Above */ - COLS9+35, /* z Dot Above */ - COLS9+19, /* Uppercase Eng */ - COLS9+19, /* Lowercase Eng */ - -/* other */ - - COLS9+6, /* D Macron */ - COLS9+6, /* d Macron */ - COLS9+16, /* L Macron */ - COLS9+16, /* l Macron */ - COLS9+19, /* N Macron */ - COLS9+19, /* n Macron */ - COLS9+25, /* R Grave */ - COLS9+25, /* r Grave */ - COLS9+27, /* S Macron */ - COLS9+27, /* s Macron */ - COLS9+29, /* T Macron */ - COLS9+29, /* t Macron */ - COLS9+34, /* Y Breve */ - COLS9+34, /* y Breve */ - COLS9+34, /* Y Grave */ - COLS9+34, /* y Grave */ - COLS9+6, /* D Apostrophe Beside */ - COLS9+6, /* d Apostrophe Beside */ - COLS9+21, /* O Apostrophe Beside */ - COLS9+21, /* o Apostrophe Beside */ - COLS9+30, /* U Apostrophe Beside */ - COLS9+30, /* u Apostrophe Beside */ - COLS9+7, /* E breve */ - COLS9+7, /* e breve */ - COLS9+12, /* I breve */ - COLS9+12, /* i breve */ - COLS9+12, /* dotless I */ - COLS9+12, /* dotless i */ - COLS9+21, /* O breve */ - COLS9+21 /* o breve */ -}; - -#define SYMTBLLEN 9 - -FLMBYTE fwp_sym60Tbl[SYMTBLLEN+2] = { - 11, /* initial character offset!! */ - SYMTBLLEN, /* len of this table */ - COLS3+2, /* pound */ - COLS3+3, /* yen */ - COLS3+4, /* pacetes */ - COLS3+5, /* floren */ - COLS0, - COLS0, - COLS0, - COLS0, - COLS3+1, /* cent */ -}; - - -/**---------------------------------------------- -*** This is defined for the full greek table. -***---------------------------------------------*/ - -#define GRKTBLLEN 219 - -FLMBYTE fwp_grk60Tbl[GRKTBLLEN+2] = { - 0, /* starting offset */ - GRKTBLLEN, /* length */ - COLS7, /* Uppercase Alpha */ - COLS7, /* Lowercase Alpha */ - COLS7+1, /* Uppercase Beta */ - COLS7+1, /* Lowercase Beta */ - COLS7+1, /* Uppercase Beta Medial */ - COLS7+1, /* Lowercase Beta Medial */ - COLS7+2, /* Uppercase Gamma */ - COLS7+2, /* Lowercase Gamma */ - COLS7+3, /* Uppercase Delta */ - COLS7+3, /* Lowercase Delta */ - COLS7+4, /* Uppercase Epsilon */ - COLS7+4, /* Lowercase Epsilon */ - COLS7+5, /* Uppercase Zeta */ - COLS7+5, /* Lowercase Zeta */ - COLS7+6, /* Uppercase Eta */ - COLS7+6, /* Lowercase Eta */ - COLS7+7, /* Uppercase Theta */ - COLS7+7, /* Lowercase Theta */ - COLS7+8, /* Uppercase Iota */ - COLS7+8, /* Lowercase Iota */ - COLS7+9, /* Uppercase Kappa */ - COLS7+9, /* Lowercase Kappa */ - COLS7+10, /* Uppercase Lambda */ - COLS7+10, /* Lowercase Lambda */ - COLS7+11, /* Uppercase Mu */ - COLS7+11, /* Lowercase Mu */ - COLS7+12, /* Uppercase Nu */ - COLS7+12, /* Lowercase Nu */ - COLS7+13, /* Uppercase Xi */ - COLS7+13, /* Lowercase Xi */ - COLS7+14, /* Uppercase Omicron */ - COLS7+14, /* Lowercase Omicron */ - COLS7+15, /* Uppercase Pi */ - COLS7+15, /* Lowercase Pi */ - COLS7+16, /* Uppercase Rho */ - COLS7+16, /* Lowercase Rho */ - COLS7+17, /* Uppercase Sigma */ - COLS7+17, /* Lowercase Sigma */ - COLS7+17, /* Uppercase Sigma Terminal */ - COLS7+17, /* Lowercase Sigma Terminal */ - COLS7+18, /* Uppercase Tau */ - COLS7+18, /* Lowercase Tau */ - COLS7+19, /* Uppercase Upsilon */ - COLS7+19, /* Lowercase Upsilon */ - COLS7+20, /* Uppercase Phi */ - COLS7+20, /* Lowercase Phi */ - COLS7+21, /* Uppercase Chi */ - COLS7+21, /* Lowercase Chi */ - COLS7+22, /* Uppercase Psi */ - COLS7+22, /* Lowercase Psi */ - COLS7+23, /* Uppercase Omega */ - COLS7+23, /* Lowercase Omega */ - -/* Other Modern Greek Characters [8,52] */ - - COLS7, /* Uppercase ALPHA Tonos high prime */ - COLS7, /* Lowercase Alpha Tonos - acute */ - COLS7+4, /* Uppercase EPSILON Tonos - high prime */ - COLS7+4, /* Lowercase Epslion Tonos - acute */ - COLS7+6, /* Uppercase ETA Tonos - high prime */ - COLS7+6, /* Lowercase Eta Tonos - acute */ - COLS7+8, /* Uppercase IOTA Tonos - high prime */ - COLS7+8, /* Lowercase iota Tonos - acute */ - COLS7+8, /* Uppercase IOTA Diaeresis */ - COLS7+8, /* Lowercase iota diaeresis */ - COLS7+14, /* Uppercase OMICRON Tonos - high prime */ - COLS7+14, /* Lowercase Omicron Tonos - acute */ - COLS7+19, /* Uppercase UPSILON Tonos - high prime */ - COLS7+19, /* Lowercase Upsilon Tonos - acute */ - COLS7+19, /* Uppercase UPSILON Diaeresis */ - COLS7+19, /* Lowercase Upsilon diaeresis */ - COLS7+23, /* Uppercase OMEGA Tonos - high prime */ - COLS7+23, /* Lowercase Omega Tonso - acute */ - -/* Variants [8,70] */ - - COLS7+4, /* epsilon (variant) */ - COLS7+7, /* theta (variant) */ - COLS7+9, /* kappa (variant) */ - COLS7+15, /* pi (variant) */ - COLS7+16, /* rho (variant) */ - COLS7+17, /* sigma (variant) */ - COLS7+19, /* upsilon (variant) */ - COLS7+20, /* phi (variant) */ - COLS7+23, /* omega (variant) */ - -/* Greek Diacritic marks [8,79] */ - - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, - COLS0, /* 8,108 end of diacritic marks */ - -/* Ancient Greek [8,109] */ - - COLS7, /* alpha grave */ - COLS7, /* alpha circumflex */ - COLS7, /* alpha w/iota */ - COLS7, /* alpha acute w/iota */ - COLS7, /* alpha grave w/iota */ - COLS7, /* alpha circumflex w/Iota */ - COLS7, /* alpha smooth */ - COLS7, /* alpha smooth acute */ - COLS7, /* alpha smooth grave */ - COLS7, /* alpha smooth circumflex */ - COLS7, /* alpha smooth w/Iota */ - COLS7, /* alpha smooth acute w/Iota */ - COLS7, /* alpha smooth grave w/Iota */ - COLS7, /* alpha smooth circumflex w/Iota */ -/* [8,123] */ - COLS7, /* alpha rough */ - COLS7, /* alpha rough acute */ - COLS7, /* alpha rough grave */ - COLS7, /* alpha rough circumflex */ - COLS7, /* alpha rough w/Iota */ - COLS7, /* alpha rough acute w/Iota */ - COLS7, /* alpha rough grave w/Iota */ - COLS7, /* alpha rough circumflex w/Iota */ -/* [8,131] */ - COLS7+4, /* epsilon grave */ - COLS7+4, /* epsilon smooth */ - COLS7+4, /* epsilon smooth acute */ - COLS7+4, /* epsilon smooth grave */ - COLS7+4, /* epsilon rough */ - COLS7+4, /* epsilon rough acute */ - COLS7+4, /* epsilon rough grave */ -/* [8,138] */ - COLS7+6, /* eta grave */ - COLS7+6, /* eta circumflex */ - COLS7+6, /* eta w/iota */ - COLS7+6, /* eta acute w/iota */ - COLS7+6, /* eta grave w/Iota */ - COLS7+6, /* eta circumflex w/Iota */ - COLS7+6, /* eta smooth */ - COLS7+6, /* eta smooth acute */ - COLS7+6, /* eta smooth grave */ - COLS7+6, /* eta smooth circumflex */ - COLS7+6, /* eta smooth w/Iota */ - COLS7+6, /* eta smooth acute w/Iota */ - COLS7+6, /* eta smooth grave w/Iota */ - COLS7+6, /* eta smooth circumflex w/Iota */ - COLS7+6, /* eta rough */ - COLS7+6, /* eta rough acute */ - COLS7+6, /* eta rough grave */ - COLS7+6, /* eta rough circumflex */ - COLS7+6, /* eta rough w/Iota */ - COLS7+6, /* eta rough acute w/Iota */ - COLS7+6, /* eta rough grave w/Iota */ - COLS7+6, /* eta rough circumflex w/Iota */ -/* [8,160] */ - COLS7+8, /* iota grave */ - COLS7+8, /* iota circumflex */ - COLS7+8, /* iota acute diaeresis */ - COLS7+8, /* iota grave diaeresis */ - COLS7+8, /* iota smooth */ - COLS7+8, /* iota smooth acute */ - COLS7+8, /* iota smooth grave */ - COLS7+8, /* iota smooth circumflex */ - COLS7+8, /* iota rough */ - COLS7+8, /* iota rough acute */ - COLS7+8, /* iota rough grave */ - COLS7+8, /* iota rough circumflex */ -/* [8,172] */ - COLS7+14, /* omicron grave */ - COLS7+14, /* omicron smooth */ - COLS7+14, /* omicron smooth acute */ - COLS7+14, /* omicron smooth grave */ - COLS7+14, /* omicron rough */ - COLS7+14, /* omicron rough acute */ - COLS7+14, /* omicron rough grave */ -/* [8,179] */ - COLS7+16, /* rho smooth */ - COLS7+16, /* rho rough */ -/* [8,181] */ - COLS7+19, /* upsilon grave */ - COLS7+19, /* upsilon circumflex */ - COLS7+19, /* upsilon acute diaeresis */ - COLS7+19, /* upsilon grave diaeresis */ - COLS7+19, /* upsilon smooth */ - COLS7+19, /* upsilon smooth acute */ - COLS7+19, /* upsilon smooth grave */ - COLS7+19, /* upsilon smooth circumflex */ - COLS7+19, /* upsilon rough */ - COLS7+19, /* upsilon rough acute */ - COLS7+19, /* upsilon rough grave */ - COLS7+19, /* upsilon rough circumflex */ -/* [8,193] */ - COLS7+23, /* omega grave */ - COLS7+23, /* omega circumflex */ - COLS7+23, /* omega w/Iota */ - COLS7+23, /* omega acute w/Iota */ - COLS7+23, /* omega grave w/Iota */ - COLS7+23, /* omega circumflex w/Iota */ - COLS7+23, /* omega smooth */ - COLS7+23, /* omega smooth acute */ - COLS7+23, /* omega smooth grave */ - COLS7+23, /* omega smooth circumflex */ - COLS7+23, /* omega smooth w/Iota */ - COLS7+23, /* omega smooth acute w/Iota */ - COLS7+23, /* omega smooth grave w/Iota */ - COLS7+23, /* omega smooth circumflex w/Iota */ - COLS7+23, /* omega rough */ - COLS7+23, /* omega rough acute */ - COLS7+23, /* omega rough grave */ - COLS7+23, /* omega rough circumflex */ - COLS7+23, /* omega rough w/Iota */ - COLS7+23, /* omega rough acute w/Iota */ - COLS7+23, /* omega rough grave w/Iota */ - COLS7+23, /* omega rough circumflex w/Iota */ -/* [8,215] */ - COLS7+24, /* Uppercase Stigma--the number 6 */ - COLS7+24, /* Uppercase Digamma--Obsolete letter used as 6 */ - COLS7+24, /* Uppercase Koppa--Obsolete letter used as 90 */ - COLS7+24 /* Uppercase Sampi--Obsolete letter used as 900 */ -}; - -#define CYRLTBLLEN 200 - -FLMBYTE fwp_cyrl60Tbl[CYRLTBLLEN+2] = { - 0, /* starting offset */ - CYRLTBLLEN, /* len of table */ -/*00*/ - COLS10, /* Russian uppercase A */ - COLS10, /* Russian lowercase A */ - COLS10+1, /* Russian uppercase BE */ - COLS10+1, /* Russian lowercase BE */ - COLS10+2, /* Russian uppercase VE */ - COLS10+2, /* Russian lowercase VE */ - COLS10+3, /* Russian uppercase GHE */ - COLS10+3, /* Russian lowercase GHE */ - COLS10+5, /* Russian uppercase DE */ - COLS10+5, /* Russian lowercase DE */ -/*10*/ - COLS10+8, /* Russian uppercase E */ - COLS10+8, /* Russian lowercase E */ - COLS10+9, /* Russian lowercase YO */ - COLS10+9, /* Russian lowercase YO */ - COLS10+11, /* Russian uppercase ZHE */ - COLS10+11, /* Russian lowercase ZHE */ - COLS10+12, /* Russian uppercase ZE */ - COLS10+12, /* Russian lowercase ZE */ - COLS10+14, /* Russian uppercase I */ - COLS10+14, /* Russian lowercase I */ -/*20*/ - COLS10+17, /* Russian uppercase SHORT I */ - COLS10+17, /* Russian lowercase SHORT I */ - COLS10+19, /* Russian uppercase KA */ - COLS10+19, /* Russian lowercase KA */ - COLS10+20, /* Russian uppercase EL */ - COLS10+20, /* Russian lowercase EL */ - COLS10+22, /* Russian uppercase EM */ - COLS10+22, /* Russian lowercase EM */ - COLS10+23, /* Russian uppercase EN */ - COLS10+23, /* Russian lowercase EN */ -/*30*/ - COLS10+25, /* Russian uppercase O */ - COLS10+25, /* Russian lowercase O */ - COLS10+26, /* Russian uppercase PE */ - COLS10+26, /* Russian lowercase PE */ - COLS10+27, /* Russian uppercase ER */ - COLS10+27, /* Russian lowercase ER */ - COLS10+28, /* Russian uppercase ES */ - COLS10+28, /* Russian lowercase ES */ - COLS10+29, /* Russian uppercase TE */ - COLS10+29, /* Russian lowercase TE */ -/*40*/ - COLS10+32, /* Russian uppercase U */ - COLS10+32, /* Russian lowercase U */ - COLS10+34, /* Russian uppercase EF */ - COLS10+34, /* Russian lowercase EF */ - COLS10+35, /* Russian uppercase HA */ - COLS10+35, /* Russian lowercase HA */ - COLS10+36, /* Russian uppercase TSE */ - COLS10+36, /* Russian lowercase TSE */ - COLS10+37, /* Russian uppercase CHE */ - COLS10+37, /* Russian lowercase CHE */ -/*50*/ - COLS10+39, /* Russian uppercase SHA */ - COLS10+39, /* Russian lowercase SHA */ - COLS10+40, /* Russian uppercase SHCHA */ - COLS10+40, /* Russian lowercase SHCHA */ - COLS10+41, /* Russian lowercase ER (also hard sign) */ - COLS10+41, /* Russian lowercase ER (also hard sign) */ - COLS10+42, /* Russian lowercase ERY */ - COLS10+42, /* Russian lowercase ERY */ - COLS10+43, /* Russian lowercase SOFT SIGN */ - COLS10+43, /* Russian lowercase SOFT SIGN */ -/*60*/ - COLS10+45, /* Russian uppercase REVERSE E */ - COLS10+45, /* Russian lowercase REVERSE E */ - COLS10+46, /* Russian uppercase YU */ - COLS10+46, /* Russian lowercase yu */ - COLS10+47, /* Russian uppercase YA */ - COLS10+47, /* Russian lowercase ya */ -/*66*/ - COLS0, /* Russian uppercase EH */ - COLS0, /* Russian lowercase eh */ - COLS10+7, /* Macedonian uppercase SOFT DJ */ - COLS10+7, /* Macedonian lowercase soft dj */ -/*70*/ - COLS10+4, /* Ukrainian uppercase HARD G */ - COLS10+4, /* Ukrainian lowercase hard g */ - COLS0, /* GE bar */ - COLS0, /* ge bar */ - COLS10+6, /* Serbian uppercase SOFT DJ */ - COLS10+6, /* Serbian lowercase SOFT DJ */ - COLS0, /* IE (variant) */ - COLS0, /* ie (variant) */ - COLS10+10, /* Ukrainian uppercase YE */ - COLS10+10, /* Ukrainian lowercase YE */ -/*80*/ - COLS0, /* ZHE with right descender */ - COLS0, /* zhe with right descender */ - COLS10+13, /* Macedonian uppercase ZELO */ - COLS10+13, /* Macedonian lowercase ZELO */ - COLS0, /* Old Slovanic uppercase Z */ - COLS0, /* Old Slovanic uppercase z */ - COLS0, /* II with macron */ - COLS0, /* ii with mscron */ - COLS10+15, /* Ukrainian uppercase I */ - COLS10+15, /* Ukrainian lowercase I */ -/*90*/ - COLS10+16, /* Ukrainian uppercase I with Two Dots */ - COLS10+16, /* Ukrainian lowercase I with Two Dots */ - COLS0, /* Old Slovanic uppercase I ligature */ - COLS0, /* Old Slovanic lowercase I ligature */ - COLS10+18, /* Serbian--Macedonian uppercase JE */ - COLS10+18, /* Serbian--Macedonian lowercase JE */ - COLS10+31, /* Macedonian uppercase SOFT K */ - COLS10+31, /* Macedonian lowercase SOFT K */ - COLS0, /* KA with right descender */ - COLS0, /* ka with right descender */ -/*100*/ - COLS0, /* KA ogonek */ - COLS0, /* ka ogonek */ - COLS0, /* KA vertical bar */ - COLS0, /* ka vertical bar */ - COLS10+21, /* Serbian--Macedonian uppercase SOFT L */ - COLS10+21, /* Serbian--Macedonian lowercase SOFT L */ - COLS0, /* EN with right descender */ - COLS0, /* en with right descender */ - COLS10+24, /* Serbian--Macedonian uppercase SOFT N */ - COLS10+24, /* Serbian--Macedonian lowercase SOFT N */ -/*110*/ - COLS0, /* ROUND OMEGA */ - COLS0, /* round omega */ - COLS0, /* OMEGA */ - COLS0, /* omega */ - COLS10+30, /* Serbian uppercase SOFT T */ - COLS10+30, /* Serbian lowercase SOFT T */ - COLS10+33, /* Byelorussian uppercase SHORT U */ - COLS10+33, /* Byelorussian lowercase SHORT U */ - COLS0, /* U with macron */ - COLS0, /* u with macron */ -/*120*/ - COLS0, /* STRAIGHT U */ - COLS0, /* straight u */ - COLS0, /* STRAIGHT U bar */ - COLS0, /* straight u bar */ - COLS0, /* OU ligature */ - COLS0, /* ou ligature */ - COLS0, /* KHA with right descender */ - COLS0, /* kha with right descender */ - COLS0, /* KHA ogonek */ - COLS0, /* kha ogonek */ -/*130*/ - COLS0, /* H */ - COLS0, /* h */ - COLS0, /* OMEGA titlo */ - COLS0, /* omega titlo */ - COLS10+38, /* Serbian uppercase HARD DJ */ - COLS10+38, /* Serbian lowercase HARD DJ */ - COLS0, /* CHE with right descender */ - COLS0, /* che with right descender */ - COLS0, /* CHE vertical bar */ - COLS0, /* che vertical bar */ -/*140*/ - COLS0, /* Old Slavonic SHCHA (variant) */ - COLS0, /* old SLAVONIC shcha (variant) */ - COLS10+44, /* Old Russian uppercase YAT */ - COLS10+44, /* Old Russian lowercase YAT */ -/**---------------------------------------------- -*** END OF UNIQUE COLLATED BYTES -*** CHARACTERS BELOW MUST HAVE HAVE THEIR OWN -*** SUB-COLLATION VALUE TO COMPARE CORRECTLY. -***---------------------------------------------*/ - COLS0, /* Old Bulgarian uppercase YUS */ - COLS0, /* Old Bulgarian lowercase YUS */ - COLS0, /* Old Slovanic uppercase YUS MALYI */ - COLS0, /* Old Slovanic uppercase YUS MALYI */ - COLS0, /* KSI */ - COLS0, /* ksi */ -/*150*/ - COLS0, /* PSI */ - COLS0, /* psi */ - COLS0, /* Old Russian uppercase FITA */ - COLS0, /* Old Russian lowercase FITA */ - COLS0, /* Old Russian uppercase IZHITSA */ - COLS0, /* Old Russian lowercase IZHITSA */ - COLS0, /* Russian uppercase A acute */ - COLS0, /* Russian lowercase A acute */ - COLS10+8, /* Russian uppercase E acute */ - COLS10+8, /* Russian lowercase E acute */ - -/*160-below all characters are russian to 199*/ - COLS0, /* E acute */ - COLS0, /* e acute */ - COLS10+14, /* II acute */ - COLS10+14, /* ii acute */ - COLS0, /* I acute */ - COLS0, /* i acute */ - COLS0, /* YI acute */ - COLS0, /* yi acute */ - COLS10+25, /* O acute */ - COLS10+25, /* o acute */ -/*170*/ - COLS10+32, /* U acute */ - COLS10+32, /* u acute */ - COLS10+42, /* YERI acute */ - COLS10+42, /* YERI acute */ - COLS10+45, /* REVERSED E acute */ - COLS10+45, /* reversed e acute */ - COLS10+46, /* YU acute */ - COLS10+46, /* yu acute */ - COLS10+47, /* YA acute */ - COLS10+47, /* ya acute */ -/*180*/ - COLS10, /* A grave */ - COLS10, /* a grave */ - COLS10+8, /* E grave */ - COLS10+8, /* e grave */ - COLS10+9, /* YO grave */ - COLS10+9, /* yo grave */ - COLS10+14, /* I grave */ - COLS10+14, /* i grave */ - COLS10+25, /* O grave */ - COLS10+25, /* o grave */ -/*190*/ - COLS10+32, /* U grave */ - COLS10+32, /* u grave */ - COLS10+42, /* YERI grave */ - COLS10+42, /* yeri grave */ - COLS10+45, /* REVERSED E grave */ - COLS10+45, /* reversed e grave */ - COLS10+46, /* IU (YU) grave */ - COLS10+46, /* iu (yu) grave */ - COLS10+47, /* ia (YA) grave */ - COLS10+47, /* ia (ya) grave ******* [10,199] */ -/***----------------------------------------- -*** What follows is for documentation only -***-----------------------------------------*/ -/*200*/ /* Acute */ - /* Grave */ - /* Diaeresis */ - /* Breve */ - /* Right descender */ - /* ogonek */ - /* Macron */ - /* 207 - GEORGIAN CHARACTERS BELOW ***/ - /* Righ Quote Marks */ - /* Left Quote Marks */ -/*210*/ /* An */ - /* Ban */ - /* Gan */ - /* Don */ - /* En */ - /* Vin */ - /* Zen */ - /* He */ - /* Tan */ - /* In */ -/*220*/ /* Kan */ - /* Las */ - /* Man */ - /* Nar */ - /* Hie */ - /* On */ - /* Par */ - /* Zhar */ - /* Rae */ - /* San */ -/*230*/ /* Tar */ - /* Un */ - /* We */ - /* Phar */ - /* Khar */ - /* Ghan */ - /* Qar */ - /* Shin */ - /* Chin */ - /* Can */ -/*240*/ /* Jil */ - /* Cil */ - /* Char */ - /* Xan */ - /* Har */ - /* Jhan */ - /* Hae */ - /* Hoe */ - /* Fi */ - /* Un w/ Circumflex - 249 END */ -}; - - -/* The Hebrew characters are collated over the Russian characters */ -/* Therefore sorting both Hebrew and Russian is impossible to do. */ - -#define HEBTBL1LEN 27 - -/* #define HEBTBLLEN 119 27 in the first section */ - /* 57 in the accents section (wasted!)*/ - /* 35 in the ancient (dagesh) section */ - -FLMBYTE fwp_heb60TblA[HEBTBL1LEN+2] = { - 0, /* starting offset */ - HEBTBL1LEN, /* len of table */ - COLS10h+0, /* Alef */ - COLS10h+1, /* Bet */ - COLS10h+2, /* Gimel */ - COLS10h+3, /* Dalet */ - COLS10h+4, /* He */ - COLS10h+5, /* Vav */ - COLS10h+6, /* Zayin */ - COLS10h+7, /* Het */ - COLS10h+8, /* Tet */ - COLS10h+9, /* Yod */ - COLS10h+10, /* Kaf (final) [9,10] */ - COLS10h+11, /* Kaf */ - COLS10h+12, /* Lamed */ - COLS10h+13, /* Mem (final) */ - COLS10h+14, /* Mem */ - COLS10h+15, /* Nun (final) */ - COLS10h+16, /* Nun */ - COLS10h+17, /* Samekh */ - COLS10h+18, /* Ayin */ - COLS10h+19, /* Pe (final) */ - COLS10h+20, /* Pe [9,20] */ - COLS10h+21, /* Tsadi (final) */ - COLS10h+22, /* Tsadi */ - COLS10h+23, /* Qof */ - COLS10h+24, /* Resh */ - COLS10h+25, /* Shin */ - COLS10h+26 /* Tav [9,26] */ -}; - - /**------------------------------------------------------ - *** This is the ANCIENT HEBREW SCRIPT piece. - *** The actual value will be stored in the subcollation. - *** This way we don't play diacritic/subcollation games. - *** - ***-----------------------------------------------------*/ - -#define HEBTBL2LEN 35 - -FLMBYTE fwp_heb60TblB[HEBTBL2LEN+2] = { - 84, - HEBTBL2LEN, - -/*[9,84]*/ - COLS10h+0, /* Alef Dagesh [9,84] */ - COLS10h+1, /* Bet Dagesh */ - COLS10h+1, /* Vez - looks like a bet */ - COLS10h+2, /* Gimel Dagesh */ - COLS10h+3, /* Dalet Dagesh */ - COLS10h+4, /* He Dagesh */ - COLS10h+5, /* Vav Dagesh [9,90] */ - COLS10h+5, /* Vav Holem */ - COLS10h+6, /* Zayin Dagesh */ - COLS10h+7, /* Het Dagesh */ - COLS10h+8, /* Tet Dagesh */ - COLS10h+9, /* Yod Dagesh */ - COLS10h+9, /* Yod Hiriq [9,96] - not on my list */ - - COLS10h+11, /* Kaf Dagesh */ - COLS10h+10, /* Kaf Dagesh (final) */ - COLS10h+10, /* Kaf Sheva (final) */ - COLS10h+10, /* Kaf Tsere (final) [9,100] */ - COLS10h+10, /* Kaf Segol (final) */ - COLS10h+10, /* Kaf Patah (final) */ - COLS10h+10, /* Kaf Qamats (final) */ - COLS10h+10, /* Kaf Dagesh Qamats (final) */ - COLS10h+12, /* Lamed Dagesh */ - COLS10h+14, /* Mem Dagesh */ - COLS10h+16, /* Nun Dagesh */ - COLS10h+15, /* Nun Qamats (final) */ - COLS10h+17, /* Samekh Dagesh */ - COLS10h+20, /* Pe Dagesh [9,110] */ - COLS10h+20, /* Fe - just guessing this is like Pe - was +21 */ - COLS10h+22, /* Tsadi Dagesh */ - COLS10h+23, /* Qof Dagesh */ - COLS10h+25, /* Sin (with sin dot) */ - COLS10h+25, /* Sin Dagesh (with sin dot) */ - COLS10h+25, /* Shin */ - COLS10h+25, /* Shin Dagesh */ - COLS10h+26 /* Tav Dagesh [9,118] */ -}; - -/** The Arabic characters are collated OVER the Russian characters -*** Therefore sorting both Arabic and Russian in the same database -*** is not supported. -*** -*** Arabic starts with a bunch of accents/diacritic marks that are -*** Actually placed OVER a preceeding character. These accents are -*** ignored while sorting the first pass - when collation == COLS0. -*** -*** There are 4 possible states for all/most arabic characters: -*** ÚÙ - occurs as the only character in a word -*** ÄÙ - appears at the first of the word -*** ÄÄ - appears at the middle of a word -*** ÚÄ - appears at the end of the word -*** -*** Usually only the simple version of the letter is stored. -*** Therefore we should not have to worry about sub-collation -*** of these characters. -*** -*** The arabic characters with diacritics differ however. The alef has -*** sub-collation values to sort correctly. There is not any more room -*** to add more collation values. Some chars in CS14 are combined when -*** urdu, pashto and sindhi characters overlap. -*** -**/ - -#define AR1TBLLEN 158 /* (195 - 38 + 1) */ - -FLMBYTE fwp_ar160Tbl[AR1TBLLEN+2] = { - 38, /* starting offset */ - AR1TBLLEN, /* len of table */ -/*[13,38]*/ - COLLS+2, /* , comma */ - COLLS+3, /* : colon */ -/*[13,40]*/ - COLLS+7, /* ? question mark */ - COLS4+2, /* * asterick */ - COLS6, /* % percent */ - COLS9+41, /* >> alphabetic - end of list) */ - COLS9+40, /* << alphabetic - end of list) */ - COLS2, /* ( */ - COLS2+1, /* ) */ -/*[13,47]*/ - COLS8+1, /* ÚÙ One */ - COLS8+2, /* ÚÙ Two */ - COLS8+3, /* ÚÙ Three*/ -/*[13,50]*/ - COLS8+4, /* ÚÙ Four */ - COLS8+5, /* ÚÙ Five */ - COLS8+6, /* ÚÙ Six */ - COLS8+7, /* ÚÙ Seven */ - COLS8+8, /* ÚÙ Eight */ - COLS8+9, /* ÚÙ Nine */ - COLS8+0, /* ÚÙ Zero */ - COLS8+2, /* ÚÙ Two (Handwritten) */ - - COLS10a+1, /* ÚÙ alif */ - COLS10a+1, /* ÚÄ alif */ -/*[13,60]*/ - COLS10a+2, /* ÚÙ ba */ - COLS10a+2, /* ÄÙ ba */ - COLS10a+2, /* ÄÄ ba */ - COLS10a+2, /* ÚÄ ba */ - COLS10a+6, /* ÚÙ ta */ - COLS10a+6, /* ÄÙ ta */ - COLS10a+6, /* ÄÄ ta */ - COLS10a+6, /* ÚÄ ta */ - COLS10a+8, /* ÚÙ tha */ - COLS10a+8, /* ÄÙ tha */ -/*[13,70]*/ - COLS10a+8, /* ÄÄ tha */ - COLS10a+8, /* ÚÄ tha */ - COLS10a+12, /* ÚÙ jiim */ - COLS10a+12, /* ÄÙ jiim */ - COLS10a+12, /* ÄÄ jiim */ - COLS10a+12, /* ÚÄ jiim */ - COLS10a+16, /* ÚÙ Ha */ - COLS10a+16, /* ÄÙ Ha */ - COLS10a+16, /* ÄÄ Ha */ - COLS10a+16, /* ÚÄ Ha */ -/*[13,80]*/ - COLS10a+17, /* ÚÙ kha */ - COLS10a+17, /* ÄÙ kha */ - COLS10a+17, /* ÄÄ kha */ - COLS10a+17, /* ÚÄ kha */ - COLS10a+20, /* ÚÙ dal */ - COLS10a+20, /* ÚÄ dal */ - COLS10a+22, /* ÚÙ dhal */ - COLS10a+22, /* ÚÄ dhal */ - COLS10a+27, /* ÚÙ ra */ - COLS10a+27, /* ÚÄ ra */ -/*[13,90]*/ - COLS10a+29, /* ÚÙ ziin */ - COLS10a+29, /* ÚÄ ziin */ - COLS10a+31, /* ÚÙ siin */ - COLS10a+31, /* ÄÙ siin */ - COLS10a+31, /* ÄÄ siin */ - COLS10a+31, /* ÚÄ siin */ - COLS10a+32, /* ÚÙ shiin*/ - COLS10a+32, /* ÄÙ shiin*/ - COLS10a+32, /* ÄÄ shiin*/ - COLS10a+32, /* ÚÄ shiin*/ -/*[13,100]*/ - COLS10a+34, /* ÚÙ Sad */ - COLS10a+34, /* ÄÙ Sad */ - COLS10a+34, /* ÄÄ Sad */ - COLS10a+34, /* ÚÄ Sad */ - COLS10a+35, /* ÚÙ Dad */ - COLS10a+35, /* ÄÙ Dad */ - COLS10a+35, /* ÄÄ Dad */ - COLS10a+35, /* ÚÄ Dad */ - COLS10a+36, /* ÚÙ Ta */ - COLS10a+36, /* ÄÙ Ta */ -/*[13,110]*/ - COLS10a+36, /* ÄÄ Ta */ - COLS10a+36, /* ÚÄ Ta */ - COLS10a+37, /* ÚÙ Za */ - COLS10a+37, /* ÄÙ Za */ - COLS10a+37, /* ÄÄ Za */ - COLS10a+37, /* ÚÄ Za */ - COLS10a+38, /* ÚÙ 'ain */ - COLS10a+38, /* ÄÙ 'ain */ - COLS10a+38, /* ÄÄ 'ain */ - COLS10a+38, /* ÚÄ 'ain */ -/*[13,120]*/ - COLS10a+39, /* ÚÙ ghain*/ - COLS10a+39, /* ÄÙ ghain*/ - COLS10a+39, /* ÄÄ ghain*/ - COLS10a+39, /* ÚÄ ghain*/ - COLS10a+40, /* ÚÙ fa */ - COLS10a+40, /* ÄÙ fa */ - COLS10a+40, /* ÄÄ fa */ - COLS10a+40, /* ÚÄ fa */ - COLS10a+42, /* ÚÙ Qaf */ - COLS10a+42, /* ÄÙ Qaf */ -/*[13,130]*/ - COLS10a+42, /* ÄÄ Qaf */ - COLS10a+42, /* ÚÄ Qaf */ - COLS10a+43, /* ÚÙ kaf */ - COLS10a+43, /* ÄÙ kaf */ - COLS10a+43, /* ÄÄ kaf */ - COLS10a+43, /* ÚÄ kaf */ - COLS10a+46, /* ÚÙ lam */ - COLS10a+46, /* ÄÙ lam */ - COLS10a+46, /* ÄÄ lam */ - COLS10a+46, /* ÚÄ lam */ -/*[13,140]*/ - COLS10a+47, /* ÚÙ miim */ - COLS10a+47, /* ÄÙ miim */ - COLS10a+47, /* ÄÄ miim */ - COLS10a+47, /* ÚÄ miim */ - COLS10a+48, /* ÚÙ nuun */ - COLS10a+48, /* ÄÙ nuun */ - COLS10a+48, /* ÄÄ nuun */ - COLS10a+48, /* ÚÄ nuun */ - COLS10a+49, /* ÚÙ ha */ - COLS10a+49, /* ÄÙ ha */ -/*[13,150]*/ - COLS10a+49, /* ÄÄ ha */ - COLS10a+49, /* ÚÄ ha */ - /* ha is also 51 for non-arabic */ - COLS10a+6, /* ÚÙ ta marbuuTah */ - COLS10a+6, /* ÚÄ ta marbuuTah */ - COLS10a+50, /* ÚÙ waw */ - COLS10a+50, /* ÚÄ waw */ - COLS10a+53, /* ÚÙ ya */ - COLS10a+53, /* ÄÙ ya */ - COLS10a+53, /* ÄÄ ya */ - COLS10a+53, /* ÚÄ ya */ -/*[13,160]*/ - COLS10a+52, /* ÚÙ alif maqSuurah */ - COLS10a+52, /* ÄÙ ya maqSuurah? */ - COLS10a+52, /* ÄÄ ya maqSuurah? */ - COLS10a+52, /* ÚÄ alif maqSuurah */ - - COLS10a+0, /* ÚÙ hamzah accent - never appears alone */ -/*[13,165]*/ -/**---------------------------------------------------- -*** Store the sub-collation as the actual -*** character value from this point on -***---------------------------------------------------*/ - COLS10a+1, /* ÚÙ alif hamzah */ - COLS10a+1, /* ÚÄ alif hamzah */ - COLS10a+1, /* ÚÙ hamzah-under-alif */ - COLS10a+1, /* ÚÄ hamzah-under-alif */ - COLS10a+1, /* ÚÙ waw hamzah */ -/*[13,170]*/ - COLS10a+1, /* ÚÄ waw hamzah */ - COLS10a+1, /* ÚÙ ya hamzah */ - COLS10a+1, /* ÄÙ ya hamzah */ - COLS10a+1, /* ÄÄ ya hamzah */ - COLS10a+1, /* ÚÄ ya hamzah */ - COLS10a+1, /* ÚÙ alif fatHataan */ - COLS10a+1, /* ÚÄ alif fatHataan */ - COLS10a+1, /* ÚÙ alif maddah */ - COLS10a+1, /* ÚÄ alif maddah */ - COLS10a+1, /* ÚÙ alif waSlah */ -/*[13,180] */ - COLS10a+1, /* ÚÄ alif waSlah (final) */ -/**--------------------------------------------------- -*** LIGATURES -*** Should NEVER be stored so will not worry -*** about breaking up into pieces for collation. -*** NOTE: -*** Let's store the "Lam" collation value (+42) -*** below and in the sub-collation store the -*** actual character. This will sort real close. -*** The best implementation is to -*** break up ligatures into its base pieces. -***--------------------------------------------------*/ - COLS10a+46, /* ÚÙ lamalif */ - COLS10a+46, /* ÚÄ lamalif */ - COLS10a+46, /* ÚÙ lamalif hamzah */ - COLS10a+46, /* ÚÄ lamalif hamzah */ - COLS10a+46, /* ÚÙ hamzah-under-lamalif */ - COLS10a+46, /* ÚÄ hamzah-under-lamalif */ - COLS10a+46, /* ÚÙ lamalif fatHataan */ - COLS10a+46, /* ÚÄ lamalif fatHataan */ - COLS10a+46, /* ÚÙ lamalif maddah */ -/*[13,190]*/ - COLS10a+46, /* ÚÄ lamalif maddah */ - COLS10a+46, /* ÚÙ lamalif waSlah */ - COLS10a+46, /* ÚÄ lamalif waSlah */ - COLS10a+46, /* ÚÙ Allah - khaDalAlif */ - COLS0_ARABIC, /* ÄÄ taTwiil - character extension - throw out */ - COLS0_ARABIC /* ÄÄ taTwiil 1/6 - character extension - throw out */ -}; - -/**------------------------------------------ -*** Alef needs a subcollation table. -*** If colval==COLS10a+1 & char>=165 -*** index through this table. Otherwise -*** the alef value is [13,58] and subcol -*** value should be 7. Alef maddah is default (0) -*** -*** Handcheck if colval==COLS10a+6 -*** Should sort: -*** [13,152]..[13,153] - taa marbuuTah - nosubcoll -*** [13,64] ..[13,67] - taa - subcoll of 1 -***-----------------------------------------*/ - -FLMBYTE fwp_alefSubColTbl[] = { -/*[13,165]*/ - 1, /* ÚÙ alif hamzah */ - 1, /* ÚÄ alif hamzah */ - 3, /* ÚÙ hamzah-under-alif */ - 3, /* ÚÄ hamzah-under-alif */ - 2, /* ÚÙ waw hamzah */ -/*[13,170]*/ - 2, /* ÚÄ waw hamzah */ - 4, /* ÚÙ ya hamzah */ - 4, /* ÄÙ ya hamzah */ - 4, /* ÄÄ ya hamzah */ - 4, /* ÚÄ ya hamzah */ - 5, /* ÚÙ alif fatHataan */ - 5, /* ÚÄ alif fatHataan */ - 0, /* ÚÙ alif maddah */ - 0, /* ÚÄ alif maddah */ - 6, /* ÚÙ alif waSlah */ -/*[13,180]*/ - 6 /* ÚÄ alif waSlah (final) */ -}; - -#define AR2TBLLEN 179 /* 219 - 41 + 1 */ - -FLMBYTE fwp_ar260Tbl[AR2TBLLEN+2] = { - 41, /* starting offset */ - AR2TBLLEN, /* len of table */ -/*[14,41]*/ - COLS8+4, /* Farsi and Urdu Four */ - COLS8+4, /* Urdu Four */ - COLS8+5, /* Farsi and Urdu Five */ - COLS8+6, /* Farsi Six */ - COLS8+6, /* Farsi and Urdu Six */ - COLS8+7, /* Urdu Seven */ - COLS8+8, /* Urdu Eight */ - - COLS10a+3, /* Sindhi bb - baa /w 2 dots below (67b) */ - COLS10a+3, - COLS10a+3, - COLS10a+3, - COLS10a+4, /* Sindhi bh - baa /w 4 dots below (680) */ - COLS10a+4, - COLS10a+4, - COLS10a+4, -/*[14,56]*/ - COLS10a+5, /* Malay, Kurdish, Pashto, Farsi, Sindhi, and Urdu p */ - COLS10a+5, /* =peh - taa /w 3 dots below (67e) */ - COLS10a+5, - COLS10a+5, - COLS10a+7, /* Urdu T - taa /w small tah */ - COLS10a+7, - COLS10a+7, - COLS10a+7, - COLS10a+7, /* Pashto T - taa /w ring (forced to combine) */ - COLS10a+7, - COLS10a+7, - COLS10a+7, - COLS10a+9, /* Sindhi th - taa /w 4 dots above (67f) */ - COLS10a+9, -/*[14,70]*/ - COLS10a+9, - COLS10a+9, - COLS10a+10, /* Sindhi Tr - taa /w 3 dots above (67d) */ - COLS10a+10, - COLS10a+10, - COLS10a+10, - COLS10a+11, /* Sindhi Th - taa /w 2 dots above (67a) */ - COLS10a+11, - COLS10a+11, - COLS10a+11, - COLS10a+13, /* Sindhi jj - haa /w 2 middle dots verticle (684) */ - COLS10a+13, - COLS10a+13, - COLS10a+13, - COLS10a+14, /* Sindhi ny - haa /w 2 middle dots (683) */ - COLS10a+14, - COLS10a+14, - COLS10a+14, -/*[14,88]*/ - COLS10a+15, /* Malay, Kurdish, Pashto, Farsi, Sindhi, and Urdu ch */ - COLS10a+15, /* =tcheh (686) */ - COLS10a+15, - COLS10a+15, - COLS10a+15, /* Sindhi chh - haa /w middle 4 dots (687) */ - COLS10a+15, /* forced to combine */ - COLS10a+15, - COLS10a+15, - COLS10a+18, /* Pashto ts - haa /w 3 dots above (685) */ - COLS10a+18, - COLS10a+18, - COLS10a+18, - COLS10a+19, /* Pashto dz - hamzah on haa (681) */ - COLS10a+19, - COLS10a+19, - COLS10a+19, -/*[14,104]*/ - COLS10a+21, /* Urdu D - dal /w small tah (688) */ - COLS10a+21, - COLS10a+21, /* Pashto D - dal /w ring (689) forced to combine */ - COLS10a+21, - COLS10a+23, /* Sindhi dh - dal /w 2 dots above (68c) */ - COLS10a+23, - COLS10a+24, /* Sindhi D - dal /w 3 dots above (68e) */ - COLS10a+24, - COLS10a+25, /* Sindhi Dr - dal /w dot below (68a) */ - COLS10a+25, - COLS10a+26, /* Sindhi Dh - dal /w 2 dots below (68d) */ - COLS10a+26, - COLS10a+28, /* Pashto r - ra /w ring (693) */ - COLS10a+28, -/*[14,118]*/ - COLS10a+28, /* Urdu R - ra /w small tah (691) forced to combine */ - COLS10a+28, - COLS10a+28, /* Sindhi r - ra /w 4 dots above (699) forced to combine */ - COLS10a+28, - COLS10a+27, /* Kurdish rolled r - ra /w 'v' below (695) */ - COLS10a+27, - COLS10a+27, - COLS10a+27, -/*[14,126]*/ - COLS10a+30, /* Kurdish, Pashto, Farsi, Sindhi, and Urdu Z */ - COLS10a+30, /* = jeh - ra /w 3 dots above (698) */ - COLS10a+30, /* Pashto zz - ra /w dot below & dot above (696) */ - COLS10a+30, /* forced to combine */ - COLS10a+30, /* Pashto g - not in unicode! - forced to combine */ - COLS10a+30, - COLS10a+33, /* Pashto x - seen dot below & above (69a) */ - COLS10a+33, - COLS10a+33, - COLS10a+33, - COLS10a+39, /* Malay ng - old maly ain /w 3 dots above (6a0) */ - COLS10a+39, /* forced to combine */ - COLS10a+39, - COLS10a+39, -/*[14,140]*/ - COLS10a+41, /* Malay p, Kurdish v - Farsi ? - fa /w 3 dots above */ - COLS10a+41, /* = veh - means foreign words (6a4) */ - COLS10a+41, - COLS10a+41, - COLS10a+41, /* Sindhi ph - fa /w 4 dots above (6a6) forced to combine*/ - COLS10a+41, - COLS10a+41, - COLS10a+41, -/*[14,148]*/ - COLS10a+43, /* Misc k - open caf (6a9) */ - COLS10a+43, - COLS10a+43, - COLS10a+43, - COLS10a+43, /* misc k - no unicode - forced to combine */ - COLS10a+43, - COLS10a+43, - COLS10a+43, - COLS10a+43, /* Sindhi k - swash caf (various) (6aa) -forced to combine*/ - COLS10a+43, - COLS10a+43, - COLS10a+43, -/*[14,160]*/ - COLS10a+44, /* Persian/Urdu g - gaf (6af) */ - COLS10a+44, - COLS10a+44, - COLS10a+44, - COLS10a+44, /* Persian/Urdu g - no unicode */ - COLS10a+44, - COLS10a+44, - COLS10a+44, - COLS10a+44, /* malay g - gaf /w ring (6b0) */ - COLS10a+44, - COLS10a+44, - COLS10a+44, - COLS10a+44, /* Sindhi ng - gaf /w 2 dots above (6ba) */ - COLS10a+44, /* forced to combine ng only */ - COLS10a+44, - COLS10a+44, - COLS10a+45, /* Sindhi gg - gaf /w 2 dots vertical below (6b3) */ - COLS10a+45, - COLS10a+45, - COLS10a+45, -/*[14,180]*/ - COLS10a+46, /* Kurdish velar l - lam /w small v (6b5) */ - COLS10a+46, - COLS10a+46, - COLS10a+46, - COLS10a+46, /* Kurdish Lamalif with diacritic - no unicode */ - COLS10a+46, -/*[14,186]*/ - COLS10a+48, /* Urdu n - dotless noon (6ba) */ - COLS10a+48, - COLS10a+48, - COLS10a+48, - COLS10a+48, /* Pashto N - noon /w ring (6bc) - forced to combine */ - COLS10a+48, - COLS10a+48, - COLS10a+48, - COLS10a+48, /* Sindhi N - dotless noon/w small tah (6bb) */ - COLS10a+48, /* forced to combine */ - COLS10a+48, - COLS10a+48, - COLS10a+50, /* Kurdish o - waw /w small v (6c6) */ - COLS10a+50, -/*[14,200]*/ - COLS10a+50, /* Kurdish o - waw /w bar above (6c5) */ - COLS10a+50, - COLS10a+50, /* Kurdish o - waw /w 2 dots above (6ca) */ - COLS10a+50, -/*[14,204]*/ - COLS10a+51, /* Urdu h - no unicode */ - COLS10a+51, - COLS10a+51, - COLS10a+51, - COLS10a+52, /* Kurdish ˆ - ya /w small v (6ce) */ - COLS10a+52, - COLS10a+52, - COLS10a+52, -/*[14,212]*/ - COLS10a+54, /* Urdu y - ya barree (6d2) */ - COLS10a+54, - COLS10a+54, /* Malay ny - ya /w 3 dots below (6d1) forced to combine */ - COLS10a+54, - COLS10a+54, - COLS10a+54, -/*[14,218]*/ - COLS10a+51, /* Farsi hamzah - hamzah on ha (6c0) forced to combine */ - COLS10a+51 -}; - - -/* If the bit position is set then save the character in the sub-col area */ -/* The bit values are determined by looking at the FLAIM COLTBL1 to see */ -/* which characters are combined with other arabic characters. */ - -FLMBYTE fwp_ar2BitTbl[] = { - /* Start at character 64 */ - /* The only 'clean' areas uncollate to the correct place, they are...*/ - /* 48..63 */ - /* 68..91 */ - /* 96..117 */ - /* 126..127 */ - /* 140..143 */ - /* 160..163 */ - /* 176..179 */ - /* 212..213 */ - - 0xF0, /* 64..71 */ - 0x00, /* 72..79 */ - 0x00, /* 80..87 */ - 0x0F, /* 88..95 - 92..95 */ - 0x00, /* 96..103 */ - 0x00, /* 104..111 */ - 0x03, /* 112..119 */ - 0xFC, /* 120..127 */ - 0xFF, /* 128..135 */ - 0xF0, /* 136..143 - 136..139 */ - 0xFF, /* 144..151 - 144..147, 148..159 */ - 0xFF, /* 152..159 */ - 0x0F, /* 160..167 - 164..175 */ - 0xFF, /* 168..175 */ - 0x0F, /* 176..183 - 180..185 */ - 0xFF, /* 184..191 - 186..197 */ - 0xFF, /* 192..199 - 198..203 */ - 0xFF, /* 200..207 - 204..207 */ - 0xF3, /* 208..215 - 208..211 , 214..217 */ - 0xF0 /* 216..219 - 218..219 */ -}; - -/**------------------------------------------------------------------ -*** Collating table -*** This table describes and gives addresses for collating 5.0 -*** character sets. Each line corresponds with a character set. -*** -*** The second table is for sorting the hebrew/arabic languages. -*** These values overlap the end of ASC/european and cyrillic tables. -***-----------------------------------------------------------------*/ - -TBL_B_TO_BP fwp_col60Tbl[] = { - {CHSASCI, fwp_asc60Tbl}, /* ascii - " " - "~" */ - {CHSMUL1, fwp_mn60Tbl}, /* multinational */ - {CHSSYM1, fwp_sym60Tbl}, /* symbols */ - {CHSGREK, fwp_grk60Tbl}, /* greek */ - {CHSCYR, fwp_cyrl60Tbl}, /* Cyrillic - Russian */ - {0xFF, 0} /* table terminator */ -}; - -TBL_B_TO_BP fwp_HebArabicCol60Tbl[] = { - {CHSASCI, fwp_asc60Tbl}, /* ascii - " " - "~" */ - {CHSMUL1, fwp_mn60Tbl}, /* multinational */ - {CHSSYM1, fwp_sym60Tbl}, /* symbols */ - {CHSGREK, fwp_grk60Tbl}, /* greek */ - {CHSHEB, fwp_heb60TblA}, /* Hebrew */ - {CHSHEB, fwp_heb60TblB}, /* Hebrew */ - {CHSARB1, fwp_ar160Tbl}, /* Arabic Set 1 */ - {CHSARB2, fwp_ar260Tbl}, /* Arabic Set 2 */ - {0xff, 0} /* table terminator */ -}; - - -/******************************************************************** - The diacritical to collated table translates the first 26 characters of - WP character set #1 into a 5 bit value for "correct" sorting - sequence for that diacritical (DCV) - diacritic collated value. - - The attempt here is to convert the collated character value - along with the DCV to form the original WP character. - - The diacriticals are in an order to fit the most languages. - Czech, Swedish, and Finnish will have to manual reposition the - ring above (assign it a value greater then the umlaut) - - This table is index by the diacritical value. -********************************************************************/ - -FLMBYTE fwp_dia60Tbl[] = -{ - 2, /* grave offset = 0 */ - 16, /* centerd offset = 1 */ - 7, /* tilde offset = 2 */ - 4, /* circum offset = 3 */ - 12, /* crossb offset = 4 */ - 10, /* slash offset = 5 */ - 1, /* acute offset = 6 */ - 6, /* umlaut offset = 7 */ - /* In SU, SV and CZ will = 9 */ - 17, /* macron offset = 8 */ - 18, /* aposab offset = 9 */ - 19, /* aposbes offset = 10 */ - 20, /* aposba offset = 11 */ - 21, /* aposbc offset = 12 */ - 22, /* abosbl offset = 13 */ - 8, /* ring offset = 14 */ - 13, /* dota offset = 15 */ - 23, /* dacute offset = 16 */ - 11, /* cedilla offset = 17 */ - 14, /* ogonek offset = 18 */ - 5, /* caron offset = 19 */ - 15, /* stroke offset = 20 */ - 24, /* bara offset = 21 */ - 3, /* breve offset = 22 */ - 0, /* dbls offset = 23 sorts as 'ss' */ - 25, /* dotlesi offset = 24 */ - 26 /* dotlesj offset = 25 */ -}; - - diff --git a/flaim/src/fxml.h b/flaim/src/fxml.h index f970625..8ad3c26 100644 --- a/flaim/src/fxml.h +++ b/flaim/src/fxml.h @@ -166,13 +166,17 @@ #define F_XML_UNI_PIPE ((FLMUNICODE)124) #define F_XML_UNI_TILDE ((FLMUNICODE)126) -// Typedefs - -typedef struct xmlChar +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct XMLCHAR { FLMBYTE ucFlags; } XMLCHAR; +/**************************************************************************** +Desc: +****************************************************************************/ class F_XML : public F_Base { public: diff --git a/flaim/src/gbinary.cpp b/flaim/src/gbinary.cpp deleted file mode 100644 index 7149588..0000000 --- a/flaim/src/gbinary.cpp +++ /dev/null @@ -1,160 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Get/set binary data in fields in gedcom records. -// Tabs: 3 -// -// Copyright (c) 1992-1993,1995-1997,1999-2000,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gbinary.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Name : GedGetBINARY -Area : GEDCOM -Desc : Gets binary data from a GEDCOM TEXT node or a GEDCOM - BINARY node. If the node is a TEXT node, it converts each two - hex digits to one byte of BINARY. -Notes: If the buffer pointer is NULL, the routine just determines how - much buffer space is needed to return the data in binary - format. -*END************************************************************************/ -RCODE // SUCCESS - No problems in processing - // FERR_CONV_DEST_OVERFLOW - number of bytes specified by *bufLenRV is - // not sufficient - // FERR_CONV_ILLEGAL - the GEDCOM node is not a BINARY or TEXT type node - // FERR_CONV_BAD_DIGIT - only hexadecimal values in a TEXT type node - // are allowed for conversion. - GedGetBINARY( - NODE * node, - // [IN] Pointer to a GEDCOM node containing binary or hexadecimal - // text data. - void * buffer, - // [OUT} Pointer to the output buffer that will contain the binary - // data. - FLMUINT * bufLenRV - // [IN] Specifies the length of buffer. - // [OUT] Returns the number of bytes used in buffer. - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * ptr; - FLMUINT valLength; - FLMUINT outputData; - FLMUINT nodeType; - - /* Check for a null node */ - - if( node == NULL) - { - rc = RC_SET( FERR_CONV_NULL_SRC); - goto Exit; - } - - if (node->ui32EncId) - { - if (!(node->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - /* If the node is not a BINARY node, return an error. */ - - nodeType = GedValType( node); - if( nodeType != FLM_BINARY_TYPE) - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - - ptr = (FLMBYTE *)GedValPtr( node); - valLength = GedValLen( node); - - /* At this point we know the node is a BINARY node */ - - outputData = ((buffer != NULL) && (*bufLenRV)); - if( (outputData) && (valLength)) - { - if( valLength > *bufLenRV) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Exit; - } - f_memcpy( buffer, ptr, valLength); - } - *bufLenRV = valLength; - -Exit: - return( rc); -} - -/*API~********************************************************************* -Desc: Copies a binary string of bytes into a GEDCOM node. -*END************************************************************************/ -RCODE GedPutBINARY( - POOL * pPool, - NODE * node, - const void * pvData, - FLMUINT uiDataLen, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - RCODE rc = FERR_OK; - FLMBYTE * outPtr; - - // Check for a null node being passed in - - if( !node) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - // If data pointer is NULL or length is zero, call GedAllocSpace with a - // length of zero to set the node length to zero and node type to - // FLM_BINARY_TYPE. - - if( pvData == NULL || !uiDataLen) - { - (void)GedAllocSpace( pPool, node, FLM_BINARY_TYPE, 0, uiEncId, uiEncSize); - goto Exit; - } - - // Allocate space in the node for the binary data - - if( (outPtr = (FLMBYTE *)GedAllocSpace( pPool, node, - FLM_BINARY_TYPE, uiDataLen, uiEncId, uiEncSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Set the node type and copy the data into the node - - f_memcpy( outPtr, pvData, uiDataLen); - - if (node->ui32EncId) - { - node->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - - return( rc); -} diff --git a/flaim/src/gd2tree.cpp b/flaim/src/gd2tree.cpp deleted file mode 100644 index 748d017..0000000 --- a/flaim/src/gd2tree.cpp +++ /dev/null @@ -1,356 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Import text GEDCOM buffer -// Tabs: 3 -// -// Copyright (c) 1990-1992,1994-2000,2002-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gd2tree.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -extern FLMBYTE arr[]; - -#define f_isdigit(c) \ - ((c) < 60 ? (( ((FLMBYTE)(arr[(c) >> 3])) << ((c) & 0x07)) & 0x80) : 0) - -FSTATIC RCODE tagValLenType( - POOL * pPool, - GED_STREAM_p x, - NODE ** node, - F_NameTable * pNameTable); - -/************************************************************************* -Desc: This function parses and builds one complete GEDCOM tree from a GEDCOM - character buffer or file. The beginning level number is used only to - delimit the tree (possiblly in forest); the generated tree's level - always start at zero. -Note: The syntax for each GEDCOM "line" in the sub-tree is: - - [ {[#] } | - [ - [@@] [{@@} | {["] ["]}] - [ [{#} | {+ ["] ["]}] ]... - ] - ]... - - Where: - - any character string - 0 <= < 32 (decimal) (delimited by whitespace/) - any string of alphanumeric characters (and/or '_') and must - not start with digit (delimited by whitespace/). - carriage return (and/or linefeed) - # 1st non-whitespace character of line showing that a comment - follows - + 1st non-whitespace character of line showing value continues - from prior line. Can not continue if xref used instead of - value - " quote mark may optionally preceed/follow string--leading or - trailing spaces are included (significant) only if bounded - by a leading/trailing quote mark - any character string. data type is automatically converted - to data dictionary type at time of storage - White space (tabs and/or spaces) is ignored except in - strings. - -***************************************************************************/ -RCODE GedToTree( - POOL * pPool, - F_FileHdl * pFileHdl, - char ** pBuf, - FLMUINT uiBufSize, - NODE ** root, - F_NameTable * pNameTable) -{ - RCODE rc = FERR_OK; - GED_STREAM x; - FLMUINT level; - FLMUINT levelBase = 0; - FLMUINT levelPrior = 0; - FLMBYTE nextChar; - NODE * nd = NULL; - NODE * ndPrior = NULL; - FLMUINT startPos; - - x.pFileHdl = pFileHdl; - x.pThis = - x.pBuf = *pBuf; - x.uiBufSize = uiBufSize; - - if( pFileHdl) - { - // Find 1st starting file position - - if( RC_OK( pFileHdl->Seek( 0L, F_IO_SEEK_CUR, &x.uiFilePos))) - { - x.pLast = x.pBuf; /* set parms for forced 1st read */ - gedReadChar( &x, x.uiFilePos); /* insure buffer has data in it */ - } - else - return( RC_SET( FERR_FILE_ER)); - } - else - { - x.errorIO = 0; - x.uiFilePos = 0; /* uiFilePos is really just bufferPos */ - x.pLast = x.pBuf + (uiBufSize - 1); - x.thisC = f_toascii( *x.pBuf); - } - - for(;;) - { - gedSkipBlankLines( &x); - startPos = x.uiFilePos; /* save position of first of line */ - - if( f_isdigit( x.thisC)) /* level number */ - { - /* process level number */ - - level = 0; - do /* compute level number */ - { - level = x.thisC - ASCII_ZERO + (level * 10); - nextChar = (FLMBYTE)(gedNextChar( &x));/* put next character in variable */ - } while( f_isdigit( nextChar)); /* to avoid problems with macro expansion */ - - if( ! f_iswhitespace( x.thisC)) - { - rc = RC_SET( FERR_BAD_FIELD_LEVEL); /* not terminated properly */ - break; - } - - if( level > GED_MAXLVLNUM) - { - rc = RC_SET( FERR_GED_MAXLVLNUM); - break; - } - - if( ndPrior) /* not 1st time through */ - { - if( levelBase >= level) /* end sub-tree; more trees follow */ - goto successful; /* done */ - else if( (levelPrior < level) && ((levelPrior + 1) != level)) - { /* bad level jump (too big: > 1) */ - rc = RC_SET( FERR_GED_SKIP_LEVEL); - break; - } - } - else - levelBase = level; - levelPrior = level; - - /* process node & value */ - - rc = tagValLenType( pPool, &x, &nd, pNameTable); - - /* link node into tree */ - - if( RC_OK( rc)) - { - if( ndPrior) - ndPrior->next = nd; /* link prior to this */ - else - *root = nd; - nd->prior = ndPrior; /* link this to prior */ - GedNodeLevelSet( nd, level - levelBase); - /* make node's level relative to base */ - ndPrior = nd; - continue; - } - } - else if( x.thisC == '\0' || x.thisC == ASCII_CTRLZ) /* end sub-tree; none follow */ - { - if( x.errorIO) - rc = RC_SET( FERR_FILE_ER); - else if( ndPrior) - { -successful: - ndPrior->next = NULL; /* finish last node's link */ - if( pFileHdl == NULL) - *pBuf = x.pThis + (FLMINT32)(startPos - x.uiFilePos); - x.uiFilePos = startPos; /* this line part of next tree */ - rc = FERR_OK; - } - else - rc = RC_SET( FERR_END); /* only BLANKLINES in input line */ - } - else - { - rc = RC_SET( FERR_BAD_FIELD_LEVEL); /* missing level number */ - } - break; /* exit "for" loop */ - } - - if( RC_BAD( rc)) - { - *root = NULL; - if( pFileHdl == NULL) - *pBuf = x.pThis; - } - if( pFileHdl) - { - /* this token had syntax error */ - pFileHdl->Seek( x.uiFilePos, F_IO_SEEK_SET, &x.uiFilePos); - } - return( rc); -} - -/*************************************************************************** -Desc: Parse the tag, value, and length from a GEDCOM buffer, create a - node, and populate it with these values. Continuation lines and - embedded comments are also handled. -***************************************************************************/ -FSTATIC RCODE tagValLenType( - POOL * pPool, - GED_STREAM_p x, - NODE ** newNode, - F_NameTable * pNameTable) -{ - FLMUINT startPos; - RCODE rc = FERR_OK; - NODE * nd; - FLMUINT drn = 0; - FLMUINT uiTagNum; - char tagBuf[ GED_MAXTAGLEN + 1]; - - gedSkipWhiteSpaces( x); - - /* process optional xref-id */ - - startPos = x->uiFilePos; - if( x->thisC == ASCII_AT) /* at-sign sequence begins */ - { - int badDRN; - for( badDRN = 0, gedNextChar( x); x->thisC != ASCII_AT; gedNextChar( x)) - { - FLMUINT priorDrn = drn; - - if( ! badDRN) - { - if( f_isdigit( x->thisC)) - { - drn = (drn * 10) + x->thisC - ASCII_ZERO; - badDRN = priorDrn != (drn / 10); - } - else - badDRN = 1; - } - } - if( badDRN) - drn = 0; - - gedNextChar( x); - if( f_iswhitespace( x->thisC)) - gedSkipWhiteSpaces( x); - else - { - rc = RC_SET( FERR_GED_BAD_RECID); - goto Exit; - } - } - - /* Determine the Tag Number and Build the NODE */ - - startPos = x->uiFilePos; - - if( !gedCopyTag( x, tagBuf)) - { - return( RC_SET( FERR_INVALID_TAG)); - } - - if( !pNameTable->getFromTagTypeAndName( NULL, tagBuf, - FLM_FIELD_TAG, &uiTagNum)) - { - /* See if tag is the reserved tag with the number following */ - - if( tagBuf[0] == f_toascii( 'T') && - tagBuf[1] == f_toascii( 'A') && - tagBuf[2] == f_toascii( 'G') && - tagBuf[3] == f_toascii( '_')) - { - uiTagNum = f_atoi( &tagBuf[ 4]); - } - else - { - return( RC_SET( FERR_NOT_FOUND)); - } - } - - if( (*newNode = nd = GedNodeCreate( pPool, uiTagNum, drn, &rc)) == NULL) - { - goto Exit; - } - - gedSkipWhiteSpaces( x); - - /* alternate xref_ptr used instead of "value" */ - - startPos = x->uiFilePos; - if( x->thisC == ASCII_AT) - { - for( drn = 0; gedNextChar( x) != ASCII_AT;) - { - FLMUINT priorDrn = drn; - if( f_isdigit( x->thisC)) - { - drn = (drn * 10) + x->thisC - ASCII_ZERO; - if( priorDrn == (drn / 10)) - continue; /* no overflow yet */ - } - rc = RC_SET( FERR_GED_BAD_VALUE); /* catch overflow & non-numeric */ - goto Exit; - } - gedNextChar( x); - GedPutRecPtr( pPool, nd, drn); - if( gedCopyValue( x, NULL)) /* test 2nd value & skip whitespace */ - { - rc = RC_SET( FERR_GED_BAD_VALUE); /* can't have both @xref@ and value */ - goto Exit; - } - } - else - { - FLMINT valLength; - FLMUINT tempPos = x->uiFilePos; - - if( (valLength = gedCopyValue( x, NULL)) > 0) - { - char * vp = (char *)GedAllocSpace( pPool, nd, - FLM_TEXT_TYPE, valLength); - - if( vp) - { - gedReadChar( x, tempPos); - gedCopyValue( x, vp); - } - else - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - } - - startPos = x->uiFilePos; /* successful: point to next token */ - -Exit: - gedReadChar( x, startPos); /* position to start of token */ - return( rc); -} - diff --git a/flaim/src/gdcopy.cpp b/flaim/src/gdcopy.cpp deleted file mode 100644 index 47c7d10..0000000 --- a/flaim/src/gdcopy.cpp +++ /dev/null @@ -1,233 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Copy GEDCOM tree -// Tabs: 3 -// -// Copyright (c) 1990-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gdcopy.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/************************************************************************** -Name : GedNodeCopy -Area : GEDCOM -Desc : Allocates a new node, value, and tag and copies from the old node - its attached child(ren) and sibling(s). -Notes: -****************************************************************************/ -NODE * GedNodeCopy( - POOL * pPool, - NODE * node, - NODE * childList, - NODE * sibList) -{ - NODE * newNd; - FLMUINT bias; - FLMBYTE * vp; - RCODE rc; - HFDB hDb; - FLMUINT uiContainer; - FLMUINT uiRecId; - - // If the node has source information, we need to copy it - - if( RC_OK( GedGetRecSource( node, &hDb, &uiContainer, &uiRecId))) - { - // The passed in node contains record source information, - // so create a GEDCOM record source node - - if( RC_BAD( gedCreateSourceNode( pPool, GedTagNum( node), hDb, - uiContainer, uiRecId, &newNd))) - { - return NULL; - } - } - else - { - // Create a normal (non-source) GEDCOM node - - if( (newNd = GedNodeMake( pPool, GedTagNum( node), &rc)) == NULL) - { - return( NULL); - } - } - - newNd->prior = NULL; - newNd->next = childList; - GedNodeLevelSet( newNd, 0); - - if( (vp = (FLMBYTE *)GedAllocSpace( pPool, newNd, GedValType( node), - GedValLen( node), node->ui32EncId, GedEncLen( node))) != NULL) - { - f_memcpy( vp, GedValPtr( node), GedValLen( node)); - - if (node->ui32EncFlags & FLD_HAVE_ENCRYPTED_DATA) - { - f_memcpy( GedEncPtr( newNd), GedEncPtr( node), GedEncLen( node)); - } - - newNd->ui32EncFlags = node->ui32EncFlags; - } - else - { - return( NULL); - } - - if( childList) - { - childList->prior = newNd; - for( /* find end of sub-tree */ - bias = GedNodeLevel( childList) - 1 - /* 1st child level should be 1 */ - ; childList->next /* continue to last in list */ - ; GedNodeLevelSub( childList, bias), /* correct relative level */ - childList = childList->next /* follow list */ - ); - GedNodeLevelSub( childList, bias); /* correct last node in list */ - childList->next = sibList; - } - else - childList = newNd; /* no child(ren)--sib(s) link to newNd */ - - if( sibList) /* attach sibling(s) */ - { - sibList->prior = childList; - childList->next = sibList; - for( /* find end of sibList */ - bias = GedNodeLevel( sibList) /* sib must be level 0 too */ - ; sibList->next - ; GedNodeLevelSub( sibList, bias), /* correct relative level */ - sibList = sibList->next - ); - GedNodeLevelSub( sibList, bias); /* correct last node in list */ - } - - return( newNd); -} - -/*API~********************************************************************* -Desc: Copies the entire contents of a tree. -****************************************************************************/ -NODE * GedCopy( - POOL * pPool, - FLMUINT cnt, - NODE * tree) -{ - NODE * oldNd; - NODE * newNd; - NODE * newRoot; - FLMUINT baseLevel; - - if( tree) - { - newRoot = newNd = GedNodeCopy( pPool, tree, NULL, NULL); - if( newRoot) - { - for( - baseLevel = GedNodeLevel( tree) - ; (tree = tree->next) != NULL && /* follow linked list */ - ( - GedNodeLevel( tree) > baseLevel || /* process sub-tree */ - ( - GedNodeLevel( tree) == baseLevel && /* if sibling in forest AND */ - --cnt /* count not expired, do next tree */ - ) - ) - ; - ) - { - oldNd = newNd; /* save for linking below */ - if( (newNd = GedNodeCopy( pPool, tree, NULL, NULL)) != NULL) - { - oldNd->next = newNd; /* link up */ - newNd->prior = oldNd; - GedNodeLevelSet( newNd, GedNodeLevel( tree) - baseLevel); - } - else - return( NULL); - } - } - return( newRoot); - } - - return( NULL); -} - -/*API~*********************************************************************** -Name : GedClip -Area : GEDCOM/LINK -Desc : Unlinks a node or sub-tree from its parent and/or siblings. -Notes: Starting at the node specified by self, treeCnt sibling trees will - be unlinked from their parent node (if any), as well as from their - previous and next sibling nodes (if any). If the clipped siblings - had a previous sibling and a next sibling, the previous sibling and - the next sibling are reconnected as siblings. If the clipped - siblings had a parent, a next sibling, but no previous sibling, the - next sibling be reconnected to the parent as the parent's first - child. -*END************************************************************************/ -NODE * - // A pointer to the input node/sub-tree (self) is returned. This - // allows GedClip to be used a a parameter to other functions which - // require a NODE * parameter. - GedClip( - FLMUINT treeCnt, - // [IN] Number of sibling trees to unlink. - NODE * self) - // [IN] Pointer to the node or sub-tree which is to be unlinked. -{ - NODE * next; - - if( self) - { - FLMUINT oldLevel = GedNodeLevel( self); - - GedNodeLevelSet( self, 0); /* clipped tree now at level 0 */ - - for( /* skip to next sub-tree */ - next = self->next; - next && /* stop at end of sub-tree */ - ( - GedNodeLevel( next) > oldLevel || /* continue if child level */ - ( - GedNodeLevel( next) == oldLevel && /* if forest sibling, --treeCnt */ - --treeCnt /* continue if treeCnt != 0 */ - ) - ) - ; GedNodeLevelSub( next, oldLevel), // Adjust levels relative to new root - next = next->next) - { - ; - } - - if( self->prior) - { - self->prior->next = next; /* re-link the gap in old tree/forest */ - } - - if( next) - { - next->prior->next = NULL; /* clipped tree's end must be made null*/ - next->prior = self->prior; /* re-link the gap in old tree/forest */ - } - self->prior = NULL; /* clipped tree's head must now be root */ - } - return( self); -} - diff --git a/flaim/src/gddiff.cpp b/flaim/src/gddiff.cpp deleted file mode 100644 index fea1f84..0000000 --- a/flaim/src/gddiff.cpp +++ /dev/null @@ -1,785 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Difference two FlmRecord objects. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gddiff.cpp 12304 2006-01-19 15:04:25 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -class RecCursor : public F_Base -{ -public: - - /* Instance methods ------------------------------------------------------*/ - - RecCursor( // Constructor - FlmRecord * pRecord, - GRD_CallBackFunction pCallBackFunction, - void * pvCallBackData) - { - m_pRecord = pRecord; - m_pvField = pRecord ? pRecord->root() : NULL; - m_uiRootLevel = pRecord ? pRecord->getLevel( m_pvField) : 0 ; - m_uiAbsoluteCursorPosition = 1; - m_pCallBack = pCallBackFunction; - m_pvCallBackData = pvCallBackData; - m_bStillAtTheRoot = TRUE; - } - - RecCursor( // Copy Constructor - RecCursor * cursor) - { - m_pRecord = cursor->m_pRecord; - m_pvField = cursor->m_pvField; - m_uiRootLevel = cursor->m_uiRootLevel; - m_uiAbsoluteCursorPosition = cursor->m_uiAbsoluteCursorPosition; - m_pCallBack = cursor->m_pCallBack; - m_pvCallBackData = cursor->m_pvCallBackData; - m_bStillAtTheRoot = cursor->m_bStillAtTheRoot; - } - - virtual ~RecCursor() // Destructor - { - if (m_pRecord) - { - m_pRecord = NULL; - } - } - - FINLINE FLMBOOL EndOfRecord() // TRUE = End-of-Record has been reached - { - return( - m_pvField == NULL ? TRUE - : (m_pRecord->getLevel( m_pvField) <= m_uiRootLevel - && !m_bStillAtTheRoot) ? TRUE : FALSE); - } - - FINLINE void Advance() // Advance cursor to next field - { - m_bStillAtTheRoot = FALSE; - if ( m_pvField) - { - m_pvField = m_pRecord->next( m_pvField); - m_uiAbsoluteCursorPosition++; - } - } - - FLMBOOL FieldValueIsEqualTo( - RecCursor * pSomeField); - - - /**************************************************************************** - Desc: Determine if the IDs of 2 fields are equal - Return: TRUE = the IDs are equal - ASSUMPTIONS: pField1 and pField2 are not NULL - ****************************************************************************/ - FINLINE FLMBOOL FieldIdIsEqualTo( - RecCursor * pSomeField) - { - return( - Level() == pSomeField->Level() - && m_pRecord->getFieldID( m_pvField) == - pSomeField->m_pRecord->getFieldID( pSomeField->m_pvField) - && m_pRecord->getDataType( m_pvField) == - pSomeField->m_pRecord->getDataType( pSomeField->m_pvField) - ? TRUE : FALSE); - } - - - enum RecFieldMatchTypes - { - GRD_NoMatch, // no match was found - GRD_ExactMatch, // an exact match was found - GRD_IDMatch // A field with the same ID was found, but the - // value was different. ID = level+tNum+type - }; - - void * Scan( - RecCursor * pTargetCursor, - RecFieldMatchTypes * peMatchType); - - - FINLINE FLMUINT AbsolutePosition()// Return the 1-based position of the - { // current field - return( m_uiAbsoluteCursorPosition ); - } - - FINLINE void * Field() // Return a pointer to the current field - { - return( m_pvField); - } - - FINLINE FlmRecord * Record() // Return a pointer to the current record - { - return( m_pRecord); - } - - FINLINE FLMUINT Level() // Return the normalized level of the - { // current field - return( m_pvField ? Normalize( m_pRecord->getLevel( m_pvField)) : 0 ); - } - - FINLINE FLMUINT RawLevel() // Return the level in its raw, - { // unnormalized form. - return( m_pvField ? m_pRecord->getLevel( m_pvField) : 0 ); - } - - FINLINE void CallBack( // Call the caller's callback function - GRD_DifferenceData &difference) - { - (*m_pCallBack)( difference, m_pvCallBackData ); - } - - - - /* Class methods ---------------------------------------------------------*/ - - static void MarkBranchDeleted( - RecCursor * pBeforeCursor, - RecCursor * pAfterCursor); - - static void MarkModified( - RecCursor * pBeforeCursor, - RecCursor * pAfterCursor); - - static void MarkInserted( - RecCursor * pCursor); - - static void MarkRangeInserted( - RecCursor * pAfterCursor, - void * pEndOfRange); - -private: - - FLMUINT m_uiAbsoluteCursorPosition;// 1-based Absolute position of cursor - FlmRecord * m_pRecord; // Pointer to current node - void * m_pvField; - FLMUINT m_uiRootLevel; // Level of the root field - GRD_CallBackFunction m_pCallBack;// Pointer to caller's callback function - void * m_pvCallBackData; // Pointer to caller's data - FLMBOOL m_bStillAtTheRoot; // TRUE = cursor is still on the root field - - - /* Methods */ - RecCursor(){} // Not allowed - - FINLINE FLMUINT Normalize( - FLMUINT level) - { /* Field levels must be normalized when comparing the levels of two fields - from different records. This allows the "root fields" of the - 2 records to have different levels. */ - return( level - m_uiRootLevel ); - } - - FINLINE FLMBOOL isLeafField() - { - void * pvNext = m_pRecord->next( m_pvField); - - //It is valid to compare raw node levels of nodes within the same record - return( - (pvNext - && m_pRecord->getLevel( pvNext) > m_pRecord->getLevel( m_pvField) ) - ? FALSE // Field has children, not a leaf field. - : TRUE); - } -}; - - -/* - * Large instance method implementations - */ - -/**************************************************************************** -Desc: Determine if 2 fields' values are equal -Return: TRUE = the 2 values are equal -ASSUMPTIONS: pField1 and pField2 are not NULL -****************************************************************************/ -FLMBOOL RecCursor::FieldValueIsEqualTo( - RecCursor * pSomeField) -{ - FLMBOOL bEqual = FALSE; - FLMUINT uiFieldLen = m_pRecord->getDataLength( m_pvField); - FLMUINT uiSomeLen = pSomeField->m_pRecord->getDataLength( pSomeField->m_pvField); - FLMUINT uiEncFieldLen = 0; - FLMUINT uiEncSomeLen = 0; - const FLMBYTE * pValue1; - const FLMBYTE * pValue2; - - // If the data lengths are not equal, we can exit. - - if( uiFieldLen != uiSomeLen) - { - goto Exit; - } - - // If one field is encrypted and the other is not, then we can exit. - - if ((m_pRecord->isEncryptedField( m_pvField) && - !pSomeField->m_pRecord->isEncryptedField( pSomeField->m_pvField)) || - (!m_pRecord->isEncryptedField( m_pvField) && - pSomeField->m_pRecord->isEncryptedField( pSomeField->m_pvField))) - { - goto Exit; - } - - // If the fields are encrypted, are they using the same encryption scheme? - - if (m_pRecord->isEncryptedField( m_pvField)) - { - if (m_pRecord->getEncryptionID( m_pvField) != - pSomeField->m_pRecord->getEncryptionID( pSomeField->m_pvField)) - { - goto Exit; - } - } - - // If the field is not encrypted, and we have a value length - - if( uiFieldLen && !m_pRecord->isEncryptedField( m_pvField)) - { - pValue1 = m_pRecord->getDataPtr( m_pvField); - pValue2 = pSomeField->m_pRecord->getDataPtr( pSomeField->m_pvField); - - // If the values are not equal, we can exit. - if( f_memcmp( pValue1, pValue2, uiFieldLen) != 0 ) - { - goto Exit; - } - } - - // Otherwise, if the field is encrypted, we need to check the encrypted value. - - else if (m_pRecord->isEncryptedField( m_pvField)) - { - uiEncFieldLen = m_pRecord->getEncryptedDataLength( m_pvField); - uiEncSomeLen = pSomeField->m_pRecord->getEncryptedDataLength( - pSomeField->m_pvField); - - // If the encrypted lengths are not equal, we can exit. - - if (uiEncFieldLen != uiEncSomeLen) - { - goto Exit; - } - - if (uiEncFieldLen) - { - pValue1 = m_pRecord->getEncryptionDataPtr( m_pvField); - pValue2 = pSomeField->m_pRecord->getEncryptionDataPtr( pSomeField->m_pvField); - - // If the encrypted values are not equal, we can exit. - - if( f_memcmp( pValue1, pValue2, uiFieldLen) != 0 ) - { - goto Exit; - } - } - } - - // If we get this far, the fields are identical. - - bEqual = TRUE; - -Exit: - - return( bEqual); - -} - - -/**************************************************************************** -Desc: Scan for the field referenced by the target cursor -out: eMatchType: - GRD_NoMatch = the target field could not be found in this - record - GRD_IDMatch = the target field was found in this record; - however, the value was changed. - GRD_ExactMatch = the target field was found in this record -Return: A pointer to the field in this record that matches the target field. - If no match was found, return NULL. -****************************************************************************/ -void * RecCursor::Scan( - RecCursor * pTargetCursor, - RecFieldMatchTypes * peMatchType) -{ - void * pvIDMatch = NULL; - FLMUINT uiTargetLevel = pTargetCursor->Level(); - FLMBOOL bAdvanced = FALSE; - - *peMatchType = GRD_NoMatch; - - for( RecCursor candidate = this ; - candidate.Level() >= uiTargetLevel && !candidate.EndOfRecord() ; - candidate.Advance(), bAdvanced = TRUE ) - { - if( pTargetCursor->FieldIdIsEqualTo( &candidate)) - { - if( pTargetCursor->FieldValueIsEqualTo( &candidate)) - { - *peMatchType = GRD_ExactMatch; - return( candidate.Field() ); - } - else if( *peMatchType == GRD_NoMatch) - { - if ( !bAdvanced && isLeafField()) - { - /* Only allow ID matches on leaf fields, when cursor hasn't - advanced */ - *peMatchType = GRD_IDMatch; - pvIDMatch = candidate.Field(); - } - } - } - } - - return( pvIDMatch); -} - - -/* - * Class Method implementations - */ - - -/**************************************************************************** -Desc: Mark the 'before field,' and all of its children, as deleted - the - field doesn't exist in the 'after record'. - -Note: It is valid to compare raw field levels of fields within the same - record. -****************************************************************************/ -void RecCursor::MarkBranchDeleted( - RecCursor * pBeforeCursor, - RecCursor * pAfterCursor) -{ - GRD_DifferenceData difference; - FLMUINT uiStartLevel = pBeforeCursor->RawLevel(); - - difference.type = GRD_DeletedSubtree; - difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); - difference.pBeforeRecord = pBeforeCursor->Record(); - difference.pvBeforeField = pBeforeCursor->Field(); - difference.pAfterRecord = NULL; - difference.pvAfterField = NULL; - - pBeforeCursor->CallBack( difference ); - difference.type = GRD_Deleted; - do - { - pBeforeCursor->CallBack( difference ); - pBeforeCursor->Advance(); - } while( !pBeforeCursor->EndOfRecord() - && pBeforeCursor->RawLevel() > uiStartLevel); -} - -/**************************************************************************** -Desc: Mark the field as modified - the value of the field in the 'after - field' is different than the value in the 'before field' -****************************************************************************/ -void RecCursor::MarkModified( - RecCursor * pBeforeCursor, - RecCursor * pAfterCursor) -{ - GRD_DifferenceData difference; - - difference.type = GRD_Modified; - difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); - difference.pBeforeRecord = pBeforeCursor->Record(); - difference.pvBeforeField = pBeforeCursor->Field(); - difference.pAfterRecord = pAfterCursor->Record(); - difference.pvAfterField = pAfterCursor->Field(); - - pBeforeCursor->CallBack( difference); -} - -/**************************************************************************** -Desc: Mark the field as inserted - the field doesn't exist in the 'before - record' -****************************************************************************/ -void RecCursor::MarkInserted( - RecCursor * pAfterCursor) -{ - GRD_DifferenceData difference; - - difference.type = GRD_Inserted; - difference.uiAbsolutePosition = pAfterCursor->AbsolutePosition(); - difference.pBeforeRecord = NULL; - difference.pvBeforeField = NULL; - difference.pAfterRecord = pAfterCursor->Record(); - difference.pvAfterField = pAfterCursor->Field(); - - pAfterCursor->CallBack( difference ); -} - -/**************************************************************************** -Desc: Mark all of the fields as inserted, starting with the current field - and ending with, but not including, the field referenced by - 'pEndOfRange' -****************************************************************************/ -void RecCursor::MarkRangeInserted( - RecCursor * pAfterCursor, - void * pEndOfRange) -{ - void * pvField; - - for( pvField = pAfterCursor->Field(); - pvField != pEndOfRange ; pvField = pAfterCursor->Field() ) - { - /* Note that MarkInserted will advance the field pointer */ - RecCursor::MarkInserted( pAfterCursor); - pAfterCursor->Advance(); - } -} - - -/**************************************************************************** -Desc: Find the differences between the 2 records. -Notes: This algorithm is intended to be accurate; however it does not always - generate the smallest number of differences. Here is an example - where the algorithm generates more differences than the optimal: - - e e - \ \ - a1 a1-prime - \ \ - v11 v11 - | | - huge-subtree huge-subtree - / / - a2 a2 - \ \ - v21 v21 - | | - v22 v22 - - In this case, the optimal results would be: - 'a1' was modified - Unfortunately, this algorithm will generate: - 'a1' was deleted - 'v11' was deleted - 'huge-subtree' was deleted <-- this is the bad news - 'a1-prime' was inserted - 'v11' was inserted - 'huge-subtree' was inserted <-- this is the other bad news - - - It will take more memory and code to handle cases like these - more optimally. -****************************************************************************/ - -void flmRecordDifference( - FlmRecord * pBefore, // 'before' record - FlmRecord * pAfter, // 'after' record - GRD_CallBackFunction pCallBackFunction,// call this function for each difference - void * pvCallBackData) // Pass this data as a parameter to the callback -{ - RecCursor beforeCursor( pBefore, pCallBackFunction, pvCallBackData); - RecCursor afterCursor( pAfter, pCallBackFunction, pvCallBackData); - - // Iterate through all of the fields in the 'before record' - while( ! beforeCursor.EndOfRecord()) - { - void * pvFound; - RecCursor::RecFieldMatchTypes eMatchType; - - if ( afterCursor.EndOfRecord() ) - { /* The end of the 'after record' has been reached. This means that - the 'before field' must have been deleted from the 'after record' */ - RecCursor::MarkBranchDeleted( &beforeCursor, &afterCursor ); - continue; - } - - pvFound = afterCursor.Scan( &beforeCursor, &eMatchType); - if( pvFound) - { - // 'before field' found in 'after record' - - //Mark all intervening 'after fields' as inserted - RecCursor::MarkRangeInserted( &afterCursor, pvFound); - if( eMatchType == RecCursor::GRD_IDMatch) - { - // 'before field' was modified in 'after record' - RecCursor::MarkModified( &beforeCursor, &afterCursor); - } - else /* eMatchType == GRD_ExactMatch */ - { // 'before field' == 'after field', advance to next field - } - afterCursor.Advance(); - beforeCursor.Advance(); - } - else - { - // 'before field' has been deleted from 'after record' - RecCursor::MarkBranchDeleted( &beforeCursor, &afterCursor); - } - - } /* End of While */ - - /* The end of the 'before record' has been reached, all remaining - 'after fields' must have been inserted */ - RecCursor::MarkRangeInserted( &afterCursor, NULL); -} - - -/* -Text differencing -*/ - -class StringCursor : public F_Base -{ - -public: - StringCursor( //Constructor - FLMBYTE * string, - FLMUINT length, - GSD_CallBackFunction pCallBackFunction, - void * pvCallBackData) - { - m_pString = string; - m_uiLength = length; - m_uiCursor = 0; - m_pCallBack = pCallBackFunction; - m_pvCallBackData = pvCallBackData; - - m_eSubState = GSD_Initial; - m_uiSubStart = 0; - m_uiSubLength = 0; - } - - virtual ~StringCursor(){} // Destructor - - - FINLINE FLMBOOL EndOfString() //TRUE = the end of the string has been reached - { - return( - m_pString == NULL ? - TRUE - : m_uiCursor >= m_uiLength ? TRUE : FALSE); - } - - FINLINE void Advance() //Advance the cursor to the next byte - { - if ( m_uiCursor < m_uiLength ) - { - m_uiCursor++; - } - } - - FINLINE void Advance( //Advance the cursor to the given position - FLMUINT uiPosition) - { - if ( uiPosition < m_uiLength) - { - m_uiCursor = uiPosition; - } - } - - FINLINE void AdvanceToEndOfString()//Advance the cursor to the end of the string - { - m_uiCursor = m_uiLength; - } - - FINLINE FLMBYTE Byte() //Return the byte the cursor is on - { - flmAssert( m_uiCursor < m_uiLength); - - return( m_pString[ m_uiCursor]); - } - - - /* Look for 'aByte' in the string, starting at the cursor. If the byte if - found, then return TRUE. Also return the offset of the byte relative - to the start of the string */ - FINLINE FLMBOOL Scan( //Scan for the presence of a given byte - FLMBYTE aByte, - FLMUINT &lLocation) - { - for( FLMUINT i = m_uiCursor; i < m_uiLength ; i++ ) - { - if ( m_pString[i] == aByte ) - { - lLocation = i; - return( TRUE ); - } - } - return( FALSE ); - } - - - enum GSD_SubState - { - GSD_Initial, // No substring has been started - GSD_BuildingASubString // A substring has been started - }; - - - FINLINE void MarkSubString( // Mark a substring as Inserted or Deleted - GSD_DifferenceType type) - { - if ( m_eSubState == GSD_BuildingASubString) - { - GSD_DifferenceData difference; - - m_eSubState = GSD_Initial; - MarkEndOfSubString(); - - if ( m_uiSubLength ) - { - // notify the caller that a difference has been found - difference.type = type; - difference.pSubString = m_pString + m_uiSubStart; - difference.uiLength = m_uiSubLength; - difference.uiPosition = m_uiSubStart; - CallBack( difference ); - } - } - /* Else there is no substring to mark, just return */ - } - - FINLINE void MarkStartOfSubString()//Start tracking a substring - { - if ( m_eSubState == GSD_Initial ) - { - m_eSubState = GSD_BuildingASubString; - m_uiSubStart = m_uiCursor; - } - /* Else a substring already exists, just return */ - } - - -private: - - FINLINE void MarkEndOfSubString() - { - m_uiSubLength = m_uiCursor - m_uiSubStart; - } - - FINLINE void CallBack( // Call the caller's callback function - GSD_DifferenceData &difference) - { - (*m_pCallBack)( difference, m_pvCallBackData); - } - - - StringCursor(){} // Not allowed - - FLMBYTE * m_pString; // Pointer to the string of bytes - FLMUINT m_uiLength; // number of bytes in the string - FLMUINT m_uiCursor; // offset of current byte in string - - /* Each StringCursor object can keep track of one substring */ - GSD_SubState m_eSubState; // the state of the substring - FLMUINT m_uiSubStart; // offset of start of substring - FLMUINT m_uiSubLength; // length of substring - - GSD_CallBackFunction m_pCallBack;// Pointer to caller's callback function - void * m_pvCallBackData;// Pointer to caller's data -}; - -/**************************************************************************** -Desc: Find the differences between the 2 strings. The strings are not - assumed to be NULL-terminated, thus the required length parameter. -Notes: This algorithm is intended to be accurate; however it does not always - generate the smallest number of differences. Like - flmRecordDifference, there cases where less than the optimal - number of differences are reported. -****************************************************************************/ -void flmStringDifference( - FLMBYTE * pBefore, - FLMUINT lBeforeLength, - FLMBYTE * pAfter, - FLMUINT lAfterLength, - GSD_CallBackFunction pCallBackFunction, - void * pvCallBackData) -{ - FLMUINT uiPosition; - StringCursor beforeCursor( pBefore, lBeforeLength, pCallBackFunction, - pvCallBackData); - - StringCursor afterCursor( pAfter, lAfterLength, pCallBackFunction, - pvCallBackData); - - - // Iterate through all of the bytes in the 'before string' - while ( ! beforeCursor.EndOfString() ) - { - if ( afterCursor.EndOfString() ) - { /* The end of the 'after string' has been reached, mark the remainder - of the 'before string' as deleted */ - beforeCursor.MarkStartOfSubString(); - beforeCursor.AdvanceToEndOfString(); - beforeCursor.MarkSubString(GSD_Deleted); - break; - } - - if ( beforeCursor.Byte() == afterCursor.Byte() ) - { // The 'before' and 'after' bytes are the same, advance both cursors - - /* If there is no substring to mark deleted, then this method - invocation is a no-op */ - beforeCursor.MarkSubString(GSD_Deleted); - - beforeCursor.Advance(); - afterCursor.Advance(); - } - else - { // The 'before' and 'after' bytes are different, log the difference - - //scan from afterCursor to EndOfString looking for 'before byte' - if ( afterCursor.Scan( beforeCursor.Byte(), uiPosition ) ) - { /* The 'before byte' was found in the 'after string' */ - - /* If there is no substring to mark deleted, then this method - invocation is a no-op */ - beforeCursor.MarkSubString(GSD_Deleted); - - /* Mark the preceding 'after bytes' as inserted */ - afterCursor.MarkStartOfSubString(); - afterCursor.Advance(uiPosition); - afterCursor.MarkSubString(GSD_Inserted); - } - else - { /* The 'before byte' doesn't exist in the 'after string' It must - have been deleted. Add the 'before byte' to a substring to be - marked deleted. */ - - /* If a substring has already been started, then this method - invocation is a no-op */ - beforeCursor.MarkStartOfSubString(); - - beforeCursor.Advance(); - } - } - } - - /* If there is no substring to mark deleted, then this method - invocation is a no-op */ - beforeCursor.MarkSubString(GSD_Deleted); - - if ( ! afterCursor.EndOfString() ) - { /* The end of the 'before string' has been reached, mark the remaining - 'after bytes' as inserted */ - afterCursor.MarkStartOfSubString(); - afterCursor.AdvanceToEndOfString(); - afterCursor.MarkSubString(GSD_Inserted); - } -} // End of flmStringDifference - diff --git a/flaim/src/gddiff.h b/flaim/src/gddiff.h deleted file mode 100644 index 810e7f1..0000000 --- a/flaim/src/gddiff.h +++ /dev/null @@ -1,188 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Difference two FlmRecord objects - class definitions. -// Tabs: 3 -// -// Copyright (c) 1998-2000,2002-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gddiff.h 12305 2006-01-19 15:04:41 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#ifndef GDDIFF_H -#define GDDIFF_H - -#include "fpackon.h" -// IMPORTANT NOTE: No other include files should follow this one except -// for fpackoff.h - -enum GRD_DifferenceType -{ - GRD_Inserted, - GRD_Deleted, - GRD_Modified, - GRD_DeletedSubtree -}; - -typedef struct -{ - GRD_DifferenceType type; /* The 'type' indicates the nature - of the difference, and can have one of the following values: - GRD_Inserted: a field was inserted. In this case, the field only exists - in the 'after record.' 'pAfterField' points to the - inserted field. 'pBeforeField' == NULL. - GRD_Deleted: a field was deleted. In this case, the field only exists in - the 'before record'. 'pBeforeField' points to the - deleted field. 'pAfterField' == NULL. - GRD_Modified: a field was modified. In this case, 'pBeforeField' points - to the field before it was modified, and 'pAfterField' - points to the field after it was modified. - GRD_DeletedSubtree: a sub-tree was deleted. In this case, the sub-tree only exists in - the 'before record'. 'pBeforeField' points to the - deleted sub-tree. 'pAfterField' == NULL. */ - - - FLMUINT uiAbsolutePosition; /* 'uiAbsolutePosition' is the - 1-based position where the - difference occured. - When using the list of differences generated by flmRecordDifference to - undo changes, uiAbsolutePosition can be thought of as the 1-based position - relative to the 'after record.' In order for 'undo' to work correctly, - the differences must be undone in reverse order. - When using the list of differences to redo changes, uiAbsolutePosition - can be thought of as the 1-based position relative to the 'before - record.' In order for 'redo' to work correctly, the differences must be - redone in order. Note that when a node is inserted or deleted, all - subsequent nodes are, in essence, renumbered. */ - - FlmRecord * pBeforeRecord; - - FlmRecord * pAfterRecord; - - void * pvBeforeField; /* 'pvBeforeField' is a pointer to - the field before the change. - There are situations where - 'pBeforeField' will be NULL. - See a description of the 'type' - for more details. */ - - void * pvAfterField; /* 'pvAfterField' is a pointer to the - field after the change. There are - situations where 'pBeforeField' - will be NULL. See a description - of the 'type' for more details. */ -} GRD_DifferenceData; - - -/* - * Function prototypes for record differencing - */ - -typedef void (* GRD_CallBackFunction)(//Called for each difference found - GRD_DifferenceData &difference,//Description of difference - void * pCallBackData); //User-defined data - -/**************************************************************************** -Desc: Return the differences between the 'before' and 'after' record -In: pBeforeRecord - pointer to the record before any changes were - made. - pAfterRecord - pointer to the record after changes were made. - pCallBackFunction - pointer to a function that will be called for each - difference found. - pCallBackData - pointer to data that will be passed as a parameter to - the call back function. This data is defined by the - caller. -Note: In addition to the call back data, a GRD_DifferenceData structure is - passed to the callback function. For a description of this structure, - please refer to its definition. -****************************************************************************/ -void flmRecordDifference( - FlmRecord * pBeforeRecord, - FlmRecord * pAfterRecord, - GRD_CallBackFunction pCallBackFunction, - void * pvCallBackData); - -/* - * Data definitions for string differencing - */ - -enum GSD_DifferenceType -{ - GSD_Inserted, - GSD_Deleted -}; - -typedef struct -{ - GSD_DifferenceType type; /* The 'type' indicates the nature - of the difference: Inserted or - Deleted.*/ - - FLMBYTE * pSubString; /* A pointer to the bytes that were - inserted or deleted. Note that - this pointer points into either the 'before' or 'after' string passed - into flmStringDifference. As a result, the callback function should - treat these substrings as read-only data. */ - - FLMUINT uiLength; /* The number of bytes that were - inserted or deleted */ - - FLMUINT uiPosition; /* 0-based position where the - substring was inserted or deleted. - When using the list of differences generated by flmStringDifference to - undo changes, the differences must be undone in reverse order. - When using the list of differences to redo changes, the differences - must be redone in order. Note that when a substring is inserted or - deleted, all subsequent bytes are, in essence, renumbered. */ -} GSD_DifferenceData; - - - -/* - * Function prototypes for string differencing - */ - -typedef void (* GSD_CallBackFunction)(//Called for each difference found - GSD_DifferenceData &difference,//Description of difference - void * pvCallBackData); //User-defined data - -/**************************************************************************** -Desc: Find the differences between the 2 strings. The strings are not - assumed to be NULL-terminated, thus the required length parameter. -In: pBefore - pointer to the string before any changes were made. - lBeforeLength - number of bytes in 'before string' - pAfter - pointer to the string after changes were made. - lBeforeLength - number of bytes in 'after string' - pCallBackFunction - pointer to a function that will be called for each - difference found. - pvCallBackData - pointer to data that will be passed as a parameter to - the call back function. This data is defined by the - caller. -Note: In addition to the call back data, a GSD_DifferenceData structure is - passed to the callback function. For a description of this structure, - please refer to its definition. -****************************************************************************/ -void flmStringDifference( - FLMBYTE * pBefore, - FLMUINT uiBeforeLength, - FLMBYTE * pAfter, - FLMUINT uiAfterLength, - GSD_CallBackFunction pCallBackFunction, - void * pvCallBackData); - -#include "fpackoff.h" - -#endif // GDDIFF_H diff --git a/flaim/src/gdfind.cpp b/flaim/src/gdfind.cpp deleted file mode 100644 index cd5424b..0000000 --- a/flaim/src/gdfind.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Find a node in a GEDCOM tree structure. -// Tabs: 3 -// -// Copyright (c) 1990-1993,1996-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gdfind.cpp 12307 2006-01-19 15:06:34 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~********************************************************************* -Name : GedFind -Area : GEDCOM -Desc : Gets the nth occurance of the node with a matching tag number. - Continues, if necessary, thru a limited number of sibling sub-trees. - If "treeCnt" is GED_FOREST(0), it continues thru virtually all sub-trees. - matches occur without regard to path (always assumes leading wild card) -Note: -*END************************************************************************/ -NODE * - // Returns a pointer to the nth occurance of the node with a matching - // tag or NULL if unsuccesful. If a value less than 0 is - // given for nth, the first value will be returned. If a - // value greater than the number of occurances is given, - // NULL will be returned. - GedFind( - FLMUINT treeCnt, - // [IN] Maximum number of sibling trees to search. - NODE * nd, - // [IN] GEDCOM tree or forest to search for matching tnum. - FLMUINT tnum, - // [IN] Specific tag number to find. - FLMINT nth - // [IN] The occurance of the tag number to find. - ) -{ - if( nd) - { - FLMUINT strtLvl = GedNodeLevel( nd); /* Starting level */ - do - { - if( (tnum == GedTagNum( nd)) && (--nth < 1)) - return( nd); - - } while( - (nd = nd->next) != NULL && - ( - GedNodeLevel( nd) > strtLvl || - (--treeCnt && GedNodeLevel( nd) == strtLvl) - ) - ); - } - return( NULL); -} - - -/*API~********************************************************************* -Name : GedNodeCopy -Area : GEDCOM -Desc : Gets the "nth" occurance of the node with a matching path of tag numbers. - This path may be found in the first tree only, the entire forest or - within the first "treeCnt" of trees. -Notes: This routine does not support any wildcard tags. -VISIT: This code has some bugs, one of which is that the - path array may be accessed past the null terminator. -*END************************************************************************/ -NODE * - // Returns the nth occurance of the node at the end of the - //path or NULL if unsuccesful. If a value less than 0 is - //given for nth, the first value will be returned. If a - //value greater than the number of occurances is given, - //NULL will be returned. - GedPathFind( - FLMUINT treeCnt, - // [IN] Maximum number of sibling tress to search. - NODE * nd, - // [IN] The input GEDCOM tree to search for matching path. - FLMUINT * puiPathArray, - // [IN] A null terminated array of field numbers which make - // up a path. - FLMINT nth - // [IN] The occurance of the matching path to return. This - // value is usualy one. - ) -{ - NODE * node = nd; - NODE * savenode; - FLMUINT * path; - - if( nd && puiPathArray) - { - FLMUINT uiLevel = GedNodeLevel( nd); - for(;;) - { - path = puiPathArray + (GedNodeLevel( node) - uiLevel); - savenode = node; - if( *path == GedTagNum( node)) /* matching piece of path */ - { - if( *(path + 1) == 0 && (--nth < 1)) - return( node); /* complete match found */ - if( (node = GedChild( node)) != NULL) - continue; /* go down level for rest of path */ - node = savenode; - } - - do - { - node = node->next; - } - while( node != NULL && - GedNodeLevel( node) > GedNodeLevel( savenode)); /* find next sibling/uncle/end */ - - if( - ! node || /* end of tree */ - GedNodeLevel( node) < uiLevel || /* end of forest */ - ( - GedNodeLevel( node) == uiLevel && - !(--treeCnt) /* end of partial forest limit */ - ) - ) - break; - } - } - return( NULL); -} - diff --git a/flaim/src/gdgraft.cpp b/flaim/src/gdgraft.cpp deleted file mode 100644 index 64a2f2d..0000000 --- a/flaim/src/gdgraft.cpp +++ /dev/null @@ -1,208 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Graft a node into a GEDCOM tree. -// Tabs: 3 -// -// Copyright (c) 1990-1993,1995-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gdgraft.cpp 12307 2006-01-19 15:06:34 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~*********************************************************************** -Name : GedChildGraft -Area : GEDCOM/LINK -Desc : Links a node or sub-tree as a child of an existing node. -*END************************************************************************/ -NODE * - // A pointer to the parent node is returned. - GedChildGraft( - NODE * parent, - // [IN] Pointer to the node to which the child will be linked. - NODE * child, - // [IN] Pointer to the child node. - FLMINT nth - // [IN] Determines where the child will be linked. Use GED_FIRST - // or GED_LAST to link as the first or last child of the parent. - // Otherwise, set nth to the ordinal number of the existing - // child to which the new child should be linked. For - // example, set nth to 1 to link after the 1st existing child. - // If no children currently exist, nth may be any value. - // - // Note: The child node must not be connected to anything else. - // If the child node is already linked to another node, - // unpredictable results (such as circular trees) could occur. - ) -{ - NODE * lastChildNode; /* Used when child is sub-tree */ - - if( parent && child) - { - FLMINT level = GedNodeLevel( parent) + 1; - - if( GedChild( parent)) /* Parent already has child(ren) */ - { - GedSibGraft( - GedChild( parent), /* graft as sib of 1st child instead */ - child, - (FLMINT)(nth == GED_FIRST /* subtacting 1 could wrap to GED_LAST */ - ? GED_FIRST /* don't wrap */ - : nth - 1) /* graft now relative to 1st child */ - ); - } - else /* Parent has no children */ - { - for( /* find end of child's sub-tree */ - lastChildNode = child - ; lastChildNode->next - ; GedNodeLevelAdd( lastChildNode, level), /* adjust level of sub-tree nodes */ - lastChildNode = lastChildNode->next - ); - child->prior = parent; - GedNodeLevelAdd( lastChildNode, level); /* adjust last node's level */ - lastChildNode->next = parent->next; - if( parent->next) - parent->next->prior = lastChildNode; - parent->next = child; - } - } - return( parent); -} -/*API~*********************************************************************** -Name : GedSibGraft -Area : GEDCOM/LINK -Desc : Links a node or sub-tree as a sibling of an existing node. -DNote: GED_LAST and GED_FIRST are #define's of +/- 32k. These are practical - assumptions. Their actual value is not tested--the loop continues - for that count or until no further siblings are found. That is to say, - if there are too many siblings in the list, a true LAST or FIRST is not - reached. Since all "nth" parameters are WORD typed, other routines - would have the same problem. -*END************************************************************************/ -NODE * - // A pointer to self or sib is returned depending upon which one - // occurs first in the sibling list. If sib occurs first, a - // pointer to sib is returned. Otherwise, a pointer to self is - // returned. - GedSibGraft( - NODE * self, - // [IN] Pointer to the node to which the child will be linked. - NODE * sib, - // [IN] Pointer to the node which is to be linked as a sibling. - FLMINT nth - // [IN] Determines where the sibling will be linked. Use GED_FIRST - // or GED_LAST to link as the first or last sibling of self. - // Otherwise, set nth to an ordinal number (relative to self) to - // specify which sibling that sib should be linked after. Zero - // will cause sib to be linked directly after self and a value of - // -1 will cause sib to be linked after the prior sibling. - // - // Note: The sib node must not be connected to anything else. - // If the node is already linked to another node, unpredictable - // results (such as circular trees) could occur. - ) -{ - NODE * lastSibNode; - NODE * returnNode; - FLMINT deltaLevel; - FLMUINT level; - FLMUINT linkAt = TRUE; - - if( ! sib) - return( self); - if( ! self) - return( sib); - - for( /* find end of sib's sub-tree */ - level = GedNodeLevel( self), - deltaLevel = (FLMINT)(level - GedNodeLevel( sib)), - /* Compute delta to modify sib tree*/ - lastSibNode = sib - ; lastSibNode->next - ; GedNodeLevelAdd( lastSibNode, deltaLevel), /* adjust level of sub-tree nodes */ - lastSibNode = lastSibNode->next - ); - - GedNodeLevelAdd( lastSibNode, deltaLevel); /* adjust last node's level */ - if (nth != GED_LAST ) /* Adjust nth to be zero based */ - nth++; /* in order to work with algorithm */ - - if( nth <= 0) /* going up sibling list */ - { - returnNode = sib; - while( nth) /* stop when nth is -1 */ - { - if( self->prior) - { - self = self->prior; - if( GedNodeLevel( self) > level) /* nephew here */ - continue; /* skip sub-tree */ - else if( GedNodeLevel( self) == level) /* true sibling here */ - { - nth++; /* count up to zero (nth < 0) */ - continue; - } - /* else no prior siblings; at parent */ - self = self->next; /* point back to first child */ - } - break; /* graft as first sibling in list */ - } - } - else /* going down sibling list */ - { - returnNode = self; - while( nth) /* stop after nth node */ - { - if( self->next) - { - self = self->next; - if( GedNodeLevel( self) > level) - continue; /* skip sub-tree */ - else if( GedNodeLevel( self) == level) - { - nth--; /* count down to zero (nth > 0) */ - continue; - } - /* else no following siblings */ - self = self->prior; /* point back to prior node */ - } - linkAt = FALSE; /* Link AFTER the self node */ - break; /* graft as last sibling in list */ - } - } - if( linkAt) - { - /* Link the sib tree AT the current self location - link before self */ - sib->prior = self->prior; - lastSibNode->next = self; - if( self->prior) - self->prior->next = sib; - self->prior = lastSibNode; - } - else /* link AFTER */ - { - /* Link the sib tree AFTER the current self location */ - sib->prior = self; - lastSibNode->next = self->next; - if( self->next) - self->next->prior = lastSibNode; - self->next = sib; - } - return( returnNode); -} - diff --git a/flaim/src/gdmisc.cpp b/flaim/src/gdmisc.cpp deleted file mode 100644 index c26251e..0000000 --- a/flaim/src/gdmisc.cpp +++ /dev/null @@ -1,571 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Miscellaneous GEDCOM routines. -// Tabs: 3 -// -// Copyright (c) 1992,1994-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gdmisc.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/* Offset from the end of the node to each record source element */ -#define NODE_DRN_POS 0 -#define NODE_CONTAINER_POS (NODE_DRN_POS + sizeof( FLMUINT)) -#define NODE_DB_POS (NODE_CONTAINER_POS + sizeof( FLMUINT)) - -/*API~********************************************************************* -Name : GedNodeCreate -Area : GEDCOM -Desc : Allocates space for a new GEDCOM node. Returns a pointer to the - node or NULL if an allocation error occurs. -Notes: -****************************************************************************/ -NODE * GedNodeCreate( - POOL * pPool, - FLMUINT tagNum, - FLMUINT id, - RCODE * rc) -{ - NODE * nd; - - if( (nd = (NODE *)GedPoolAlloc( pPool, - ( sizeof(NODE) + (id ? sizeof(id) : 0)))) == NULL) - { - *rc = RC_SET( FERR_MEM); - } - else - { - f_memset( nd, '\0', sizeof( NODE)); - - GedValTypeSet( nd, FLM_CONTEXT_TYPE); - GedTagNumSet( nd, tagNum); - - if( id) - { - FLMBYTE * ptr; - GedValTypeSetFlag( nd, HAS_REC_ID); /* Must set the ID before getting ptr */ - ptr = ((FLMBYTE *) nd) + sizeof(NODE); /* If we call GedIdPtr */ - *((FLMUINT *)(ptr + NODE_DRN_POS)) = id; - } - *rc = FERR_OK; - } - - return( nd); -} - -/**************************************************************************** -Desc: This routine allocates space in a GEDCOM node for a value. If the - node already has the required space, nothing is done. Otherwise, - it calls the PoolAlloc routine to get the needed memory. This - routine also sets the value length and type information. -Note: On FLM_TEXT_TYPE data type one extra byte will be allocated. - This byte will be used for a NULL character. -NOTE: WARNING - If there is a length then the ptr value may be reused. - This could cause problems with reusing GEDCOM memory and using - the pool marker. -****************************************************************************/ -void * GedAllocSpace( - POOL * pPool, - NODE * node, - FLMUINT valType, - FLMUINT size, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - FLMBYTE * rPtr; /* Return Pointer */ - FLMUINT uiAllocSize = size; - - if( valType == FLM_TEXT_TYPE) - uiAllocSize++; - - if( uiAllocSize <= sizeof( void *)) - { - /* If the size is less than sizeof (void *), we use the space right */ - /* inside value pointer itself. */ - - rPtr = (FLMBYTE *) &node->value; - } - - /* BUG 10/1/96: Don't use wAllocSize here */ - - else if( size <= GedValLen( node)) - { - /* If there is already allocated space, just re-use it */ - - rPtr = (FLMBYTE *)GedValPtr( node); - } - - else - { - /* At this point, we know we have to allocate space elsewhere. - ** NOTE: If we are unable to allocate the space required, DO - ** NOT modify the node -- return NULL immediately. - */ - - if( (node->value = rPtr = - (FLMBYTE *) GedPoolAlloc( pPool, uiAllocSize)) == NULL) - { - /* VISIT: 10/1/96: Comment above does not agree with this code. */ - - node->ui32Length = 0; - node->value = NULL; - return( NULL); - } - } - if( valType == FLM_TEXT_TYPE) - rPtr[ size] = '\0'; - - /* Now set the size and the data type */ - - node->ui32Length = (FLMUINT32)size; - GedSetType( node, valType); - - // If passed-in enc id is zero, use the node's enc id. - - if (!uiEncId) - { - flmAssert( !uiEncSize); - if (size) - { - uiEncId = node->ui32EncId; - uiEncSize = size + (16 - (size % 16)); - } - } - else - { - - // We only should have an encryption ID if size is non-zero. - // If size is non-zero, encryption size must also be non-zero. - - flmAssert( size); - flmAssert( uiEncSize); - } - - if (uiEncId) - { - if( uiEncSize > GedEncLen( node)) - { - if( (node->pucEncValue = - (FLMBYTE *) GedPoolAlloc( pPool, uiEncSize)) == NULL) - { - node->ui32EncLength = 0; - node->pucEncValue = NULL; - return( NULL); - } - } - node->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA | FLD_HAVE_ENCRYPTED_DATA; - node->ui32EncId = (FLMUINT32)uiEncId; - node->ui32EncLength = (FLMUINT32)uiEncSize; - } - - - return( rPtr); -} - -/**************************************************************************** -Desc: return pointer to value. The value may be store in the node if it's - small enough in size to fit in the void * value pointer slot. -****************************************************************************/ -void * GedValPtr( - NODE * nd) -{ - return( - nd && nd->ui32Length - ? GedValType( nd) == FLM_TEXT_TYPE - ? nd->ui32Length < sizeof( void *) - ? (void *) &nd->value - : (void *) nd->value - : nd->ui32Length > sizeof( void *) /* non-text (no null terminator) */ - ? (void *) nd->value /* value seperate from node */ - : (void *) &nd->value /* value in node's valuePtr space */ - : (void *)NULL /* no node or value */ - ); -} - -/**************************************************************************** -Desc: return pointer to encryption value. -****************************************************************************/ -void * GedEncPtr( - NODE * nd) -{ - return( - nd && nd->ui32EncLength - ? (void *)nd->pucEncValue - : (void *)NULL /* no node or encrypted value */ - ); -} - -/**************************************************************************** -Desc: Allows the user to set the ID (record number, or sub-record number) - for the supplied field. -****************************************************************************/ -RCODE GedPutRecId( - POOL * pPool, - NODE ** ppNd, - FLMUINT uiId) -{ - NODE * pNewNd; - NODE * pOldNd = *ppNd; - FLMBYTE * ptr; - - if( (pNewNd = (NODE *)GedPoolAlloc(pPool, - sizeof( NODE) + sizeof( uiId))) == NULL) - { - *ppNd = NULL; - return( RC_SET( FERR_MEM)); - } - - // Copy the contents of the existing node - - pNewNd->prior = pOldNd->prior; - pNewNd->next = pOldNd->next; - pNewNd->value = pOldNd->value; - pNewNd->ui32Length = pOldNd->ui32Length; - pNewNd->ui32EncId = pOldNd->ui32EncId; - pNewNd->ui32EncLength = pOldNd->ui32EncLength; - pNewNd->ui32EncFlags = pOldNd->ui32EncFlags; - pNewNd->pucEncValue = pOldNd->pucEncValue; - GedTagNumSet( pNewNd, GedTagNum( pOldNd)); - GedNodeLevelSet( pNewNd, GedNodeLevel( pOldNd)); - GedNodeTypeSet( pNewNd, (GedNodeType( pOldNd) | HAS_REC_ID)); - - // Link in new node to parent and children/siblings - - if( pNewNd->prior) - { - pNewNd->prior->next = pNewNd; - } - - if( pNewNd->next) - { - pNewNd->next->prior = pNewNd; - } - - // Set the Ids value - ptr = (FLMBYTE *)GedIdPtr( pNewNd ); - *((FLMUINT *)(ptr + NODE_DRN_POS)) = uiId; - *ppNd = pNewNd; - - return( FERR_OK); -} - -/**************************************************************************** -Desc: Will set the source information in a GEDCOM node. -****************************************************************************/ -void gedSetRecSource( - NODE * pNode, - HFDB hDb, - FLMUINT uiContainer, - FLMUINT uiDrn ) -{ - FLMBYTE * pucPtr; - - pucPtr = ((FLMBYTE *) pNode) + sizeof( NODE); /* Set pucPtr to end of node */ - if( uiDrn) - { - GedValTypeSetFlag( pNode, HAS_REC_ID); - *((FLMUINT *)(pucPtr + NODE_DRN_POS)) = uiDrn; - } - if( uiContainer) - { - GedValTypeSetFlag( pNode, HAS_REC_SOURCE); - *((FLMUINT *)(pucPtr + NODE_CONTAINER_POS)) = uiContainer; - } - if( hDb) - { - GedValTypeSetFlag( pNode, HAS_REC_SOURCE); - *((HFDB *)(pucPtr + NODE_DB_POS)) = hDb; - } -} - -/**************************************************************************** -Desc: Will create a GEDCOM node that contains a FLAIM Database's HFDB, - store number, container number, and record id (DRN). -****************************************************************************/ -RCODE gedCreateSourceNode( - POOL * pPool, /* Users allocation pool */ - FLMUINT uiFieldNum, /* Tag Number */ - HFDB hDb, /* FLAIM Database that record came from */ - FLMUINT uiContainer, /* Container record came from */ - FLMUINT uiRecId, /* Record id (DRN) */ - NODE ** ppNode) /* [out] newly created gedcom source node */ -{ - NODE * nd; - RCODE rc = FERR_OK; - - *ppNode = nd = (NODE *)GedPoolCalloc( pPool, - ( sizeof( NODE) - + sizeof( FLMUINT) /* Record Id (DRN) */ - + sizeof( FLMUINT) /* Container Number */ - + sizeof( HFDB))); /* Database handle */ - if( nd != NULL) - { - GedValTypeSet( nd, FLM_CONTEXT_TYPE); - GedTagNumSet( nd, uiFieldNum); - gedSetRecSource( nd, hDb, uiContainer, uiRecId); - } - else - { - rc = RC_SET( FERR_MEM); - } - - return( rc); -} - -/**************************************************************************** -Desc: Returns the FLAIM database source that this GEDCOM record is from. -Remarks: The root node of each GEDCOM record returned from FLAIM will contain - information about where the record came from. This information is - known as its source information and includes: - Memory Handle to FLAIM Database (HFDB) - Store Number - Container Number - Record Id (DRN) - -Note: Some GEDCOM Nodes may only contain the Record Id, in those cases - calls to GedGetRecSource will return a NULL for the HFDB and 0's for - the Store and Container number (meaning the record has not been - assigned to a FLAIM database yet). -****************************************************************************/ -RCODE GedGetRecSource( - NODE * pNode, /* GEDCOM node to return FLAIM database source - information. */ - HFDB * phDb, /* [out] FLAIM Database that this record came from. - NOTE: This value is only valid while the - database is actually open, and has no persistent - capabilities. */ - FLMUINT * puiContainer,/* [out] Database Container that this record is from.*/ - FLMUINT * puiRecId) /* [out] Database Record Id (DRN) that has been - assigned to this record. This is unique only - within a database's container. */ -{ - RCODE rc = FERR_OK; - FLMBYTE * ptr = ((FLMBYTE *) pNode) + sizeof( NODE); /* Set ptr to end of node */ - - if( GedNodeType( pNode) & HAS_REC_SOURCE) - { - if( phDb) - { - *phDb = *((HFDB *)(ptr + NODE_DB_POS)); - } - - if( puiContainer) - { - *puiContainer = *((FLMUINT *)(ptr + NODE_CONTAINER_POS)); - } - - if( puiRecId) - { - *puiRecId = *((FLMUINT *)( ptr + NODE_DRN_POS)); - } - } - else if( GedNodeType( pNode) & HAS_REC_ID) - { - if( phDb) - { - *phDb = NULL; - } - - if( puiContainer) - { - *puiContainer = 0; - } - - if( puiRecId) - { - *puiRecId = *((FLMUINT *)( ptr + NODE_DRN_POS)); - } - } - else - { /* The record contains no record source, because the user may ignore - the return code lets make sure everything is set to null/0. */ - - if( phDb) - { - *phDb = NULL; - } - - if( puiContainer) - { - *puiContainer = 0; - } - - if( puiRecId) - { - *puiRecId = 0; - } - - rc = RC_SET( FERR_NOT_FOUND); - goto Exit; - } - -Exit: - return( rc); -} - - -/*API~********************************************************************* -Desc: Places the suppolied DRN into a context type node. -*END************************************************************************/ -RCODE GedPutRecPtr( - POOL * pPool, - NODE * nd, - FLMUINT drn, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - void * ptr; - RCODE rc = FERR_OK; - - /* Check for a null node being passed in */ - - if( nd == NULL) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - if( (ptr = GedAllocSpace( pPool, nd, FLM_CONTEXT_TYPE, - sizeof(FLMUINT32), uiEncId, uiEncSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - UD2FBA( (FLMUINT32) drn, ptr); - - if (nd->ui32EncId) - { - nd->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - return( rc); -} - -/*API~********************************************************************* -Name : GedGetRecPtr -Area : GEDCOM -Desc : Obtain the DRN (database record number) from a GEDCOM context type - node. No conversion from other data types will be performed. -*END************************************************************************/ -RCODE // FERR_CONV_ILLEGAL - the input node (nd) is not a context type. - // FERR_CONV_NULL_SRC - The input node (nd) is NULL. - GedGetRecPtr( - NODE * nd, - // [IN] Input GEDCOM node. - FLMUINT * drnRV - // [OUT] Returns the DRN value on SUCCESS. - ) -{ - RCODE rc = FERR_OK; - - *drnRV = (FLMUINT) 0xFFFFFFFF; /* value for "no value" */ - - if( nd == NULL) /* Make sure we have a valid node */ - { - rc = RC_SET( FERR_CONV_NULL_SRC); - goto Exit; - } - - if (nd->ui32EncId) - { - if (!(nd->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( GedValType(nd) != FLM_CONTEXT_TYPE) - { - rc = RC_SET( FERR_CONV_ILLEGAL); /* DIN's doesn't convert */ - goto Exit; - } - - if( GedValLen( nd) == sizeof( FLMUINT32)) - { - *drnRV = (FLMUINT)(FB2UD((FLMBYTE *) GedValPtr( nd))); - } - -Exit: - return( rc); -} - - -/*API~********************************************************************* -Name : GedWalk -Area : GEDCOM -Desc : Traverses a tree or forest of GEDCOM tress. For each GEDCOM node - that is visited, a user specified callback function is called. - - The passed-in function needs to accept the following parameters: - FLMUINT level; * current relative level of this node * - NODE * node; * pointer to current node * - void * arg; * user's passed-thru parameter * - This passed-in function is repeatedly called until its return code is - not SUCCESS, the tree/forest is completely processed, or the count - expires. - -Notes:This function can be extremely useful in many contexts. -*END************************************************************************/ -RCODE GedWalk( - FLMUINT treeCnt, - // [IN] treeCnt is the number of sibling trees to process. - // Pass in GED_TREE to walk through the input node and all - // of its children. Pass in GED_FOREST to walk through the input - // node and all of its siblings as well as all children. A number - // may also be specified to limit the number of trees that are - // walked through. GED_TREE has a value of one. - NODE * node, - // [IN] Pointer to the first node of a GEDCOM tree or forest. - GEDWALK_FUNC_p func, - // [IN] User specified callback function called on every GEDCOM - // node that is visited. - void * arg) - // [IN] Argument used as an argument for the callback function func(). -{ - RCODE rc; - - if( node) /* non-null tree */ - { - FLMUINT baseLevel = GedNodeLevel( node);/* save to know when sub-tree's done */ - do - { - rc = /* save return code for test & exit */ - (*func)( /* passed-in function pointer */ - (GedNodeLevel( node) - baseLevel),/* node's relative level number */ - node, arg); - }while( - RC_OK( rc) && /* stop if( *func) != SUCCESS */ - (node = node->next) != NULL && /* stop if end of tree/forest */ - ( - GedNodeLevel( node) > baseLevel || /* continue while in sub-tree */ - ( - GedNodeLevel( node) == baseLevel &&/* if sibling, decrement treeCnt */ - --treeCnt /* continue if treeCnt != 0 */ - ) - ) /* else, stop if no sibling trees */ - ); - } - else - rc = FERR_OK; /* null tree always SUCCESS */ - - return( rc); -} diff --git a/flaim/src/gdpool.cpp b/flaim/src/gdpool.cpp index 8b766fa..e2d1446 100644 --- a/flaim/src/gdpool.cpp +++ b/flaim/src/gdpool.cpp @@ -102,7 +102,7 @@ FINLINE void UpdateSmartPoolStats( } } -/*API~******************************************************************* +/************************************************************************* Desc: Initialize a smart pool memory structure. A smart pool is one that will adjust it's block allocation size based on statistics it gathers within the POOL_STATS structure. For each pool that user @@ -129,12 +129,12 @@ void GedSmartPoolInit( } } -/*API~*********************************************************************** +/**************************************************************************** Desc: Allocates a block of memory from a memory pool. Note: If the number of bytes is more than the what is left in the current block then a new block will be allocated and the lbkl element of the PMS will be updated. -*END************************************************************************/ +****************************************************************************/ FLMEXP void * FLMAPI GedPoolAlloc( POOL * pPool, FLMUINT uiSize) @@ -203,7 +203,7 @@ Exit: return( (void *) freePtr); } -/*API~******************************************************************** +/************************************************************************ Desc: Allocates memory from a pool and initializes all bytes to zero. *END*********************************************************************/ FLMEXP void * FLMAPI GedPoolCalloc( @@ -219,10 +219,10 @@ FLMEXP void * FLMAPI GedPoolCalloc( return ptr; } -/*API~*********************************************************************** +/**************************************************************************** Desc: Releases all memory allocated to a pool. Note: All memory allocated to the pool is returned to the operating system. -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI GedPoolFree( POOL * pPool) { @@ -248,11 +248,11 @@ FLMEXP RCODE FLMAPI GedPoolFree( return( FERR_OK); } -/*API~*********************************************************************** +/**************************************************************************** Desc: Resets memory blocks allocated to a pool. Note: Will reset the free space in the first memory block, and if any extra blocks exist they will be freed (destroyed). -*END************************************************************************/ +****************************************************************************/ FLMEXP RCODE FLMAPI GedPoolReset( POOL * pPool, void * markPtr) diff --git a/flaim/src/gdtrvrs1.cpp b/flaim/src/gdtrvrs1.cpp deleted file mode 100644 index e326431..0000000 --- a/flaim/src/gdtrvrs1.cpp +++ /dev/null @@ -1,135 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: GEDCOM tree traversal routines. -// Tabs: 3 -// -// Copyright (c) 1990-1993,1996-2000,2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gdtrvrs1.cpp 12308 2006-01-19 15:08:11 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~********************************************************************* -Name : GedSibNext -Area : GEDCOM -Desc : Returns a pointer to the sibling node that is after the input node. - NULL is returned if there is not a next sibling. -Notes: -*END************************************************************************/ -NODE * - // Pointer to the next sibling from node or NULL if the next - // sibling does not exist. - GedSibNext( - NODE * node) - // [IN] Pointer to a GEDCOM node. -{ - FLMUINT lev; - - if( node) - { - lev = GedNodeLevel( node); - while( /*skip children*/ - ((node = node->next) != NULL) && - (GedNodeLevel( node) > lev) - ); - } - - return( - (node && (GedNodeLevel( node) == lev)) - ? node - : NULL); -} - -/*API~********************************************************************* -Name : GedSibNext -Area : GEDCOM -Desc : Returns a pointer to the parent of the input node. - NULL is returned if there is not a parent. -Notes: -*END************************************************************************/ -NODE * - // Returns a pointer to the parent of the input node or NULL. - GedParent( - NODE * node) - // [IN] Pointer to a GEDCOM node. -{ - if( node) - { - FLMUINT lev = GedNodeLevel( node); - while( /*skip nephews & siblings*/ - ((node = node->prior) != NULL) && - (GedNodeLevel( node) >= lev) - ); - } - return( node); -} - -/*API~********************************************************************* -Name : GedChild -Area : GEDCOM -Desc : Returns a pointer to the child of the input node. - NULL is returned if there is not a child. -Notes: -*END************************************************************************/ -NODE * - // Returns a pointer to the child of the input node or NULL. - GedChild( - NODE * node - // [IN] POinter to a GEDCOM node. - ) -{ - return( - node && - node->next && - (GedNodeLevel( node->next) > GedNodeLevel( node)) - ? node->next - : NULL - ); -} - -/*API~********************************************************************* -Name : GedNodeCreate -Area : GEDCOM -Desc : Returns a pointer to the previous sibling of the input node. -Notes: -*END************************************************************************/ -NODE * - // Returns a pointer to the previous sibling or NULL. - GedSibPrev( - NODE * node) - // [IN] Pointer to a GEDCOM node. -{ - FLMUINT lev; - - if( node) - { - lev = GedNodeLevel( node); - while( /* skip nephews */ - ((node = node->prior) != NULL) && - (GedNodeLevel( node) > lev) - ); - } - return( - (node && (GedNodeLevel( node) == lev)) - ? node - : NULL - ); -} - - - diff --git a/flaim/src/gnative.cpp b/flaim/src/gnative.cpp deleted file mode 100644 index 78ea70b..0000000 --- a/flaim/src/gnative.cpp +++ /dev/null @@ -1,150 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Set/get native strings into/from GEDCOM nodes. -// Tabs: 3 -// -// Copyright (c) 1992-1993,1995-1997,1999-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gnative.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~********************************************************************* -Desc: Copies and formats a native 8-bit null terminated string into a - GEDCOM node. The code page - It converts the string into an internal TEXT string in the GEDCOM node. - ALL single byte, fixed length, and variable length function codes - are preserved as long as GedGetWP60 is called. Other GedGet*() - calls will lose all formatting information. -Note: The code page parameter is currently not supported. All character - values of 0x80 and higher will be stored as non-character values. - These values will be preserved if GedGetNATIVE is called, but will - be dropped if any other GEDCOM get routine is called. In addition, - all character values under 0x20 are preserved as non-character values. -*END************************************************************************/ -RCODE GedPutNATIVE( - POOL * pPool, - NODE * node, - const char * nativeString, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - RCODE rc = FERR_OK; - FLMUINT allocLength; - FLMBYTE * outPtr; - - // Check for a null node being passed in - - if( node == NULL) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - /* If the string is NULL or empty, call GedAllocSpace with a length */ - /* of zero to set the node length to zero and node type to FLM_TEXT_TYPE. */ - - if( (!nativeString) || (!(*nativeString))) - { - (void)GedAllocSpace( pPool, node, FLM_TEXT_TYPE, 0, uiEncId, uiEncSize); - goto Exit; - } - - // Determine the size of the buffer needed to store the string - - if( RC_BAD( rc = FlmNative2Storage( nativeString, &allocLength, NULL))) - { - goto Exit; - } - - if( (outPtr = (FLMBYTE *)GedAllocSpace( pPool, node, - FLM_TEXT_TYPE, allocLength, - uiEncId, uiEncSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - // Convert the string - - if( RC_BAD( rc = FlmNative2Storage( nativeString, &allocLength, outPtr))) - { - goto Exit; - } - - // Encrypted fields - only have decrypetd data at this point. - - if (node->ui32EncId) - { - node->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - - return( rc); -} - -/*API~********************************************************************* -Desc : Places 8-bit text from a GEDCOM text type node into an output buffer. - The current text representation supports WordPerfect 6.x character - values, WordPerfect formatting codes, UNICODE character values - and 8-bit character values that range from 0x80 to 0xFF. -*END************************************************************************/ -RCODE GedGetNATIVE( - NODE * node, - char * pszBuffer, - FLMUINT * bufLenRV) -{ - RCODE rc = FERR_OK; - FLMBYTE * ptr; - FLMUINT valLength; - FLMUINT nodeType; - - if( !node) - { - rc = RC_SET( FERR_CONV_NULL_SRC); - goto Exit; - } - - if (node->ui32EncId) - { - if (!(node->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - // If the node is not a TEXT or a NUMBER node, return an error for now - - nodeType = (FLMBYTE)GedValType( node); - if( (nodeType == FLM_BINARY_TYPE) || (nodeType == FLM_CONTEXT_TYPE)) - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - - ptr = (FLMBYTE *)GedValPtr( node); - valLength = GedValLen( node); - - rc = FlmStorage2Native( nodeType, valLength, (const FLMBYTE *)ptr, bufLenRV, pszBuffer); - -Exit: - - return( rc); -} diff --git a/flaim/src/gnbcd.cpp b/flaim/src/gnbcd.cpp deleted file mode 100644 index 42e6a1b..0000000 --- a/flaim/src/gnbcd.cpp +++ /dev/null @@ -1,594 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: BCD numbers in GEDCOM. -// Tabs: 3 -// -// Copyright (c) 1992-1993,1995-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gnbcd.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -// External Data - -extern FLMBYTE ucMaxBcdINT32[ ]; - -extern FLMBYTE ucMinBcdINT32[ ]; - -extern FLMBYTE ucMaxBcdUINT32[ ]; - - -/**************************************************************************** -Desc: Given an unsigned number create the matching FLAIM-specific BCD number. -Note: If terminating byte is half-full, low-nibble value is - undefined. Example: -125 creates B1-25-FX -Method: - using a MOD algorithm, stack BCD values -- popping to - destination reverses the order for correct final sequence -****************************************************************************/ -RCODE GedPutUINT( - POOL * pPool, - NODE * pNode, - FLMUINT uiNum, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPtr; - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - - if( pNode == NULL) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - /* push spare (undefined) nibble for possible half-used terminating byte */ - - pucNibStk = &ucNibStk[ 1]; - - /* push terminator nibble -- popped last */ - - *pucNibStk++ = 0x0F; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10); /* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - /* Determine number of bytes required for BCD number & allocate space */ - - if( (pucPtr = (FLMBYTE *)GedAllocSpace( pPool, pNode, FLM_NUMBER_TYPE, - ((pucNibStk - ucNibStk) >> 1), /* count: nibbleCount/2 & truncate */ - uiEncId, uiEncSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pucPtr++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - if (pNode->ui32EncId) - { - pNode->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Given an signed number create the matching FLAIM-specific BCD number. -Note: If terminating byte is half-full, low-nibble value is - undefined. Example: -125 creates B1-25-FX -Method: - using a MOD algorithm, stack BCD values -- popping to - destination reverses the order for correct final sequence -WARNING: - -2,147,483,648 may yield different results on different platforms -****************************************************************************/ -RCODE GedPutINT( - POOL * pPool, - NODE * pNode, - FLMINT iNum, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - RCODE rc = FERR_OK; - FLMUINT uiNum; - FLMBYTE * pucPtr; - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - FLMINT iNegFlag; - - if( pNode == NULL) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - /* push spare (undefined) nibble for possible half-used terminating byte */ - - pucNibStk = &ucNibStk[ 1]; - - /* push terminator nibble -- popped last */ - - *pucNibStk++ = 0x0F; - - /* separate sign from magnituted; (FLMUINT)un = +/- n & flag */ - - uiNum = ((iNegFlag = iNum < 0) != 0) - ? -iNum - : iNum; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10); /* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - if( iNegFlag) - *pucNibStk++ = 0x0B; /* push sign nibble last */ - - /* Determine number of bytes required for BCD number & allocate space */ - - if( (pucPtr = (FLMBYTE *)GedAllocSpace( pPool, pNode, FLM_NUMBER_TYPE, - ((pucNibStk - ucNibStk) >> 1), /* count: nibbleCount/2 & truncate */ - uiEncId, uiEncSize)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pucPtr++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - if (pNode->ui32EncId) - { - pNode->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - return( rc); -} - -/*API~********************************************************************* -Name : GedGetINT -Area : GEDCOM -Desc : Returns a signed value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into WSDWORD. - // FERR_CONV_NUM_UNDERFLOW - the value is too small to fit into WSDWORD. - GedGetINT( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMINT * piNum - // [OUT] Returns the 16-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_BAD(rc = flmBcd2Num( GedValType( pNode), GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), &bcd))) - { - goto Exit; - } - if( bcd.bNegFlag) - { - *piNum = -((FLMINT)bcd.uiNum); - rc = (bcd.uiNibCnt < 11) || - (bcd.uiNibCnt == 11 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMinBcdINT32, 6) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_UNDERFLOW); - // goto Exit; - } - else - { - *piNum = (FLMINT)bcd.uiNum; - rc = (bcd.uiNibCnt < 10) || - (bcd.uiNibCnt == 10 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdINT32, 5) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - // goto Exit; - } - -Exit: - return( rc); -} - -/*API~********************************************************************* -Name : GedGetINT32 -Area : GEDCOM -Desc : Returns a 32-bit signed value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into WSDWORD. - // FERR_CONV_NUM_UNDERFLOW - the value is too small to fit into WSDWORD. - GedGetINT32( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMINT32 * pi32Num - // [OUT] Returns the 16-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK(rc = flmBcd2Num( GedValType( pNode), GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), &bcd))) - { - if( bcd.bNegFlag) - { - *pi32Num = -((FLMINT32)bcd.uiNum); - rc = (bcd.uiNibCnt < 11) || - (bcd.uiNibCnt == 11 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMinBcdINT32, 6) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_UNDERFLOW); - // goto Exit; - } - else - { - *pi32Num = (FLMINT32)bcd.uiNum; - rc = (bcd.uiNibCnt < 10) || - (bcd.uiNibCnt == 10 && - (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdINT32, 5) <= 0))) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - // goto Exit; - } - } - -Exit: - return( rc); -} - -/*API~********************************************************************* -Name : GedGetINT16 -Area : GEDCOM -Desc : Returns a 16-bit signed value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into WSWORD. - // FERR_CONV_NUM_UNDERFLOW - the value is too small to fit into WSWORD. - GedGetINT16( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMINT16 * pi16Num - // [OUT] Returns the 16-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK( rc = flmBcd2Num( GedValType( pNode), GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), &bcd))) - { - if( bcd.bNegFlag ) - { - *pi16Num = -((FLMINT16)(bcd.uiNum)); - rc = (bcd.uiNibCnt < 6) || - (bcd.uiNibCnt == 6 && bcd.uiNum <= FLM_MAX_INT16 ) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_UNDERFLOW); - // goto Exit; - } - else - { - *pi16Num = (FLMINT16)bcd.uiNum; - rc = (bcd.uiNibCnt < 5) || - (bcd.uiNibCnt == 5 && bcd.uiNum < FLM_MAX_INT16 ) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - //goto Exit; - } - } - -Exit: - return( rc); -} - -/*API~********************************************************************* -Name : GedGetUINT -Area : GEDCOM -Desc : Returns an unsigned value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into FLMUINT16 - // FERR_CONV_NUM_UNDERFLOW - the value is a negative number - GedGetUINT( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMUINT * puiNum - // [OUT] Returns the 32-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK(rc = flmBcd2Num( GedValType( pNode), - GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), - &bcd))) - { - *puiNum = bcd.uiNum; - - if( bcd.bNegFlag) - { - rc = RC_SET( FERR_CONV_NUM_UNDERFLOW); - } - else if( bcd.uiNibCnt < 10) - { - rc = FERR_OK; - } - else if( bcd.uiNibCnt == 10) - { - rc = (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdUINT32, 5) <= 0)) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - else - { - rc = RC_SET( FERR_CONV_NUM_OVERFLOW); - } - } - -Exit: - - return( rc); -} - -/*API~********************************************************************* -Name : GedGetUINT8 -Area : GEDCOM -Desc : Returns an 8-bit unsigned value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into FLMUINT16 - // FERR_CONV_NUM_UNDERFLOW - the value is a negative number - GedGetUINT8( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMUINT8 * pui8Num - // [OUT] Returns the 8-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK(rc = flmBcd2Num( GedValType( pNode), - GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), - &bcd))) - { - *pui8Num = (FLMUINT8)bcd.uiNum; - rc = bcd.bNegFlag - ? RC_SET( FERR_CONV_NUM_UNDERFLOW) - : (bcd.uiNibCnt < 3) || (bcd.uiNibCnt == 3 && bcd.uiNum < FLM_MAX_UINT8) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - -Exit: - - return( rc); -} - -/*API~********************************************************************* -Name : GedGetUINT32 -Area : GEDCOM -Desc : Returns a 32-bit unsigned value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into FLMUINT16 - // FERR_CONV_NUM_UNDERFLOW - the value is a negative number - GedGetUINT32( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMUINT32 * pui32Num - // [OUT] Returns the 32-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK(rc = flmBcd2Num( GedValType( pNode), - GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), - &bcd))) - { - *pui32Num = (FLMUINT32)bcd.uiNum; - - if( bcd.bNegFlag) - { - rc = RC_SET( FERR_CONV_NUM_UNDERFLOW); - } - else if( bcd.uiNibCnt < 10) - { - rc = FERR_OK; - } - else if( bcd.uiNibCnt == 10) - { - rc = (!bcd.pucPtr || (f_memcmp( bcd.pucPtr, ucMaxBcdUINT32, 5) <= 0)) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - else - { - rc = RC_SET( FERR_CONV_NUM_OVERFLOW); - } - } - -Exit: - - return( rc); -} - -/*API~********************************************************************* -Name : GedGetUINT16 -Area : GEDCOM -Desc : Returns a 16-bit unsigned value from a GEDCOM node field. - The data in the node may be a number type, text type or context type. -Notes: -*END************************************************************************/ -RCODE // FERR_OK - // FERR_CONV_ILLEGAL - node was not a number type or had - // non-converatble values if a context or text type. - // FERR_CONV_NUM_OVERFLOW - the value is too large to fit into FLMUINT16 - // FERR_CONV_NUM_UNDERFLOW - the value is a negative number - GedGetUINT16( - NODE * pNode, - // [IN] Pointer to a GEDCOM node. - FLMUINT16 * pui16Num - // [OUT] Returns the 16-bit unsigned number value. - ) -{ - BCD_TYPE bcd; - RCODE rc = FERR_OK; - - if (pNode->ui32EncId) - { - if (!(pNode->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - if( RC_OK(rc = flmBcd2Num( GedValType( pNode), - GedValLen( pNode), - (const FLMBYTE *)GedValPtr( pNode), - &bcd)) == FERR_OK) - { - *pui16Num = (FLMUINT16)bcd.uiNum; - rc = bcd.bNegFlag - ? RC_SET( FERR_CONV_NUM_UNDERFLOW) - : (bcd.uiNibCnt < 5) || - (bcd.uiNibCnt == 5 && bcd.uiNum < FLM_MAX_UINT16 ) - ? FERR_OK - : RC_SET( FERR_CONV_NUM_OVERFLOW); - } - -Exit: - - return( rc); -} - diff --git a/flaim/src/gnum2txt.cpp b/flaim/src/gnum2txt.cpp deleted file mode 100644 index 28496eb..0000000 --- a/flaim/src/gnum2txt.cpp +++ /dev/null @@ -1,194 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Convert internal number to internal text format. -// Tabs: 3 -// -// Copyright (c) 1992-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gnum2txt.cpp 12309 2006-01-19 15:09:04 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: This routine converts an internal number to an internal (ASCII) text. - Support for FT_NUMBER and FT_REAL numeric types. -****************************************************************************/ -RCODE GedNumToText( - const FLMBYTE * num, - FLMBYTE * buffer, - FLMUINT * bufLenRV) -{ - FLMBYTE * outPtr; - FLMBYTE c; - FLMBYTE c1 = 0; - FLMUINT bytesOutput; - FLMUINT outputData; - FLMUINT maxOutLen; - FLMBYTE done; - FLMBYTE firstNibble; - FLMBYTE lastChar; - const FLMBYTE * pExp = NULL; - FLMBYTE parseExponent = 0; - FLMBYTE firstNibbleAtExp = 0; - FLMBYTE firstDigit = 0; - - maxOutLen = *bufLenRV; - outputData = ((buffer != NULL) && (maxOutLen)); - bytesOutput = 0; - outPtr = buffer; - - /* Parse through the string outputting data to the buffer */ - /* as we go. */ - - done = (num == NULL); /* Sets to TRUE if NULL else FALSE */ - firstNibble = 1; - lastChar = 0xFF; - - while( !done) - { -continue_loop: - - if( firstNibble) /* Rather not do a ? : here because */ - { /* of the num++ in the : portion */ - c = (FLMBYTE)(*num >> 4); - } - else - { - c = (FLMBYTE)(*num++ & 0x0F); - } - firstNibble = !firstNibble; - - if( c <= 9) /* Check common case before switch */ - { - if( parseExponent) /* Exponent number? */ - firstDigit++; - c1 = (FLMBYTE)( ASCII_ZERO + c); /* Normal decimal value */ - } - else switch( c) - { - case 0x0A: - c1 = ASCII_DOT; - break; - case 0x0B: - c1 = ASCII_DASH; - break; - case 0x0C: /* Ignore for now - imaginary numbers not implemented */ - c1 = 0; /* Set c1 to zero if no output */ - break; - - case 0x0D: - c1 = ASCII_SLASH; - break; - case 0x0E: - /* For real numbers the exponent appears first */ - /* This was done to make it easier for building keys */ - if( !parseExponent) - { - parseExponent++; /* 1=need to output 1st digit */ - pExp = num; /* Set state to reparse exponent */ - if( firstNibble) /* If set to one */ - pExp--; - firstNibbleAtExp = (FLMBYTE)(firstNibble ^ 1); - - /* Parse to the end of the exponent area - most 5 nibbles */ - for (;;) - { - if( firstNibble) - { - if( (*num >> 4) == 0x0F) - break; - } - else - { - if( (*num++ & 0x0F) == 0x0F) - break; - } - firstNibble = !firstNibble; - } - firstNibble = !firstNibble; /* Don't forget this! */ - goto continue_loop; /* 'continue' is vauge - use a goto */ - } - else - { - c1 = ASCII_UPPER_E; - parseExponent = 0; /* Clear flag */ - } - break; - case 0x0F: - c1 = 0; /* Set c1 to zero if no output */ - if( !parseExponent) /* Done if no exponent or done /w exp*/ - done = TRUE; - break; - /* default checked before switch */ - /* default: - ** c1 = ASCII_ZERO + c; - ** break; - */ - } - - /* If we got a character, put into output buffer (or just count) */ - - if( c1) - { - /* If the last character was an exponent and the current */ - /* character is not a minus sign, insert a plus (+) */ - - if( (lastChar == ASCII_UPPER_E) && (c1 != ASCII_MINUS)) - { - if( outputData) - { - if( bytesOutput < maxOutLen) - *outPtr++ = ASCII_PLUS; - else - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - } - bytesOutput++; - } - if( outputData) - { - if( bytesOutput < maxOutLen) - *outPtr++ = c1; - else - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - } - bytesOutput++; - /* If exponent (real) number output decimal place */ - if( firstDigit == 1) - { - firstDigit++; /* Set to != 1 */ - if( outputData) - { - if( bytesOutput < maxOutLen) - *outPtr++ = ASCII_DOT; - else - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - } - bytesOutput++; - } - lastChar = c1; - } - else if( parseExponent) /* Hit last trailing 'F' in num */ - { - num = pExp; /* Restore state */ - firstNibble = firstNibbleAtExp; - /* Go again parsing the exponent */ - } - } - *bufLenRV = bytesOutput; - return( FERR_OK); -} diff --git a/flaim/src/gtxt2num.cpp b/flaim/src/gtxt2num.cpp deleted file mode 100644 index de820e6..0000000 --- a/flaim/src/gtxt2num.cpp +++ /dev/null @@ -1,198 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Convert internal text to internal number -// Tabs: 3 -// -// Copyright (c) 1992-1994,1996-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gtxt2num.cpp 12309 2006-01-19 15:09:04 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: This routine converts an internal text string to a number. -Ret: SUCCESS or FERR_CONV_BAD_DIGIT or FERR_CONV_DEST_OVERFLOW. -Notes: If the buffer pointer is NULL, the routine just determines how - much buffer space is needed to return the text in number - format. -****************************************************************************/ -RCODE GedTextToNum( - FLMBYTE * textStr, /* Pointer to buffer containing TEXT */ - FLMUINT textLen, /* Length of text (in bytes) */ - FLMBYTE * buffer, /* Pointer to buffer where number data is to be - returned */ - FLMUINT * bufLenRV) /* Return length -- on input contains buffer size */ -{ - FLMBYTE * outPtr; - FLMBYTE c; - FLMUINT bytesProcessed; - FLMUINT bytesOutput; - FLMUINT outputData; - FLMUINT maxOutLen; - FLMUINT objType; - FLMUINT objLength; - FLMBOOL firstNibble; - FLMBOOL have1Num; - FLMBOOL insideNum; - FLMBOOL haveSign; - - maxOutLen = *bufLenRV; - outputData = ((buffer != NULL) && (maxOutLen)); - bytesProcessed = - bytesOutput = 0; - outPtr = buffer; - - /* Parse through the string outputting data to the buffer */ - /* as we go. */ - - haveSign = - have1Num = - insideNum = 0; - firstNibble = 1; - if( textStr == NULL) - textLen = 0; - - for( - ; bytesProcessed < textLen - ; textStr += objLength, bytesProcessed += objLength) - { - - /* Determine what we are pointing at */ - - c = *textStr; - objType = (FLMBYTE)GedTextObjType( c); /* Don't put this in if() below */ - - if( objType == ASCII_CHAR_CODE) - { - objLength = 1; - if( (c == ASCII_SPACE) || (c == ASCII_TAB) || (c == ASCII_NEWLINE) || (c == ASCII_CR)) - { - if( insideNum) - have1Num = 1; - break; - } - /* Code below was a break - now skips leading zeros */ - - if( (c == ASCII_ZERO) && (!insideNum)) /* Ignore leading zeroes */ - continue; - - if( (c >= ASCII_ZERO) && (c <= ASCII_NINE)) - { - if( !insideNum) - { - insideNum = 1; - haveSign = 1; - } - c -= ASCII_ZERO; - } - - /* Handle sign characters ('+', '-') */ - - else if( ((c == ASCII_PLUS) || (c == ASCII_MINUS)) && (!haveSign) && (!insideNum)) - { - haveSign = 1; - if( c == ASCII_MINUS) - c = 0x0B; - } - else - return( RC_SET( FERR_CONV_BAD_DIGIT)); - - if( outputData) - { - if( (firstNibble) && (bytesOutput == maxOutLen)) - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - - if( firstNibble) - { - c <<= 4; - *outPtr = c; - } - else - { - *outPtr = (FLMBYTE)(*outPtr + c); - outPtr++; - } - } - if( firstNibble) - bytesOutput++; - firstNibble = !firstNibble; - - } - else switch( objType) - { - case WHITE_SPACE_CODE: - objLength = 1; - break; - - /* Skip the unkown codes for now */ - - case UNK_GT_255_CODE: - objLength = (1 + sizeof( FLMUINT16) + FB2UW( textStr + 1)); - break; - case UNK_LE_255_CODE: - objLength = (2 + (FLMUINT16)*(textStr + 1)); - break; - case UNK_EQ_1_CODE: - objLength = 2; - break; - case CHAR_SET_CODE: - case EXT_CHAR_CODE: - case OEM_CODE: - case UNICODE_CODE: - // Should not hit default. - default: - return( RC_SET( FERR_CONV_BAD_DIGIT)); - } - } - - /* Interpret empty number or all zeroes as single zero */ - - if( (!insideNum) && (!have1Num)) - { - if( outputData) - { - if( (firstNibble) && (bytesOutput == maxOutLen)) - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - if( firstNibble) - { - *outPtr = 0x00; - } - else - outPtr++; - } - if( firstNibble) - bytesOutput++; - firstNibble = !firstNibble; - } - - /* Add Terminator code to the end of the number */ - - if( outputData) - { - if( (firstNibble) && (bytesOutput == maxOutLen)) - return( RC_SET( FERR_CONV_DEST_OVERFLOW)); - if( firstNibble) - *outPtr = 0xFF; - else - *outPtr = (FLMBYTE)(*outPtr + 0x0F); - } - if( firstNibble) - bytesOutput++; - *bufLenRV = bytesOutput; - return( FERR_OK); -} diff --git a/flaim/src/gunicode.cpp b/flaim/src/gunicode.cpp deleted file mode 100644 index bbc9c07..0000000 --- a/flaim/src/gunicode.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Get/Set Unicode into GEDCOM node. -// Tabs: 3 -// -// Copyright (c) 1999-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: gunicode.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/*API~********************************************************************* -Desc: Copies and formats a Unicode string into a GEDCOM node. The Unicode - string must be in little endian format. The Unicode string is - converted into an internal TEXT string in the GEDCOM node. - Unicode values that are not represented as WordPerfect 6.x characters - are preserved as non-WP characters and will be droped if any other - GEDCOM get routine is called other than GedGetUNICODE. -*END************************************************************************/ -RCODE GedPutUNICODE( - POOL * pPool, - NODE * node, - const FLMUNICODE * puzString, - FLMUINT uiEncId, - FLMUINT uiEncSize) -{ - FLMUINT allocLength = 0; - FLMBYTE * outPtr; - RCODE rc = FERR_OK; - - /* Check for a null node being passed in */ - - if( node == NULL) - { - rc = RC_SET( FERR_CONV_NULL_DEST); - goto Exit; - } - - /* - ** If the string is NULL or empty, call GedAllocSpace with a length - ** of zero to set the node length to zero and node type to FLM_TEXT_TYPE. - */ - - if( (puzString == NULL) || (*puzString == 0)) - { - GedAllocSpace( pPool, node, FLM_TEXT_TYPE, 0, uiEncId, uiEncSize); - return( FERR_OK); - } - - /* Two passes are needed on the data. - ** The first pass is to determine the storage length - ** The second pass is to store the string into FLAIMs internal text format - */ - - allocLength = FlmGetUnicodeStorageLength( puzString); - - if( (outPtr = (FLMBYTE *)GedAllocSpace( pPool, node, - FLM_TEXT_TYPE, allocLength, - uiEncId, uiEncSize)) == NULL) - { - return( RC_SET( FERR_MEM)); - } - - if (RC_BAD( rc = FlmUnicode2Storage( puzString, &allocLength, outPtr))) - { - goto Exit; - } - - if (node->ui32EncId) - { - node->ui32EncFlags = FLD_HAVE_DECRYPTED_DATA; - } - -Exit: - return( rc); -} - - -/*API~********************************************************************* -Name : GedGetUNICODE -Area : GEDCOM -Desc : Get Unicode data from a GEDCOM text type node. Also supports - conversions from number, date, time and time stamp types. - Most WordPerfect extended characters are converted to Unicode - character values. All Unicode character values are preserved if - GedPutUNICODE() is used. The Unicode representation is ALWAYS in - little endian byte order. This may change if FLAIM moves to JAVA. -Notes: -*END************************************************************************/ -RCODE // SUCCESS - // FERR_CONV_ILLEGAL - the input node is not a text, number, date, - // time or time stampe type. - // FERR_CONV_NULL_SRC - the input node (nd) is NULL. - // FERR_CONV_DEST_OVERFLOW - the number of bytes - GedGetUNICODE( - NODE * node, - // [IN] GEDCOM node that contains data. - FLMUNICODE * uniBuf, - // [IN/OUT] Unicode buffer to hold the data. If uniBuf is NULL then - // only a count return in bufLenRV is return that is the number - // of bytes needed to contain the data. Two bytes must be added - // to this value to account for the two bytes of null termination. - FLMUINT * bufLenRV - // [IN] Specified the number of bytes available in buffer including - // the terminating two null bytes. - // [OUT] Returns the number of Unicode bytes that are needed to - // represent the data. The two null termination bytes are not - // included in this value. - ) -{ - FLMUINT nodeType; - RCODE rc = FERR_OK; - - /* Check for a null node */ - - if( node == NULL) - { - rc = RC_SET( FERR_CONV_NULL_SRC); - goto Exit; - } - - if (node->ui32EncId) - { - if (!(node->ui32EncFlags & FLD_HAVE_DECRYPTED_DATA)) - { - rc = RC_SET( FERR_FLD_NOT_DECRYPTED); - goto Exit; - } - } - - /* If the node is not a TEXT or a NUMBER node, return an error for now. */ - - nodeType = GedValType( node); - - if( (nodeType == FLM_BINARY_TYPE) || (nodeType == FLM_CONTEXT_TYPE)) - { - rc = RC_SET( FERR_CONV_ILLEGAL); - goto Exit; - } - - rc = FlmStorage2Unicode( nodeType, GedValLen( node), (const FLMBYTE *)GedValPtr( node), - bufLenRV, uniBuf); - -Exit: - return( rc); -} - diff --git a/flaim/src/imonbase.cpp b/flaim/src/imonbase.cpp index 8ca110f..e445134 100644 --- a/flaim/src/imonbase.cpp +++ b/flaim/src/imonbase.cpp @@ -1,2727 +1,2752 @@ -//------------------------------------------------------------------------- -// Desc: Base class for monitoring code. -// Tabs: 3 -// -// Copyright (c) 2001-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: imonbase.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define RESP_WRITE_BUF_SIZE 1024 /* see also FLMHTTP.h */ -#define FLM_SESSION_ID_NAME "flmsessionid" - -/**************************************************************************** - Desc: Outputs a javascript function that, when called, causes a new - window to open and a page to be displayed in it. -****************************************************************************/ -void F_WebPage::popupFrame( void) -{ - fnPrintf( m_pHRequest, "\n"); - -} - -/****************************************************************************** -Desc: This method will extract the value of the parameter in the form of - PARAMETER=VALUE -*******************************************************************************/ -RCODE F_WebPage::ExtractParameter( - FLMUINT uiNumParams, - const char ** ppszParams, - const char * pszParamName, - FLMUINT uiParamLen, - char * pszParamValue) -{ - RCODE rc = FERR_OK; - FLMUINT uiLoop; - FLMUINT uiParamNameLen; - const char * pszTemp; - FLMBOOL bFound = FALSE; - - uiParamNameLen = f_strlen( pszParamName); - for( uiLoop = 0; uiLoop < uiNumParams; uiLoop++) - { - if( f_strncmp( (char *)ppszParams[ uiLoop], - pszParamName, uiParamNameLen) == 0 && - (ppszParams[ uiLoop][ uiParamNameLen] == '\0' || - ppszParams[ uiLoop][ uiParamNameLen] == '=')) - { - pszTemp = &ppszParams[ uiLoop][ uiParamNameLen]; - if( *pszTemp == '=') - { - pszTemp++; // skip past the equal sign - f_strncpy( pszParamValue, pszTemp, uiParamLen-1); - - // See if the param was too long to store - if (f_strlen( pszTemp) >= uiParamLen) - { - pszParamValue[uiParamLen]='\0'; - rc = RC_SET( FERR_MEM); - } - - } - else - { - *pszParamValue = 0; - } - - bFound = TRUE; - break; - } - } - - return( bFound ? rc : RC_SET(FERR_NOT_FOUND)); -} - -/**************************************************************************** -Desc: This method will detect the presence of a parameter in the form - PARAMETER - no value will be checked. A TRUE or FALSE value will - be returned. -*****************************************************************************/ -FLMBOOL F_WebPage::DetectParameter( - FLMUINT uiNumParams, - const char ** ppszParams, - const char * pszParamName) -{ - - for (FLMUINT uiLoop = 0; uiLoop < uiNumParams; uiLoop++) - { - if (f_strncmp((char *)ppszParams[uiLoop], pszParamName, - f_strlen((char *)pszParamName))==0) - { - return TRUE; - } - } - - return( FALSE); -} - -/**************************************************************************** -Desc: -*****************************************************************************/ -RCODE F_WebPage::getDatabaseHandleParam( - FLMUINT uiNumParams, - const char ** ppszParams, - F_Session * pFlmSession, - HFDB * phDb, - char * pszKey) -{ - RCODE rc = FERR_OK; - HFDB hDb; - char szTmp[ 64]; - char * pTmp; - - if( phDb) - { - *phDb = hDb = HFDB_NULL; - } - - if( pszKey) - { - *pszKey = 0; - } - - // Need to memset the first F_SESSION_DB_KEY_LEN bytes of - // szTmp because the hash lookup algorithm expects the buffer - // to be padded with zeros at the end of the key. - - f_memset( szTmp, 0, F_SESSION_DB_KEY_LEN); - - if( RC_BAD( ExtractParameter( uiNumParams, ppszParams, - "dbhandle", sizeof( szTmp), szTmp))) - { - pTmp = &szTmp[ 0]; - if( RC_BAD( getFormValueByName( "dbhandle", - &pTmp, sizeof( szTmp), NULL))) - { - rc = RC_SET( FERR_NOT_FOUND); - goto Exit; - } - } - - if( szTmp[ 0]) - { - if( RC_BAD( rc = pFlmSession->getDbHandle( szTmp, &hDb))) - { - goto Exit; - } - - if( pszKey) - { - f_memcpy( pszKey, szTmp, F_SESSION_DB_KEY_LEN); - } - } - - if( phDb) - { - *phDb = hDb; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Function to display the formatted time value in the form dd hh:mm:ss.ccc -*****************************************************************************/ -void F_WebPage::FormatTime( - FLMUINT uiTimerUnits, - char * pszFormattedTime) -{ - FLMUINT uiMilli; - FLMUINT uiSec; - FLMUINT uiMin; - FLMUINT uiHr; - FLMUINT uiDays; - FLMUINT uiTemp; - - // Initialize to NULL; - pszFormattedTime[0] = '\0'; - - //Convert the timer units to milliseconds - FLM_TIMER_UNITS_TO_MILLI(uiTimerUnits, uiMilli); - - //Determine the number of days - uiDays = uiMilli / 86400000; - uiTemp = uiMilli % 86400000; // Get the remainder - - //Now the hours - uiHr = uiTemp / 3600000; - uiTemp = uiTemp % 3600000; - - //Determine the minutes - uiMin = uiTemp / 60000; - uiTemp = uiTemp % 60000; - - //Determine seconds - uiSec = uiTemp / 1000; - - // Determine the milliseconds - uiMilli = uiTemp % 1000; - - //Put it all together - hh:mm:ss - f_sprintf((char *)pszFormattedTime, - "%ld %2.2ld:%2.2ld:%2.2ld.%3.3ld",uiDays, uiHr, uiMin, uiSec, uiMilli); -} - -/**************************************************************************** - Desc: Procedure to generate the HTML page that displays the usage statistics - structure. - ****************************************************************************/ -RCODE F_WebPage::writeUsage( - FLM_CACHE_USAGE * pUsage, - FLMBOOL bRefresh, - const char * pszURL, - const char * pszTitle) -{ - RCODE rc = FERR_OK; - FLMBOOL bHighlight = FALSE; - char szTemp[ 100]; - - stdHdr(); - fnPrintf( m_pHRequest, HTML_DOCTYPE); - fnPrintf( m_pHRequest, "\n"); - - // Setup the page header & refresh control... - // Assuming the the first parameter ?Usage is already contained in the pszURL string. - if (bRefresh) - { - fnPrintf( m_pHRequest, - "" - "" - "%s\n", - m_pszURLString, pszURL, pszTitle); - printStyle(); - fnPrintf( m_pHRequest, "\n\n"); - - - f_sprintf( (char *)szTemp, - "Stop Auto-refresh", m_pszURLString, pszURL); - - } - else - { - fnPrintf( m_pHRequest, "%s\n", pszTitle); - printStyle(); - fnPrintf( m_pHRequest, "\n\n"); - - f_sprintf( (char *)szTemp, - "Start Auto-refresh (5 sec.)", - m_pszURLString, pszURL); - - } - - - // Begin the table - printTableStart( (char *)pszTitle, 4); - - printTableRowStart(); - printColumnHeading( "", JUSTIFY_LEFT, - FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); - fnPrintf( m_pHRequest, "Refresh, ", m_pszURLString, pszURL); - fnPrintf( m_pHRequest, "%s\n", szTemp); - printColumnHeadingClose(); - printTableRowEnd(); - - // Write out the table headings. - printTableRowStart(); - printColumnHeading( "Byte Offset (hex)"); - printColumnHeading( "Field Name"); - printColumnHeading( "Byte Offset"); - printColumnHeading( "Value"); - printTableRowEnd(); - - - // uiMaxBytes - printHTMLUint( - (char *)"uiMaxBytes", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiMaxBytes, - pUsage->uiMaxBytes, - (bHighlight = ~bHighlight)); - - - // uiTotalBytesAllocated - printHTMLUint( - (char *)"uiTotalBytesAllocated", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiTotalBytesAllocated, - pUsage->uiTotalBytesAllocated, - (bHighlight = ~bHighlight)); - - - // uiCount - printHTMLUint( - (char *)"uiCount", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiCount, - pUsage->uiCount, - (bHighlight = ~bHighlight)); - - - // uiOldVerCount - printHTMLUint( - (char *)"uiOldVerCount", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiOldVerCount, - pUsage->uiOldVerCount, - (bHighlight = ~bHighlight)); - - - // uiOldVerBytes - printHTMLUint( - (char *)"uiOldVerBytes", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiOldVerBytes, - pUsage->uiOldVerBytes, - (bHighlight = ~bHighlight)); - - // uiCacheHits - printHTMLUint( - (char *)"uiCacheHits", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiCacheHits, - pUsage->uiCacheHits, - (bHighlight = ~bHighlight)); - - - // uiCacheHitLooks - printHTMLUint( - (char *)"uiCacheHitLooks", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiCacheHitLooks, - pUsage->uiCacheHitLooks, - (bHighlight = ~bHighlight)); - - - // uiCacheFaults - printHTMLUint( - (char *)"uiCacheFaults", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiCacheFaults, - pUsage->uiCacheFaults, - (bHighlight = ~bHighlight)); - - - // uiCacheFaultLooks - printHTMLUint( - (char *)"uiCacheFaultLooks", - (char *)"FLMUINT", - (void *)pUsage, - (void *)&pUsage->uiCacheFaultLooks, - pUsage->uiCacheFaultLooks, - (bHighlight = ~bHighlight)); - - - printTableEnd(); - - fnPrintf( m_pHRequest, "
\n"); - fnPrintf( m_pHRequest, "
\n"); - fnPrintf( m_pHRequest, "
\n"); - - - fnPrintf( m_pHRequest, "\n"); - - fnEmit(); - - return( rc); -} - -/********************************************************************* -Desc: This function prints a linkable field in HTML -*********************************************************************/ -void F_WebPage::printHTMLLink( - const char * pszName, - const char * pszType, - void * pvBase, - void * pvAddress, - void * pvValue, - const char * pszLink, - FLMBOOL bHighlight) -{ - char szAddress[ 20]; - char szOffset[ 8]; - - printOffset( pvBase, pvAddress, szOffset); - printTableRowStart( bHighlight); - fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset - if (pvValue) - { - printAddress( pvValue, szAddress); - fnPrintf( m_pHRequest, TD_a_s_s, pszLink, pszName); // Link & Name - fnPrintf( m_pHRequest, TD_s, pszType); // Type - fnPrintf( m_pHRequest, TD_a_s_s, pszLink, szAddress); // Link & Value - } - else - { - fnPrintf( m_pHRequest, TD_s, pszName); - fnPrintf( m_pHRequest, TD_s, pszType); - fnPrintf( m_pHRequest, TD_s, "Null"); - } - printTableRowEnd(); -} - -/********************************************************************* -Desc: This function prints a text field in HTML -*********************************************************************/ -void F_WebPage::printHTMLString( - const char * pszName, - const char * pszType, - void * pvBase, - void * pvAddress, - const char * pszValue, - FLMBOOL bHighlight) -{ - char szOffset[ 8]; - - printOffset( pvBase, pvAddress, szOffset); - printTableRowStart( bHighlight); - fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset - fnPrintf( m_pHRequest, TD_s, pszName); // Name - fnPrintf( m_pHRequest, TD_s, pszType); // Type - fnPrintf( m_pHRequest, TD_s, pszValue); // Value - printTableRowEnd(); -} - -/********************************************************************* -Desc: This function prints a unsigned long (FLMUINT) field in HTML -*********************************************************************/ -void F_WebPage::printHTMLUint( - const char * pszName, - const char * pszType, - void * pvBase, - void * pvAddress, - FLMUINT uiValue, - FLMBOOL bHighlight) -{ - char szOffset[ 8]; - - printOffset( pvBase, pvAddress, szOffset); - printTableRowStart( bHighlight); - fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset - fnPrintf( m_pHRequest, TD_s, pszName); // Name - fnPrintf( m_pHRequest, TD_s, pszType); // Type - fnPrintf( m_pHRequest, TD_ui, uiValue); // Value - printTableRowEnd(); -} - -/********************************************************************* -Desc: This function prints a signed long (FLMINT) field in HTML -*********************************************************************/ -void F_WebPage::printHTMLInt( - const char * pszName, - const char * pszType, - void * pvBase, - void * pvAddress, - FLMINT iValue, - FLMBOOL bHighlight) -{ - char szOffset[ 8]; - - printOffset( pvBase, pvAddress, szOffset); - printTableRowStart( bHighlight); - fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset - fnPrintf( m_pHRequest, TD_s, pszName); // Name - fnPrintf( m_pHRequest, TD_s, pszType); // Type - fnPrintf( m_pHRequest, TD_i, iValue); // Value - printTableRowEnd(); -} - -/********************************************************************* -Desc: This function prints a unsigned long field in HTML -*********************************************************************/ -void F_WebPage::printHTMLUlong( - const char * pszName, - const char * pszType, - void * pvBase, - void * pvAddress, - unsigned long luValue, - FLMBOOL bHighlight) -{ - char szOffset[ 8]; - - printOffset( pvBase, pvAddress, szOffset); - printTableRowStart( bHighlight); - fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset - fnPrintf( m_pHRequest, TD_s, pszName); // Name - fnPrintf( m_pHRequest, TD_s, pszType); // Type - fnPrintf( m_pHRequest, TD_lu, luValue); // Value - printTableRowEnd(); -} - -/********************************************************************* -Desc: This function takes the name of a form field, and returns a - pointer to it. This will allocate the buffer returned. The - calling function is responsible for freeing that buffer. -*********************************************************************/ -RCODE F_WebPage::getFormValueByName( - const char * pszValueTag, - char ** ppszBuf, - FLMUINT uiBufLen, - FLMUINT * puiDataLen) -{ - RCODE rc = FERR_OK; - char szTag[ 128]; - char * pszValue; - FLMUINT uiLen; - FLMBOOL bFreeFormData = FALSE; - FLMBOOL bFreeUserData = FALSE; - - if( puiDataLen) - { - *puiDataLen = 0; - } - -#ifdef FLM_DEBUG - if( !uiBufLen) - { - flmAssert( ppszBuf && *ppszBuf == NULL); - } -#endif - - if( f_strlen( pszValueTag) + 1 >= sizeof( szTag)) - { - flmAssert( 0); - rc = RC_SET( FERR_MEM); - goto Exit; - } - - f_sprintf( (char *)szTag, "%s=", pszValueTag); - - if( !m_pszFormData) - { - char * pszContentLength; - FLMUINT uiContentLength; - - // First we need to determine how much form data there is. - - if( (pszContentLength = (char *)fnReqHdrValue( "Content-Length")) == NULL) - { - rc = RC_SET( FERR_NOT_FOUND); - goto Exit; - } - - if( (uiContentLength = f_atoi( pszContentLength)) == 0) - { - rc = RC_SET( FERR_NOT_FOUND); - goto Exit; - - } - - // Now allocate a buffer to hold the form data - - if( RC_BAD( rc = f_alloc( uiContentLength + 1, &m_pszFormData))) - { - goto Exit; - } - bFreeFormData = TRUE; - - if( fnRecvBuffer( m_pszFormData, (size_t *)&uiContentLength) != 0) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - - m_pszFormData[ uiContentLength] = 0; - bFreeFormData = FALSE; - } - - // Now, parse through the buffer until we find the field we are looking for. - // The data is in the form name=value:name=value... - - if( (pszValue = f_strstr( m_pszFormData, szTag)) != NULL) - { - pszValue += f_strlen( szTag); - for( uiLen = 0; pszValue[ uiLen] && - pszValue[ uiLen] != ':' && pszValue[ uiLen] != '&'; uiLen++); - - if( ppszBuf) - { - if( !uiBufLen) - { - uiBufLen = uiLen + 1; - bFreeUserData = TRUE; - *ppszBuf = NULL; - if( RC_BAD( rc = f_alloc( uiBufLen, ppszBuf))) - { - goto Exit; - } - } - - if( uiLen >= uiBufLen) - { - rc = RC_SET( FERR_CONV_DEST_OVERFLOW); - goto Exit; - } - - f_memcpy( *ppszBuf, pszValue, uiLen); - (*ppszBuf)[ uiLen] = 0; - bFreeUserData = FALSE; - } - - if( puiDataLen) - { - *puiDataLen = uiLen + 1; - } - goto Exit; - } - else - { - rc = RC_SET( FERR_NOT_FOUND); - goto Exit; - } - -Exit: - - if( bFreeFormData) - { - f_free( &m_pszFormData); - } - - if( bFreeUserData && *ppszBuf) - { - f_free( ppszBuf); - } - - return( rc); -} - -/**************************************************************************** -Desc: Prints the standard style sheet -****************************************************************************/ -void F_WebPage::printStyle( void) -{ - fnPrintf( m_pHRequest, - "\n", - m_pszURLString); -} - -/**************************************************************************** -Desc: Outputs a column heading using elements from the standard style sheet -****************************************************************************/ -void F_WebPage::printColumnHeading( - const char * pszHeading, - JustificationType eJustification, - const char * pszBackground, - FLMUINT uiColSpan, - FLMUINT uiRowSpan, - FLMBOOL bClose, - FLMUINT uiWidth) -{ - fnPrintf( m_pHRequest, "\n"); - if( pszHeading) - { - printEncodedString( pszHeading); - } - - if( bClose) - { - fnPrintf( m_pHRequest, "\n"); - } -} - -/**************************************************************************** -Desc: Closes a column heading -****************************************************************************/ -void F_WebPage::printColumnHeadingClose( void) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: Encodes a string for rendering in an HTML page or for inclusion in - an URL -****************************************************************************/ -void F_WebPage::printEncodedString( - const char * pszString, - FStringEncodeType eEncodeType, - FLMBOOL bMapSlashes) -{ - char ucChar; - - while( (ucChar = *pszString) != 0) - { - if( (ucChar >= '0' && ucChar <= '9') || - (ucChar >= 'A' && ucChar <= 'Z') || - (ucChar >= 'a' && ucChar <= 'z') || - ucChar == '_' || - (eEncodeType == URL_PATH_ENCODING && - (ucChar == '.' || (bMapSlashes && - (ucChar == '/' || ucChar == '\\'))))) - { - if( ucChar == '\\') - { - ucChar = '/'; - } - fnPrintf( m_pHRequest, "%c", ucChar); - } - else if( eEncodeType == URL_PATH_ENCODING) - { - fnPrintf( m_pHRequest, "%%%02X", (unsigned)ucChar); - } - else if( eEncodeType == URL_QUERY_ENCODING) - { - if( ucChar == ' ') - { - ucChar = '+'; - } - fnPrintf( m_pHRequest, "%%%02X", (unsigned)ucChar); - } - else // HTML encoding - { - fnPrintf( m_pHRequest, "&#%u;", (unsigned)ucChar); - } - pszString++; - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printDocStart( - const char * pszTitle, - FLMBOOL bPrintTitle, - FLMBOOL bStdHeader, - const char * pszBackground) -{ - if( bStdHeader) - { - stdHdr(); - } - - fnPrintf( m_pHRequest, HTML_DOCTYPE); - fnPrintf( m_pHRequest, "\n"); - fnPrintf( m_pHRequest, "\n"); - printRecordStyle(); - printStyle(); - fnPrintf( m_pHRequest, "Database iMonitor - "); - printEncodedString( pszTitle); - fnPrintf( m_pHRequest, "\n"); - fnPrintf( m_pHRequest, "\n"); - fnPrintf( m_pHRequest, "\n", - pszBackground ? pszBackground : "white"); - - if( bPrintTitle) - { - printTableStart( pszTitle, 1); - printTableEnd(); - fnPrintf( m_pHRequest, "
\n"); - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printDocEnd( void) -{ - fnPrintf( m_pHRequest, "\n"); - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printMenuReload( void) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableStart( - const char * pszTitle, - FLMUINT uiColumns, - FLMUINT uiWidthFactor) -{ - fnPrintf( m_pHRequest, "\n"); - - if( pszTitle) - { - printTableRowStart(); - fnPrintf( m_pHRequest, ""); - printTableRowEnd(); - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableEnd( void) -{ - fnPrintf( m_pHRequest, "
\n"); - printEncodedString( pszTitle); - fnPrintf( m_pHRequest, "
\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableRowStart( - FLMBOOL bHighlight) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableRowEnd( void) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableDataStart( - FLMBOOL bNoWrap, - JustificationType eJustification, - FLMUINT uiWidth) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableDataEnd( void) -{ - fnPrintf( m_pHRequest, "\n"); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printTableDataEmpty( void) -{ - fnPrintf( m_pHRequest, " "); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printErrorPage( - RCODE rc, - FLMBOOL bStdHeader, - const char * pszWhat) -{ - printDocStart( "Error", TRUE, bStdHeader); - - fnPrintf( m_pHRequest, "

\n"); - fnPrintf( m_pHRequest, "%s
%s (0x%04X).\n", - pszWhat, FlmErrorString( rc), (unsigned)rc); - fnPrintf( m_pHRequest, "

\n"); - - printDocEnd(); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printErrorPage( - const char * pszErrStr, - const char * pszErrStr2, - FLMBOOL bStdHeader) -{ - printDocStart( "Error", TRUE, bStdHeader); - - fnPrintf( m_pHRequest, "

\n"); - fnPrintf( m_pHRequest, "%s\n", pszErrStr); - if (pszErrStr2 && *pszErrStr2) - { - fnPrintf( m_pHRequest, "
%s\n", pszErrStr2); - } - fnPrintf( m_pHRequest, "

\n"); - - printDocEnd(); -} - -/**************************************************************************** -Desc: Start an input form -****************************************************************************/ -void F_WebPage::printStartInputForm( - const char * pszFormName, - const char * pszPage, - FLMUINT uiFormValue) -{ - fnPrintf( m_pHRequest, - "
\n" - "\n", - pszFormName, - m_pszURLString, - pszPage, - (unsigned)uiFormValue); -} - -/**************************************************************************** -Desc: End an input form -****************************************************************************/ -void F_WebPage::printEndInputForm( void) -{ - fnPrintf( m_pHRequest, "
"); -} - -/**************************************************************************** -Desc: Generic function to output HTML that gererates a button -****************************************************************************/ -void F_WebPage::printButton( - const char * pszContents, - ButtonTypes eBType, - const char * pszName, - const char * pszValue, - const char * pszExtra, - FLMBOOL bDisabled, - FLMBYTE ucAccessKey, - FLMUINT uiTabIndex) -{ - fnPrintf( m_pHRequest, "\n", (char *)(pszContents ? pszContents : "")); -} - - -/**************************************************************************** -Desc: Format and output date. -****************************************************************************/ -void F_WebPage::printDate( - FLMUINT uiGMTTime, - char * pszBuffer) -{ - F_TMSTAMP timeStamp; - FLMUINT uiLocalTime; - char * pszAmPm; - const char * pszMonth; - - uiLocalTime = (FLMUINT)(uiGMTTime - f_timeGetLocalOffset()); - f_timeSecondsToDate( uiLocalTime, &timeStamp); - - pszAmPm = (char *)((timeStamp.hour >= 12) ? (char *)"pm" : (char *)"am"); - if (timeStamp.hour > 12) - { - timeStamp.hour -= 12; - } - if (timeStamp.hour == 0) - { - timeStamp.hour = 12; - } - - switch (timeStamp.month) - { - case 0: - pszMonth = "Jan"; - break; - case 1: - pszMonth = "Feb"; - break; - case 2: - pszMonth = "Mar"; - break; - case 3: - pszMonth = "Apr"; - break; - case 4: - pszMonth = "May"; - break; - case 5: - pszMonth = "Jun"; - break; - case 6: - pszMonth = "Jul"; - break; - case 7: - pszMonth = "Aug"; - break; - case 8: - pszMonth = "Sep"; - break; - case 9: - pszMonth = "Oct"; - break; - case 10: - pszMonth = "Nov"; - break; - default: - case 11: - pszMonth = "Dec"; - break; - } - - if (pszBuffer != NULL) - { - f_sprintf( (char *)pszBuffer, - "%s %u, %u %u:%02u:%02u %s", - pszMonth, (unsigned)timeStamp.day, (unsigned)timeStamp.year, - (unsigned)timeStamp.hour, (unsigned)timeStamp.minute, - (unsigned)timeStamp.second, pszAmPm); - } - else - { - fnPrintf( m_pHRequest, - "%s %u, %u %u:%02u:%02u %s", - pszMonth, (unsigned)timeStamp.day, (unsigned)timeStamp.year, - (unsigned)timeStamp.hour, (unsigned)timeStamp.minute, - (unsigned)timeStamp.second, pszAmPm); - } -} - -/**************************************************************************** -Desc: Outputs a Yes or No value based on the passed-in boolean -****************************************************************************/ -void F_WebPage::printYesNo( - FLMBOOL bYes) -{ - fnPrintf( m_pHRequest, "%s", bYes ? "Yes" : "No"); -} - -/**************************************************************************** -Desc: Outputs a number with commas, for easier reading. -****************************************************************************/ -void F_WebPage::printCommaNumText( - FLMUINT64 ui64Num) -{ - FLMUINT uiTerm; - FLMUINT64 ui64Divisor = 1; - FLMBOOL bFirstPass = TRUE; - - while( (FLMUINT64)(ui64Num / (ui64Divisor * (FLMUINT64)1000))) - { - ui64Divisor *= 1000; - } - - while( ui64Divisor) - { - uiTerm = (FLMUINT)(ui64Num / ui64Divisor); - ui64Num -= ((FLMUINT64)uiTerm) * ui64Divisor; - if( bFirstPass) - { - fnPrintf( m_pHRequest, "%u", (unsigned)uiTerm); - bFirstPass = FALSE; - } - else - { - fnPrintf( m_pHRequest, "%03u", (unsigned)uiTerm); - } - if( (ui64Divisor /= (FLMUINT64)1000) > (FLMUINT64)0) - { - fnPrintf( m_pHRequest, ","); - } - } -} - -/**************************************************************************** -Desc: Outputs a number with commas, for easier reading. -****************************************************************************/ -void F_WebPage::printCommaNum( - FLMUINT64 ui64Num, - JustificationType eJustify, - FLMBOOL bChangedValue) -{ - printTableDataStart( TRUE, eJustify); - if (bChangedValue) - { - fnPrintf( m_pHRequest, ""); - } - - printCommaNumText( ui64Num); - - if (bChangedValue) - { - fnPrintf( m_pHRequest, ""); - } - printTableDataEnd(); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -RCODE F_WebPage::acquireSession() -{ - RCODE rc = FERR_OK; - FLMBOOL bHttpSessionMutexLocked = FALSE; - FLMUINT uiSize; - void * pvHttpSession = NULL; - char szSessionKey[ F_SESSION_KEY_LEN]; - - m_pFlmSession = NULL; - - if( !gv_FlmSysData.HttpConfigParms.fnAcquireSession) - { - rc = RC_SET( FERR_NOT_IMPLEMENTED); - goto Exit; - } - - if( (pvHttpSession = fnAcquireSession()) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - f_mutexLock( gv_FlmSysData.hHttpSessionMutex); - bHttpSessionMutexLocked = TRUE; - - uiSize = sizeof( szSessionKey); - if( fnGetSessionValue( pvHttpSession, - FLM_SESSION_ID_NAME, (void *)szSessionKey, (size_t *)&uiSize) != 0) - { -CreateSession: - - if( RC_BAD( rc = gv_FlmSysData.pSessionMgr->createSession( - &m_pFlmSession))) - { - goto Exit; - } - - fnSetSessionValue( pvHttpSession, - FLM_SESSION_ID_NAME, m_pFlmSession->getKey(), sizeof( szSessionKey)); - } - else - { - if( RC_BAD( rc = gv_FlmSysData.pSessionMgr->getSession( - szSessionKey, &m_pFlmSession))) - { - if( rc == FERR_NOT_FOUND) - { - goto CreateSession; - } - } - } - - -Exit: - - if (RC_BAD( rc)) - { - if( m_pFlmSession) - { - releaseSession(); - } - } - - if( pvHttpSession) - { - fnReleaseSession( pvHttpSession); - } - - if( bHttpSessionMutexLocked) - { - f_mutexUnlock( gv_FlmSysData.hHttpSessionMutex); - } - - return( rc); -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::releaseSession() -{ - if ( m_pFlmSession) - { - gv_FlmSysData.pSessionMgr->releaseSession( &m_pFlmSession); - m_pFlmSession = NULL; - } -} - -/**************************************************************************** -Desc: -****************************************************************************/ -void F_WebPage::printSpaces( - FLMUINT uiCount) -{ - while( uiCount--) - { - fnPrintf( m_pHRequest, " "); - } -} - -/**************************************************************************** -Desc: Outputs elapsed milliseconds as seconds.milli. The optional parameter - pszBuffer will cause the time to be written to pszBuffer instead of the - web page. That way it can be incorporated into more complex structures - if desired. -****************************************************************************/ -void F_WebPage::printElapTime( - FLMUINT64 ui64ElapTime, - char * pszBuffer, - JustificationType eJustify, - FLMBOOL bTimeIsMilli) -{ - FLMUINT uiHours; - FLMUINT uiMinutes; - FLMUINT uiSeconds; - FLMUINT uiMilli = 0; - - if (bTimeIsMilli) - { - uiHours = (FLMUINT)(ui64ElapTime / (FLMUINT64)(1000 * 3600)); - uiMinutes = (FLMUINT)((ui64ElapTime / - (FLMUINT64)(1000 * 60)) % (FLMUINT64)60); - uiSeconds = (FLMUINT)((ui64ElapTime / (FLMUINT64)1000) % (FLMUINT64)60); - uiMilli = (FLMUINT)(ui64ElapTime % (FLMUINT64)1000); - } - else - { - uiHours = (FLMUINT)(ui64ElapTime / (FLMUINT64)3600); - uiMinutes = (FLMUINT)((ui64ElapTime / (FLMUINT64)60) % (FLMUINT64)60); - uiSeconds = (FLMUINT)(ui64ElapTime % (FLMUINT64)60); - } - - if (!pszBuffer) - { - printTableDataStart( TRUE, eJustify); - } - - if (pszBuffer) - { - f_sprintf( (char *)pszBuffer, "%02u:%02u:%02u", - (unsigned)uiHours, (unsigned)uiMinutes, (unsigned)uiSeconds); - } - else - { - fnPrintf( m_pHRequest, "%02u:%02u:%02u", - (unsigned)uiHours, (unsigned)uiMinutes, (unsigned)uiSeconds); - } - - if (bTimeIsMilli) - { - if (pszBuffer) - { - char szTemp[5]; - - f_sprintf( szTemp, ".%03u", (unsigned)uiMilli); - f_strncat( (char *)pszBuffer, szTemp, 4); - } - else - { - fnPrintf( m_pHRequest, ".%03u", (unsigned)uiMilli); - } - } - - if (!pszBuffer) - { - printTableDataEnd(); - } -} - -/**************************************************************************** -Desc: This function will output a form in an already existing page that will - present a formatted display of the record passed in. An optional parameter - bReadOnly will determine if the form should allow editing of the record - or not. The default value is TRUE (No editing capability). A null may - be passed in for the FlmRecord pointer, in which case an empty display - will be created. Normally, a bReadOnly value of false would accompany - a null record so that a record can be created. The printRecordStyle() - must be called in the header section of the page prior to calling this - function. Multiple calls may be made to display multiple records per page. - The puiContext parameter must be initialized to zero before the first - (and possibly the only) call, otherwise the scripts need to run this page - will not be loaded. -****************************************************************************/ -#define MAX_FIELD_SIZE( uiSize) (uiSize > 100 ? 100 : (uiSize < 20 ? 20 : uiSize)) -void F_WebPage::printRecord( - const char * pszDbKey, - FlmRecord * pRec, - F_NameTable * pNameTable, - FLMUINT * puiContext, - FLMBOOL bReadOnly, - FLMUINT uiSelectedField, - FLMUINT uiFlags) -{ -#define SP " " - FLMBOOL bEmpty = FALSE; - FLMUINT uiContainer; - FLMUINT uiDrn; - void * pvField; - FLMUINT uiFieldCounter; - FLMUINT uiFldCnt; - FLMUINT uiTagNum; - FLMUINT uiLevel; - FLMUINT uiType; - FLMUINT uiContext = 0; - char szNameBuf[ 128]; - - flmAssert( pNameTable); - - if (puiContext) - { - uiContext = *puiContext; - (*puiContext)++; - } - - // See if we need to write out the scripts - if (uiContext == 0) - { - printRecordScripts(); - } - - if (!pRec) - { - bEmpty = TRUE; - uiDrn = 0; - uiContainer = 0; - } - else - { - // Get the Drn & Container - uiDrn = pRec->getID(); - uiContainer = pRec->getContainerID(); - } - - // Count the fields - uiFldCnt = 0; - if (pRec != NULL) - { - pvField = pRec->root(); - while (pvField) - { - pvField = pRec->next( pvField); - uiFldCnt++; - } - } - - - // Begin the form that displays the record data (if any) - fnPrintf( m_pHRequest, "
\n", - uiContext, gv_FlmSysData.HttpConfigParms.pszURLString); - printHiddenField( "ReadOnly", (char *)(bReadOnly ? "TRUE" : "FALSE")); - - if (pszDbKey) - { - printHiddenField( "dbhandle", (char *)(pszDbKey)); - } - - printHiddenField( (char *)"Action", "none"); - printHiddenField( (char *)"FieldLevel", (FLMUINT)0); - printHiddenField( (char *)"FieldNumber", (FLMUINT)0); - printHiddenField( (char *)"FieldCount", uiFldCnt); - - // Print out the block that displays the DRN and Container list - fnPrintf( m_pHRequest, "
\n"); - fnPrintf( m_pHRequest, - "\n"); - fnPrintf( m_pHRequest, - "\n\n\n", - uiDrn, pszDbKey == NULL ? "disabled" : ""); - - if (pszDbKey != NULL) - { - fnPrintf( m_pHRequest, "\n\n\n"); - } - - fnPrintf( m_pHRequest, "\n\n\n", uiContainer); - } - fnPrintf( m_pHRequest, "\n\n"); - - - if (pszDbKey != NULL) - { - // Print out the field list drop down box. - fnPrintf( m_pHRequest, "\n\n\n"); - - // Print out the Add, Modify, Delete action buttons. - fnPrintf( m_pHRequest, - "\n"); - } - fnPrintf( m_pHRequest, "
DRN  
Flags \n"); - printRetrievalFlagsPulldown( uiFlags); - fnPrintf( m_pHRequest, "
Container \n"); - if (pszDbKey != NULL) - { - printContainerPulldown( pNameTable, uiContainer); - } - else - { - fnPrintf( m_pHRequest, - " 
Field list "); - printFieldPulldown( pNameTable, uiSelectedField); - fnPrintf( m_pHRequest, "
", uiContext); - if (pRec != NULL) - { - if (!bReadOnly) - { - fnPrintf( m_pHRequest, - "", uiContext); - fnPrintf( m_pHRequest, - "", uiContext); - } - fnPrintf( m_pHRequest, - "", uiContext); - } - fnPrintf( m_pHRequest, - "", uiContext); - if (pRec != NULL && bReadOnly) - { - fnPrintf( m_pHRequest, - "", uiContext); - } - fnPrintf( m_pHRequest, "
\n
\n"); - - // Print out the record fields (if there are any) - if (pRec != NULL) - { - fnPrintf( m_pHRequest, "
\n"); - if (!bReadOnly) - { - fnPrintf( m_pHRequest, - "", uiContext); - if (uiFldCnt > 1) - { - fnPrintf( m_pHRequest, - "", uiContext); - fnPrintf( m_pHRequest, - "", uiContext); - fnPrintf( m_pHRequest, "\n", uiContext); - } - } - - fnPrintf( m_pHRequest, "
\n");
-
-		// Now for the actual data.  Start with the root field.  
-		pvField = pRec->root();
-
-		uiFieldCounter = 0;
-
-		while (pvField)
-		{
-			uiTagNum			= pRec->getFieldID( pvField);
-			uiLevel			= pRec->getLevel( pvField);
-			uiType			= pRec->getDataType( pvField);
-
-			if (uiLevel != 0 && !bReadOnly)
-			{
-				fnPrintf( m_pHRequest,
-					"",
-					uiFieldCounter, uiContext, uiFieldCounter, uiLevel);
-			}
-			pNameTable->getFromTagNum(
-				uiTagNum, NULL, szNameBuf, sizeof( szNameBuf));
-			printSpaces( uiLevel + 5);
-
-			fnPrintf( m_pHRequest,
-				"%s%d%s%s%s",
-				SP, uiLevel, SP, szNameBuf, SP);
-
-			if (pRec->getDataLength( pvField))
-			{
-
-				switch (uiType)
-				{
-					case FLM_TEXT_TYPE:
-						printTextField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-					case FLM_NUMBER_TYPE:
-						printNumberField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-					case FLM_BINARY_TYPE:
-						printBinaryField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-					case FLM_CONTEXT_TYPE:
-						printContextField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-					case FLM_BLOB_TYPE:
-						printBlobField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-					default:
-						printDefaultField(
-							pRec, pvField, uiFieldCounter, bReadOnly);
-						break;
-				}
-
-			}
-			else if (!bReadOnly)
-			{
-				fnPrintf( m_pHRequest, "",
-					uiFieldCounter, MAX_FIELD_SIZE( 0));
-			}
-
-			// Print the hidden field Ids
-			printFieldIds( uiFieldCounter, uiLevel, uiType, uiTagNum);
-			fnPrintf( m_pHRequest, "\n");
-
-			pvField = pRec->next( pvField);
-			uiFieldCounter++;
-		}
-		fnPrintf( m_pHRequest, "
\n
\n
\n"); - } - fnPrintf( m_pHRequest, "
\n"); - - return; -} - - -/**************************************************************************** -Desc: Prints out a style sheet specific to displaying records. -****************************************************************************/ -void F_WebPage::printRecordStyle( void) -{ - fnPrintf( m_pHRequest, - "\n"); -} - -/**************************************************************************** -Desc: Prints out the required scripts for displaying and updating records. -****************************************************************************/ -void F_WebPage::printRecordScripts( void) -{ - fnPrintf( m_pHRequest, "\n"); -} - - -/**************************************************************************** -Desc: Prints out a hidden field with a character string value -****************************************************************************/ -void F_WebPage::printHiddenField( - const char * pszName, - const char * pszValue) -{ - fnPrintf( m_pHRequest, - "", pszName, pszValue); -} - -/**************************************************************************** -Desc: Prints out a hidden with an unsigned long value -****************************************************************************/ -void F_WebPage::printHiddenField( - const char * pszName, - FLMUINT uiValue) -{ - fnPrintf( m_pHRequest, - "", - pszName, (unsigned)uiValue); -} - - -/**************************************************************************** -Desc: Prints out the value for the field, assuming the field is a text field. -****************************************************************************/ -void F_WebPage::printTextField( - FlmRecord * pRec, - void * pvField, - FLMUINT uiFieldCounter, - FLMBOOL bReadOnly) -{ - RCODE rc = FERR_OK; - FLMUNICODE * puzBuf = NULL; - FLMUNICODE * puzTmp = NULL; - F_DynamicBuffer * pBuffer = NULL; - FLMUINT uiLen; - - if (RC_BAD( rc = pRec->getUnicodeLength( pvField, &uiLen))) - { - fnPrintf( m_pHRequest, "** Error retrieving Unicode field length (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - // The length returned does not allow for 2 NULL terminators. - // We must allow for them when allocating a buffer. - uiLen += 2; - if (RC_BAD( rc = f_alloc( uiLen, &puzBuf))) - { - fnPrintf( m_pHRequest, "** Error allocating memory buffer (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - if (RC_BAD(rc = pRec->getUnicode( pvField, puzBuf, &uiLen))) - { - fnPrintf( m_pHRequest, "** Error retrieving Unicode field (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - puzTmp = puzBuf; - if ((pBuffer = f_new F_DynamicBuffer) == NULL) - { - fnPrintf( m_pHRequest, "** Error allocating memory **"); - goto Exit; - } - - // Start the text field if not read only mode. - if (!bReadOnly) - { - fnPrintf( m_pHRequest, ""); - } - - while (*puzTmp) - { - // Check for ASCII characters - if ((*puzTmp >= 32) && (*puzTmp <= 126)) - { - if (RC_BAD( rc = pBuffer->addChar( (char)*puzTmp))) - { - fnPrintf( m_pHRequest, "** Error adding Unicode character to buffer (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - } - else - { - // Treat as though these are NON-ASCII. They will be printed - // in the form ~[0x####] - char szTempBuff[20]; - - f_sprintf( szTempBuff, "~[0x%04X]", (unsigned)(*puzTmp)); - - if (RC_BAD( rc = pBuffer->addString( szTempBuff))) - { - fnPrintf( m_pHRequest, "** Error formatting Unicode string (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - } - // We are attempting to not let our buffer get any larger than the - // Http stack buffer size. We don't really know what the limit is, but - // we are using what seems to reasonable to us... - if ((pBuffer->getBufferSize() + 9) >= RESP_WRITE_BUF_SIZE) - { - fnPrintf( m_pHRequest, "%s", pBuffer->printBuffer()); - pBuffer->reset(); - } - puzTmp++; - } - - if (bReadOnly) - { - fnPrintf( m_pHRequest, "%s", pBuffer->printBuffer()); - } - else - { - fnPrintf( m_pHRequest, "%s\" size=\"%d\">", - pBuffer->printBuffer(), MAX_FIELD_SIZE( uiLen)); - } - - -Exit: - - if (puzBuf) - { - f_free( &puzBuf); - } - - if (pBuffer) - { - pBuffer->Release(); - } -} - -/**************************************************************************** -Desc: Prints out the value for the field, assuming the field is a number field. -****************************************************************************/ -void F_WebPage::printNumberField( - FlmRecord * pRec, - void * pvField, - FLMUINT uiFieldCounter, - FLMBOOL bReadOnly) -{ - RCODE rc = FERR_OK; - FLMINT iVal; - FLMUINT uiVal; - - if (RC_BAD( rc = pRec->getUINT( pvField, &uiVal))) - { - if (RC_OK( rc = pRec->getINT( pvField, &iVal))) - { - if (bReadOnly) - { - fnPrintf( m_pHRequest, "%d", (int)iVal); - } - else - { - fnPrintf( m_pHRequest, "", - uiFieldCounter, (int)iVal, MAX_FIELD_SIZE( 0)); - } - } - else - { - fnPrintf( m_pHRequest, "** Error retrieving number field (Return Code = 0x%04X, %s)**\n", - (unsigned)rc, FlmErrorString( rc)); - } - } - else - { - if (bReadOnly) - { - fnPrintf( m_pHRequest, "%lu", (unsigned long)uiVal); - } - else - { - fnPrintf( m_pHRequest, "", uiFieldCounter, (unsigned long)uiVal); - } - } -} - -/**************************************************************************** -Desc: Prints out the value for the field, assuming the field is a binary field. -****************************************************************************/ -void F_WebPage::printBinaryField( - FlmRecord * pRec, - void * pvField, - FLMUINT uiFieldCounter, - FLMBOOL bReadOnly) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucBuf = NULL; - FLMBYTE * pszTmpBuf = NULL; - FLMBYTE * pszTmp = NULL; - FLMUINT uiLoop; - FLMUINT uiLen; - FLMUINT uiBufLen; - - uiLen = pRec->getDataLength( pvField); - - if (RC_BAD( rc = f_alloc( uiLen, &pucBuf))) - { - fnPrintf( m_pHRequest, - "** Error occured allocating memory to retrieve binary field (Return Code = 0x%04X, %s) **\n", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - if (RC_BAD(rc = pRec->getBinary( pvField, pucBuf, &uiLen))) - { - if (rc != FERR_NOT_FOUND) - { - fnPrintf( m_pHRequest, - "** Error occured retrieving binary field (Return Code = 0x%04X, %s) **\n", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - } - - if (RC_BAD( rc = f_alloc( RESP_WRITE_BUF_SIZE + 1, &pszTmpBuf))) - { - fnPrintf( m_pHRequest, - "** Error occured allocating memory to format binary field (Return Code = 0x%04X, %s) **\n", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - if (!bReadOnly) - { - fnPrintf( m_pHRequest, ""); - } - - // Scan through the binary data, present all data as Hex. - for ( pszTmp = pszTmpBuf, uiLoop = 0, uiBufLen = 0; - uiLoop < uiLen; - uiLoop++) - { - if (uiLoop) - { - *pszTmp++ = ' '; - uiBufLen++; - } - f_sprintf((char *)pszTmp, "%2.2X", (unsigned)pucBuf[uiLoop]); - pszTmp += 2; - uiBufLen += 2; - if ((uiBufLen + 3) >= RESP_WRITE_BUF_SIZE) - { - // Flush the current buffer - *pszTmp = '\0'; - fnPrintf( m_pHRequest, "%s", pszTmpBuf); - pszTmp = pszTmpBuf; - uiBufLen = 0; - } - - } - - *pszTmp = '\0'; - - if (bReadOnly) - { - fnPrintf( m_pHRequest, "%s", pszTmpBuf); - } - else - { - fnPrintf( m_pHRequest, "%s\" size=\"%d\">", pszTmpBuf, MAX_FIELD_SIZE( uiLen * 3)); - } - - -Exit: - - if (pucBuf) - { - f_free( &pucBuf); - } - - if (pszTmpBuf) - { - f_free( &pszTmpBuf); - } -} - - -/**************************************************************************** -Desc: Prints out the value for the field, assuming the field is a context field. -****************************************************************************/ -void F_WebPage::printContextField( - FlmRecord * pRec, - void * pvField, - FLMUINT uiFieldCounter, - FLMBOOL bReadOnly) -{ - RCODE rc = FERR_OK; - FLMUINT uiRecPointer; - - if (RC_OK( rc = pRec->getRecPointer( pvField, &uiRecPointer))) - { - if (bReadOnly) - { - fnPrintf( m_pHRequest, - "%lu", (unsigned long)uiRecPointer); - } - else - { - fnPrintf( m_pHRequest, - "", - uiFieldCounter, (unsigned long)uiRecPointer, MAX_FIELD_SIZE( 0)); - } - } - else - { - fnPrintf( m_pHRequest, - "** Error retrieving context field (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - } - -} - - -/**************************************************************************** -Desc: Prints out the value for the field, assuming the field is a blob field. -****************************************************************************/ -void F_WebPage::printBlobField( - FlmRecord * pRec, - void * pvField, - FLMUINT uiFieldCounter, - FLMBOOL bReadOnly) -{ - RCODE rc = FERR_OK; - FlmBlob * pBlob = NULL; - char szPath[ F_PATH_MAX_SIZE]; - FLMUINT uiLen; - - if (RC_BAD( rc = pRec->getBlob( pvField, &pBlob))) - { - fnPrintf( m_pHRequest, "** Failed to retrieve Blob object (Return Code = 0x%04X, %s) **", - (unsigned long)rc, FlmErrorString(rc)); - goto Exit; - } - - uiLen = ((FlmBlobImp *)pBlob)->getDataLength(); - if (uiLen == 0) - { - if (!bReadOnly) - { - fnPrintf( m_pHRequest, - "", - uiFieldCounter, MAX_FIELD_SIZE( 0)); - } - goto Exit; - } - - if( RC_BAD( rc = pBlob->buildFileName( szPath))) - { - fnPrintf( m_pHRequest, "** Failed to retrieve Blob filename (Return Code = 0x%04X, %s) **", - (unsigned)rc, FlmErrorString( rc)); - goto Exit; - } - - if (bReadOnly) - { - fnPrintf( m_pHRequest, ""); - printEncodedString( szPath, HTML_ENCODING); - fnPrintf( m_pHRequest, ""); - } - else - { - fnPrintf( m_pHRequest, - ""); - } - -Exit: - - if (pBlob) - { - pBlob->Release(); - } - -} - - -/**************************************************************************** -Desc: Prints out a string identifying this as a default field - error condition. -****************************************************************************/ -void F_WebPage::printDefaultField( - FlmRecord *, //pRec, - void *, //pvField, - FLMUINT, //uiFieldCounter, - FLMBOOL //bReadOnly - ) -{ - fnPrintf( m_pHRequest, "**Default Field**"); -} - -/**************************************************************************** -Desc: Prints out the hidden field identifiers -****************************************************************************/ -void F_WebPage::printFieldIds( - FLMUINT uiFieldCounter, - FLMUINT uiFieldLevel, - FLMUINT uiType, - FLMUINT uiTagNum) -{ - char szTmp[ 20]; - - f_sprintf( szTmp, "fieldLevel%u", (unsigned)uiFieldCounter); - printHiddenField( szTmp, uiFieldLevel); - f_sprintf( szTmp, "fieldType%u", (unsigned)uiFieldCounter); - printHiddenField( szTmp, uiType); - f_sprintf( szTmp, "fieldTag%u", (unsigned)uiFieldCounter); - printHiddenField( szTmp, uiTagNum); -} - - -/**************************************************************************** -Desc: Prints a table listing the fields of the supplied Log Headers. Any of - the log header pointers may be null, in which case a series of blank - entries will be created in the table for that entry. -****************************************************************************/ -void F_WebPage::printLogHeaders( - FLMBYTE * pucLastCommitted, - FLMBYTE * pucCheckpoint, - FLMBYTE * pucUncommitted) -{ - FLMBOOL bHighlight = FALSE; - // Start the table and headings... - printTableStart( NULL, 5, 100); - - printTableRowStart( FALSE); - printColumnHeading( "Offset (hex)"); - printColumnHeading( "Field"); - printColumnHeading( "Last Committed"); - printColumnHeading( "Checkpoint"); - printColumnHeading( "Uncommitted"); - printTableRowEnd(); - - // Fill in the table here. - //LOG_RFL_FILE_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_FILE_NUM); - fnPrintf( m_pHRequest, "Current RFL file"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_FILE_NUM); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_FILE_NUM); - printLogFileEntryUD( pucUncommitted, LOG_RFL_FILE_NUM); - printTableRowEnd(); - - //LOG_RFL_LAST_TRANS_OFFSET - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_TRANS_OFFSET); - fnPrintf( m_pHRequest, "Current RFL offset"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_TRANS_OFFSET); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_TRANS_OFFSET); - printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_TRANS_OFFSET); - printTableRowEnd(); - - - //LOG_RFL_LAST_CP_FILE_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_CP_FILE_NUM); - fnPrintf( m_pHRequest, "Last CP RFL file"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_CP_FILE_NUM); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_CP_FILE_NUM); - printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_CP_FILE_NUM); - printTableRowEnd(); - - //LOG_RFL_LAST_CP_OFFSET - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_CP_OFFSET); - fnPrintf( m_pHRequest, "Last CP RFL offset"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_CP_OFFSET); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_CP_OFFSET); - printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_CP_OFFSET); - printTableRowEnd(); - - //LOG_ROLLBACK_EOF - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_ROLLBACK_EOF); - fnPrintf( m_pHRequest, "End of file"); - printLogFileEntryUD( pucLastCommitted, LOG_ROLLBACK_EOF); - printLogFileEntryUD( pucCheckpoint, LOG_ROLLBACK_EOF); - printLogFileEntryUD( pucUncommitted, LOG_ROLLBACK_EOF); - printTableRowEnd(); - - //LOG_INC_BACKUP_SEQ_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_INC_BACKUP_SEQ_NUM); - fnPrintf( m_pHRequest, "Incremental backup sequence number"); - printLogFileEntryUD( pucLastCommitted, LOG_INC_BACKUP_SEQ_NUM); - printLogFileEntryUD( pucCheckpoint, LOG_INC_BACKUP_SEQ_NUM); - printLogFileEntryUD( pucUncommitted, LOG_INC_BACKUP_SEQ_NUM); - printTableRowEnd(); - - //LOG_CURR_TRANS_ID - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_CURR_TRANS_ID); - fnPrintf( m_pHRequest, "Transaction ID"); - printLogFileEntryUD( pucLastCommitted, LOG_CURR_TRANS_ID); - printLogFileEntryUD( pucCheckpoint, LOG_CURR_TRANS_ID); - printLogFileEntryUD( pucUncommitted, LOG_CURR_TRANS_ID); - printTableRowEnd(); - - //LOG_COMMIT_COUNT - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_COMMIT_COUNT); - fnPrintf( m_pHRequest, "Commit count"); - printLogFileEntryUD( pucLastCommitted, LOG_COMMIT_COUNT); - printLogFileEntryUD( pucCheckpoint, LOG_COMMIT_COUNT); - printLogFileEntryUD( pucUncommitted, LOG_COMMIT_COUNT); - printTableRowEnd(); - - //LOG_PL_FIRST_CP_BLOCK_ADDR - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_PL_FIRST_CP_BLOCK_ADDR); - fnPrintf( m_pHRequest, "First CP block address"); - printLogFileEntryUDX( pucLastCommitted, LOG_PL_FIRST_CP_BLOCK_ADDR); - printLogFileEntryUDX( pucCheckpoint, LOG_PL_FIRST_CP_BLOCK_ADDR); - printLogFileEntryUDX( pucUncommitted, LOG_PL_FIRST_CP_BLOCK_ADDR); - printTableRowEnd(); - - //LOG_LAST_RFL_FILE_DELETED - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LAST_RFL_FILE_DELETED); - fnPrintf( m_pHRequest, "Last RFL file deleted"); - printLogFileEntryUD( pucLastCommitted, LOG_LAST_RFL_FILE_DELETED); - printLogFileEntryUD( pucCheckpoint, LOG_LAST_RFL_FILE_DELETED); - printLogFileEntryUD( pucUncommitted, LOG_LAST_RFL_FILE_DELETED); - printTableRowEnd(); - - //LOG_RFL_MIN_FILE_SIZE - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_MIN_FILE_SIZE); - fnPrintf( m_pHRequest, "Minimum RFL file size"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_MIN_FILE_SIZE); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_MIN_FILE_SIZE); - printLogFileEntryUD( pucUncommitted, LOG_RFL_MIN_FILE_SIZE); - printTableRowEnd(); - - //LOG_HDR_CHECKSUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_HDR_CHECKSUM); - fnPrintf( m_pHRequest, "Header checksum"); - printLogFileEntryUW( pucLastCommitted, LOG_HDR_CHECKSUM); - printLogFileEntryUW( pucCheckpoint, LOG_HDR_CHECKSUM); - printLogFileEntryUW( pucUncommitted, LOG_HDR_CHECKSUM); - printTableRowEnd(); - - //LOG_FLAIM_VERSION - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_FLAIM_VERSION); - fnPrintf( m_pHRequest, "Flaim version"); - printLogFileEntryUW( pucLastCommitted, LOG_FLAIM_VERSION); - printLogFileEntryUW( pucCheckpoint, LOG_FLAIM_VERSION); - printLogFileEntryUW( pucUncommitted, LOG_FLAIM_VERSION); - printTableRowEnd(); - - //LOG_LAST_BACKUP_TRANS_ID - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LAST_BACKUP_TRANS_ID); - fnPrintf( m_pHRequest, "Last backup trans ID"); - printLogFileEntryUD( pucLastCommitted, LOG_LAST_BACKUP_TRANS_ID); - printLogFileEntryUD( pucCheckpoint, LOG_LAST_BACKUP_TRANS_ID); - printLogFileEntryUD( pucUncommitted, LOG_LAST_BACKUP_TRANS_ID); - printTableRowEnd(); - - //LOG_BLK_CHG_SINCE_BACKUP - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_BLK_CHG_SINCE_BACKUP); - fnPrintf( m_pHRequest, "Blocks changed since backup"); - printLogFileEntryUD( pucLastCommitted, LOG_BLK_CHG_SINCE_BACKUP); - printLogFileEntryUD( pucCheckpoint, LOG_BLK_CHG_SINCE_BACKUP); - printLogFileEntryUD( pucUncommitted, LOG_BLK_CHG_SINCE_BACKUP); - printTableRowEnd(); - - //LOG_LAST_CP_TRANS_ID - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LAST_CP_TRANS_ID); - fnPrintf( m_pHRequest, "Last CP trans ID"); - printLogFileEntryUD( pucLastCommitted, LOG_LAST_CP_TRANS_ID); - printLogFileEntryUD( pucCheckpoint, LOG_LAST_CP_TRANS_ID); - printLogFileEntryUD( pucUncommitted, LOG_LAST_CP_TRANS_ID); - printTableRowEnd(); - - //LOG_PF_FIRST_BACKCHAIN - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_PF_FIRST_BACKCHAIN); - fnPrintf( m_pHRequest, "Backchain block address"); - if (pucLastCommitted && - FB2UD( &pucLastCommitted[ LOG_PF_FIRST_BACKCHAIN]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucLastCommitted, LOG_PF_FIRST_BACKCHAIN); - } - if (pucCheckpoint && - FB2UD(&pucCheckpoint[ LOG_PF_FIRST_BACKCHAIN]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucCheckpoint, LOG_PF_FIRST_BACKCHAIN); - } - if (pucUncommitted && - FB2UD( &pucUncommitted[ LOG_PF_FIRST_BACKCHAIN]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucUncommitted, LOG_PF_FIRST_BACKCHAIN); - } - printTableRowEnd(); - - //LOG_PF_AVAIL_BLKS - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_PF_AVAIL_BLKS); - fnPrintf( m_pHRequest, "Available blocks"); - if (pucLastCommitted && - FB2UD( &pucLastCommitted[ LOG_PF_AVAIL_BLKS]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucLastCommitted, LOG_PF_AVAIL_BLKS); - } - if (pucCheckpoint && - FB2UD( &pucCheckpoint[ LOG_PF_AVAIL_BLKS]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucCheckpoint, LOG_PF_AVAIL_BLKS); - } - if (pucUncommitted && - FB2UD( &pucUncommitted[ LOG_PF_AVAIL_BLKS]) == BT_END) - { - fnPrintf( m_pHRequest, "none"); - } - else - { - printLogFileEntryUDX( pucUncommitted, LOG_PF_AVAIL_BLKS); - } - printTableRowEnd(); - - //LOG_LOGICAL_EOF - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LOGICAL_EOF); - fnPrintf( m_pHRequest, "Logical EOF"); - printLogFileEntryUD_X( pucLastCommitted, LOG_LOGICAL_EOF); - printLogFileEntryUD_X( pucCheckpoint, LOG_LOGICAL_EOF); - printLogFileEntryUD_X( pucUncommitted, LOG_LOGICAL_EOF); - printTableRowEnd(); - - - //LOG_LAST_RFL_COMMIT_ID - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LAST_RFL_COMMIT_ID); - fnPrintf( m_pHRequest, "Last RFL commit ID"); - printLogFileEntryUD( pucLastCommitted, LOG_LAST_RFL_COMMIT_ID); - printLogFileEntryUD( pucCheckpoint, LOG_LAST_RFL_COMMIT_ID); - printLogFileEntryUD( pucUncommitted, LOG_LAST_RFL_COMMIT_ID); - printTableRowEnd(); - - //LOG_KEEP_ABORTED_TRANS_IN_RFL - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_KEEP_ABORTED_TRANS_IN_RFL); - fnPrintf( m_pHRequest, "Keep aborted trans in RFL"); - printLogFileEntryBool( pucLastCommitted, LOG_KEEP_ABORTED_TRANS_IN_RFL); - printLogFileEntryBool( pucCheckpoint, LOG_KEEP_ABORTED_TRANS_IN_RFL); - printLogFileEntryBool( pucUncommitted, LOG_KEEP_ABORTED_TRANS_IN_RFL); - printTableRowEnd(); - - //LOG_PF_FIRST_BC_CNT - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_PF_FIRST_BC_CNT); - fnPrintf( m_pHRequest, "First BC count"); - printLogFileEntryUC( pucLastCommitted, LOG_PF_FIRST_BC_CNT); - printLogFileEntryUC( pucCheckpoint, LOG_PF_FIRST_BC_CNT); - printLogFileEntryUC( pucUncommitted, LOG_PF_FIRST_BC_CNT); - printTableRowEnd(); - - //LOG_KEEP_RFL_FILES - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_KEEP_RFL_FILES); - fnPrintf( m_pHRequest, "Keep RFL files"); - printLogFileEntryBool( pucLastCommitted, LOG_KEEP_RFL_FILES); - printLogFileEntryBool( pucCheckpoint, LOG_KEEP_RFL_FILES); - printLogFileEntryBool( pucUncommitted, LOG_KEEP_RFL_FILES); - printTableRowEnd(); - - //LOG_AUTO_TURN_OFF_KEEP_RFL - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_AUTO_TURN_OFF_KEEP_RFL); - fnPrintf( m_pHRequest, "Auto turn off keep RFL"); - printLogFileEntryBool( pucLastCommitted, LOG_AUTO_TURN_OFF_KEEP_RFL); - printLogFileEntryBool( pucCheckpoint, LOG_AUTO_TURN_OFF_KEEP_RFL); - printLogFileEntryBool( pucUncommitted, LOG_AUTO_TURN_OFF_KEEP_RFL); - printTableRowEnd(); - - //LOG_PF_NUM_AVAIL_BLKS - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_PF_NUM_AVAIL_BLKS); - fnPrintf( m_pHRequest, "Avail Blocks"); - printLogFileEntryUD( pucLastCommitted, LOG_PF_NUM_AVAIL_BLKS); - printLogFileEntryUD( pucCheckpoint, LOG_PF_NUM_AVAIL_BLKS); - printLogFileEntryUD( pucUncommitted, LOG_PF_NUM_AVAIL_BLKS); - printTableRowEnd(); - - //LOG_RFL_MAX_FILE_SIZE - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_MAX_FILE_SIZE); - fnPrintf( m_pHRequest, "Max file size"); - printLogFileEntryUD( pucLastCommitted, LOG_RFL_MAX_FILE_SIZE); - printLogFileEntryUD( pucCheckpoint, LOG_RFL_MAX_FILE_SIZE); - printLogFileEntryUD( pucUncommitted, LOG_RFL_MAX_FILE_SIZE); - printTableRowEnd(); - - //LOG_DB_SERIAL_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_DB_SERIAL_NUM); - fnPrintf( m_pHRequest, "DB serial number"); - printSerialNum( pucLastCommitted ? &pucLastCommitted[ LOG_DB_SERIAL_NUM] : NULL); - printSerialNum( pucCheckpoint ? &pucCheckpoint[ LOG_DB_SERIAL_NUM] : NULL); - printSerialNum( pucUncommitted ? &pucUncommitted[ LOG_DB_SERIAL_NUM] : NULL); - printTableRowEnd(); - - //LOG_LAST_TRANS_RFL_SERIAL_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_LAST_TRANS_RFL_SERIAL_NUM); - fnPrintf( m_pHRequest, "Last Trans RFL serial number"); - printSerialNum( pucLastCommitted ? &pucLastCommitted[ LOG_LAST_TRANS_RFL_SERIAL_NUM] : NULL); - printSerialNum( pucCheckpoint ? &pucCheckpoint[ LOG_LAST_TRANS_RFL_SERIAL_NUM] : NULL); - printSerialNum( pucUncommitted ? &pucUncommitted[ LOG_LAST_TRANS_RFL_SERIAL_NUM] : NULL); - printTableRowEnd(); - - //LOG_RFL_NEXT_SERIAL_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_RFL_NEXT_SERIAL_NUM); - fnPrintf( m_pHRequest, "Next RFL serial number"); - printSerialNum( pucLastCommitted ? &pucLastCommitted[ LOG_RFL_NEXT_SERIAL_NUM] : NULL); - printSerialNum( pucCheckpoint ? &pucCheckpoint[ LOG_RFL_NEXT_SERIAL_NUM] : NULL); - printSerialNum( pucUncommitted ? &pucUncommitted[ LOG_RFL_NEXT_SERIAL_NUM] : NULL); - printTableRowEnd(); - - //LOG_INC_BACKUP_SERIAL_NUM - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_INC_BACKUP_SERIAL_NUM); - fnPrintf( m_pHRequest, "Incremental backup serial number"); - printSerialNum( pucLastCommitted ? &pucLastCommitted[ LOG_INC_BACKUP_SERIAL_NUM] : NULL); - printSerialNum( pucCheckpoint ? &pucCheckpoint[ LOG_INC_BACKUP_SERIAL_NUM] : NULL); - printSerialNum( pucUncommitted ? &pucUncommitted[ LOG_INC_BACKUP_SERIAL_NUM] : NULL); - printTableRowEnd(); - - //LOG_MAX_FILE_SIZE - printTableRowStart( bHighlight = !bHighlight); - fnPrintf( m_pHRequest, "0x%X", LOG_MAX_FILE_SIZE); - fnPrintf( m_pHRequest, "Maximum file size (64K units)"); - printLogFileEntryUW( pucLastCommitted, LOG_MAX_FILE_SIZE); - printLogFileEntryUW( pucCheckpoint, LOG_MAX_FILE_SIZE); - printLogFileEntryUW( pucUncommitted, LOG_MAX_FILE_SIZE); - printTableRowEnd(); - - printTableEnd(); -} - -/******************************************************************* -Desc: -********************************************************************/ -void F_WebPage::printSerialNum( - FLMBYTE * pucSerialNum) -{ - if (pucSerialNum) - { - printTableDataStart( FALSE, JUSTIFY_LEFT); - //fnPrintf( m_pHRequest, "0x"); - for (int iLoop = 0; iLoop < F_SERIAL_NUM_SIZE; iLoop++) - { - fnPrintf( m_pHRequest, "%02X ", pucSerialNum[ iLoop]); - } - printTableDataEnd(); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - - -/******************************************************************* -Desc: Print a table entry as unsigned 4 digit hex minimum. -********************************************************************/ -void F_WebPage::printLogFileEntryUDX( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - fnPrintf( m_pHRequest, "0x%04X", FB2UD( &pucLog[ uiOffset])); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - - -/******************************************************************* -Desc: Print a table entry as unsigned decimal hex in parenthesis. -********************************************************************/ -void F_WebPage::printLogFileEntryUD_X( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - printTableDataStart( TRUE, JUSTIFY_LEFT); - printCommaNumText( (FLMUINT64)FB2UD( &pucLog[ uiOffset])); - fnPrintf( m_pHRequest, " (0x%X)", FB2UD( &pucLog[ uiOffset])); - printTableDataEnd(); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - - -/******************************************************************* -Desc: Print a table entry as unsigned decimal. -********************************************************************/ -void F_WebPage::printLogFileEntryUD( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - printCommaNum( (FLMUINT64)FB2UD( &pucLog[ uiOffset]), JUSTIFY_LEFT); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - - -/******************************************************************* -Desc: Print a table entry as unsigned word. -********************************************************************/ -void F_WebPage::printLogFileEntryUW( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - printCommaNum( (FLMUINT64)FB2UW( &pucLog[ uiOffset]), JUSTIFY_LEFT); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - - -/******************************************************************* -Desc: Print a table entry as unsigned char. -********************************************************************/ -void F_WebPage::printLogFileEntryUC( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - fnPrintf( m_pHRequest, - "%u", (unsigned char)pucLog[ uiOffset]); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - -/******************************************************************* -Desc: Print a table entry as yes or no (FLMBOOL) -********************************************************************/ -void F_WebPage::printLogFileEntryBool( - FLMBYTE * pucLog, - FLMUINT uiOffset) -{ - if (pucLog) - { - printTableDataStart(TRUE, JUSTIFY_LEFT); - printYesNo( (FLMBOOL)pucLog[ uiOffset]); - printTableDataEnd(); - } - else - { - fnPrintf( m_pHRequest, "-"); - } -} - +//------------------------------------------------------------------------- +// Desc: Base class for monitoring code. +// Tabs: 3 +// +// Copyright (c) 2001-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: imonbase.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +#define RESP_WRITE_BUF_SIZE 1024 +#define FLM_SESSION_ID_NAME "flmsessionid" + +#define MAX_FIELD_SIZE(uiSize) \ + (uiSize > 100 ? 100 : (uiSize < 20 ? 20 : uiSize)) + +/**************************************************************************** + Desc: Outputs a javascript function that, when called, causes a new + window to open and a page to be displayed in it. +****************************************************************************/ +void F_WebPage::popupFrame( void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/****************************************************************************** +Desc: This method will extract the value of the parameter in the form of + PARAMETER=VALUE +*******************************************************************************/ +RCODE F_WebPage::ExtractParameter( + FLMUINT uiNumParams, + const char ** ppszParams, + const char * pszParamName, + FLMUINT uiParamLen, + char* pszParamValue) +{ + RCODE rc = FERR_OK; + FLMUINT uiLoop; + FLMUINT uiParamNameLen; + const char* pszTemp; + FLMBOOL bFound = FALSE; + + uiParamNameLen = f_strlen( pszParamName); + for (uiLoop = 0; uiLoop < uiNumParams; uiLoop++) + { + if( f_strncmp( (char*) ppszParams[uiLoop], pszParamName, uiParamNameLen) == 0 && + (ppszParams[uiLoop][uiParamNameLen] == '\0' || + ppszParams[uiLoop][uiParamNameLen] == '=')) + { + pszTemp = &ppszParams[uiLoop][uiParamNameLen]; + if (*pszTemp == '=') + { + // Skip past the equal sign + + pszTemp++; + + f_strncpy( pszParamValue, pszTemp, uiParamLen - 1); + + // See if the param was too long to store + + if (f_strlen( pszTemp) >= uiParamLen) + { + pszParamValue[uiParamLen] = '\0'; + rc = RC_SET( FERR_MEM); + } + } + else + { + *pszParamValue = 0; + } + + bFound = TRUE; + break; + } + } + + return (bFound ? rc : RC_SET( FERR_NOT_FOUND)); +} + +/**************************************************************************** +Desc: This method will detect the presence of a parameter in the form + PARAMETER - no value will be checked. A TRUE or FALSE value will + be returned. +*****************************************************************************/ +FLMBOOL F_WebPage::DetectParameter( + FLMUINT uiNumParams, + const char ** ppszParams, + const char * pszParamName) +{ + for (FLMUINT uiLoop = 0; uiLoop < uiNumParams; uiLoop++) + { + if (f_strncmp( (char*) ppszParams[uiLoop], pszParamName, + f_strlen( (char*) pszParamName)) == 0) + { + return (TRUE); + } + } + + return (FALSE); +} + +/**************************************************************************** +Desc: +*****************************************************************************/ +RCODE F_WebPage::getDatabaseHandleParam( + FLMUINT uiNumParams, + const char ** ppszParams, + F_Session * pFlmSession, + HFDB* phDb, + char* pszKey) +{ + RCODE rc = FERR_OK; + HFDB hDb; + char szTmp[ 64]; + char * pTmp; + + if (phDb) + { + *phDb = hDb = HFDB_NULL; + } + + if (pszKey) + { + *pszKey = 0; + } + + // Need to memset the first F_SESSION_DB_KEY_LEN bytes of szTmp + // because the hash lookup algorithm expects the buffer to be padded + // with zeros at the end of the key. + + f_memset( szTmp, 0, F_SESSION_DB_KEY_LEN); + + if (RC_BAD( ExtractParameter( uiNumParams, ppszParams, "dbhandle", + sizeof(szTmp), szTmp))) + { + pTmp = &szTmp[0]; + if (RC_BAD( getFormValueByName( "dbhandle", &pTmp, sizeof(szTmp), NULL))) + { + rc = RC_SET( FERR_NOT_FOUND); + goto Exit; + } + } + + if (szTmp[0]) + { + if (RC_BAD( rc = pFlmSession->getDbHandle( szTmp, &hDb))) + { + goto Exit; + } + + if (pszKey) + { + f_memcpy( pszKey, szTmp, F_SESSION_DB_KEY_LEN); + } + } + + if (phDb) + { + *phDb = hDb; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Function to display the formatted time value in the form dd hh:mm:ss.ccc +*****************************************************************************/ +void F_WebPage::FormatTime( + FLMUINT uiTimerUnits, + char * pszFormattedTime) +{ + FLMUINT uiMilli; + FLMUINT uiSec; + FLMUINT uiMin; + FLMUINT uiHr; + FLMUINT uiDays; + FLMUINT uiTemp; + + // Initialize to NULL; + + pszFormattedTime[0] = '\0'; + + // Convert the timer units to milliseconds + + FLM_TIMER_UNITS_TO_MILLI( uiTimerUnits, uiMilli); + + // Determine the number of days + + uiDays = uiMilli / 86400000; + uiTemp = uiMilli % 86400000; + + // Now the hours + + uiHr = uiTemp / 3600000; + uiTemp = uiTemp % 3600000; + + // Determine the minutes + + uiMin = uiTemp / 60000; + uiTemp = uiTemp % 60000; + + // Determine seconds + + uiSec = uiTemp / 1000; + + // Determine the milliseconds + + uiMilli = uiTemp % 1000; + + // Put it all together - hh:mm:ss + + f_sprintf( (char *) pszFormattedTime, "%ld %2.2ld:%2.2ld:%2.2ld.%3.3ld", + uiDays, uiHr, uiMin, uiSec, uiMilli); +} + +/**************************************************************************** + Desc: Procedure to generate the HTML page that displays the usage statistics + structure. +****************************************************************************/ +RCODE F_WebPage::writeUsage( + FLM_CACHE_USAGE* pUsage, + FLMBOOL bRefresh, + const char* pszURL, + const char* pszTitle) +{ + RCODE rc = FERR_OK; + FLMBOOL bHighlight = FALSE; + char szTemp[100]; + + stdHdr(); + fnPrintf( m_pHRequest, HTML_DOCTYPE); + fnPrintf( m_pHRequest, "\n"); + + // Setup the page header & refresh control... Assuming the the first + // parameter ?Usage is already contained in the pszURL string. + + if (bRefresh) + { + fnPrintf( m_pHRequest, "" + "" + "%s\n", m_pszURLString, pszURL, pszTitle); + printStyle(); + fnPrintf( m_pHRequest, "\n\n"); + + f_sprintf( (char*) szTemp, "Stop Auto-refresh", + m_pszURLString, pszURL); + } + else + { + fnPrintf( m_pHRequest, "%s\n", pszTitle); + printStyle(); + fnPrintf( m_pHRequest, "\n\n"); + + f_sprintf( (char*) szTemp, + "Start Auto-refresh (5 sec.)", + m_pszURLString, pszURL); + } + + // Begin the table + + printTableStart( (char*) pszTitle, 4); + printTableRowStart(); + printColumnHeading( "", JUSTIFY_LEFT, FLM_IMON_COLOR_PUTTY_1, 4, 1, FALSE); + fnPrintf( m_pHRequest, "Refresh, ", m_pszURLString, pszURL); + fnPrintf( m_pHRequest, "%s\n", szTemp); + printColumnHeadingClose(); + printTableRowEnd(); + + // Write out the table headings. + + printTableRowStart(); + printColumnHeading( "Byte Offset (hex)"); + printColumnHeading( "Field Name"); + printColumnHeading( "Byte Offset"); + printColumnHeading( "Value"); + printTableRowEnd(); + + // uiMaxBytes + + printHTMLUint( (char*) "uiMaxBytes", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiMaxBytes, pUsage->uiMaxBytes, + (bHighlight = ~bHighlight)); + + // uiTotalBytesAllocated + + printHTMLUint( (char*) "uiTotalBytesAllocated", (char*) "FLMUINT", + (void*) pUsage, (void*) &pUsage->uiTotalBytesAllocated, + pUsage->uiTotalBytesAllocated, (bHighlight = ~bHighlight)); + + // uiCount + + printHTMLUint( (char*) "uiCount", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiCount, pUsage->uiCount, + (bHighlight = ~bHighlight)); + + // uiOldVerCount + + printHTMLUint( (char*) "uiOldVerCount", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiOldVerCount, pUsage->uiOldVerCount, + (bHighlight = ~bHighlight)); + + // uiOldVerBytes + + printHTMLUint( (char*) "uiOldVerBytes", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiOldVerBytes, pUsage->uiOldVerBytes, + (bHighlight = ~bHighlight)); + + // uiCacheHits + + printHTMLUint( (char*) "uiCacheHits", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiCacheHits, pUsage->uiCacheHits, + (bHighlight = ~bHighlight)); + + // uiCacheHitLooks + + printHTMLUint( (char*) "uiCacheHitLooks", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiCacheHitLooks, pUsage->uiCacheHitLooks, + (bHighlight = ~bHighlight)); + + // uiCacheFaults + + printHTMLUint( (char*) "uiCacheFaults", (char*) "FLMUINT", (void*) pUsage, + (void*) &pUsage->uiCacheFaults, pUsage->uiCacheFaults, + (bHighlight = ~bHighlight)); + + // uiCacheFaultLooks + + printHTMLUint( (char*) "uiCacheFaultLooks", (char*) "FLMUINT", + (void*) pUsage, (void*) &pUsage->uiCacheFaultLooks, + pUsage->uiCacheFaultLooks, (bHighlight = ~bHighlight)); + + printTableEnd(); + + fnPrintf( m_pHRequest, "
\n"); + fnPrintf( m_pHRequest, + "
\n"); + fnPrintf( m_pHRequest, "
\n"); + + fnPrintf( m_pHRequest, "\n"); + + fnEmit(); + + return (rc); +} + +/********************************************************************* +Desc: This function prints a linkable field in HTML +*********************************************************************/ +void F_WebPage::printHTMLLink( + const char * pszName, + const char * pszType, + void * pvBase, + void * pvAddress, + void * pvValue, + const char * pszLink, + FLMBOOL bHighlight) +{ + char szAddress[20]; + char szOffset[8]; + + printOffset( pvBase, pvAddress, szOffset); + printTableRowStart( bHighlight); + fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset + + if (pvValue) + { + printAddress( pvValue, szAddress); + fnPrintf( m_pHRequest, TD_a_s_s, pszLink, pszName); // Link & Name + fnPrintf( m_pHRequest, TD_s, pszType); // Type + fnPrintf( m_pHRequest, TD_a_s_s, pszLink, szAddress); // Link & Value + } + else + { + fnPrintf( m_pHRequest, TD_s, pszName); + fnPrintf( m_pHRequest, TD_s, pszType); + fnPrintf( m_pHRequest, TD_s, "Null"); + } + + printTableRowEnd(); +} + +/********************************************************************* +Desc: This function prints a text field in HTML +*********************************************************************/ +void F_WebPage::printHTMLString( + const char * pszName, + const char * pszType, + void * pvBase, + void * pvAddress, + const char * pszValue, + FLMBOOL bHighlight) +{ + char szOffset[8]; + + printOffset( pvBase, pvAddress, szOffset); + printTableRowStart( bHighlight); + fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset + fnPrintf( m_pHRequest, TD_s, pszName); // Name + fnPrintf( m_pHRequest, TD_s, pszType); // Type + fnPrintf( m_pHRequest, TD_s, pszValue); // Value + printTableRowEnd(); +} + +/********************************************************************* +Desc: This function prints a unsigned long (FLMUINT) field in HTML +*********************************************************************/ +void F_WebPage::printHTMLUint( + const char * pszName, + const char * pszType, + void * pvBase, + void * pvAddress, + FLMUINT uiValue, + FLMBOOL bHighlight) +{ + char szOffset[8]; + + printOffset( pvBase, pvAddress, szOffset); + printTableRowStart( bHighlight); + fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset + fnPrintf( m_pHRequest, TD_s, pszName); // Name + fnPrintf( m_pHRequest, TD_s, pszType); // Type + fnPrintf( m_pHRequest, TD_ui, uiValue); // Value + printTableRowEnd(); +} + +/********************************************************************* +Desc: This function prints a signed long (FLMINT) field in HTML +*********************************************************************/ +void F_WebPage::printHTMLInt( + const char * pszName, + const char * pszType, + void * pvBase, + void * pvAddress, + FLMINT iValue, + FLMBOOL bHighlight) +{ + char szOffset[8]; + + printOffset( pvBase, pvAddress, szOffset); + printTableRowStart( bHighlight); + fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset + fnPrintf( m_pHRequest, TD_s, pszName); // Name + fnPrintf( m_pHRequest, TD_s, pszType); // Type + fnPrintf( m_pHRequest, TD_i, iValue); // Value + printTableRowEnd(); +} + +/********************************************************************* +Desc: This function prints a unsigned long field in HTML +*********************************************************************/ +void F_WebPage::printHTMLUlong( + const char * pszName, + const char * pszType, + void * pvBase, + void * pvAddress, + unsigned long luValue, + FLMBOOL bHighlight) +{ + char szOffset[8]; + + printOffset( pvBase, pvAddress, szOffset); + printTableRowStart( bHighlight); + fnPrintf( m_pHRequest, TD_s, szOffset); // Field offset + fnPrintf( m_pHRequest, TD_s, pszName); // Name + fnPrintf( m_pHRequest, TD_s, pszType); // Type + fnPrintf( m_pHRequest, TD_lu, luValue); // Value + printTableRowEnd(); +} + +/********************************************************************* +Desc: This function takes the name of a form field, and returns a + pointer to it. This will allocate the buffer returned. The + calling function is responsible for freeing that buffer. +*********************************************************************/ +RCODE F_WebPage::getFormValueByName( + const char * pszValueTag, + char ** ppszBuf, + FLMUINT uiBufLen, + FLMUINT * puiDataLen) +{ + RCODE rc = FERR_OK; + char szTag[128]; + char * pszValue; + FLMUINT uiLen; + FLMBOOL bFreeFormData = FALSE; + FLMBOOL bFreeUserData = FALSE; + + if (puiDataLen) + { + *puiDataLen = 0; + } + +#ifdef FLM_DEBUG + if (!uiBufLen) + { + flmAssert( ppszBuf && *ppszBuf == NULL); + } +#endif + + if (f_strlen( pszValueTag) + 1 >= sizeof(szTag)) + { + flmAssert( 0); + rc = RC_SET( FERR_MEM); + goto Exit; + } + + f_sprintf( (char*) szTag, "%s=", pszValueTag); + + if (!m_pszFormData) + { + char * pszContentLength; + FLMUINT uiContentLength; + + // First we need to determine how much form data there is. + + if ((pszContentLength = (char*) fnReqHdrValue( "Content-Length")) == NULL) + { + rc = RC_SET( FERR_NOT_FOUND); + goto Exit; + } + + if ((uiContentLength = f_atoi( pszContentLength)) == 0) + { + rc = RC_SET( FERR_NOT_FOUND); + goto Exit; + } + + // Now allocate a buffer to hold the form data + + if (RC_BAD( rc = f_alloc( uiContentLength + 1, &m_pszFormData))) + { + goto Exit; + } + + bFreeFormData = TRUE; + + if (fnRecvBuffer( m_pszFormData, (size_t*) &uiContentLength) != 0) + { + rc = RC_SET( FERR_FAILURE); + goto Exit; + } + + m_pszFormData[uiContentLength] = 0; + bFreeFormData = FALSE; + } + + // Now, parse through the buffer until we find the field we are + // looking for. The data is in the form name=value:name=value... + + if ((pszValue = f_strstr( m_pszFormData, szTag)) != NULL) + { + pszValue += f_strlen( szTag); + for (uiLen = 0; + pszValue[uiLen] && pszValue[uiLen] != ':' && pszValue[uiLen] != '&'; + uiLen++); + + if (ppszBuf) + { + if (!uiBufLen) + { + uiBufLen = uiLen + 1; + bFreeUserData = TRUE; + *ppszBuf = NULL; + if (RC_BAD( rc = f_alloc( uiBufLen, ppszBuf))) + { + goto Exit; + } + } + + if (uiLen >= uiBufLen) + { + rc = RC_SET( FERR_CONV_DEST_OVERFLOW); + goto Exit; + } + + f_memcpy( *ppszBuf, pszValue, uiLen); + (*ppszBuf)[uiLen] = 0; + bFreeUserData = FALSE; + } + + if (puiDataLen) + { + *puiDataLen = uiLen + 1; + } + + goto Exit; + } + else + { + rc = RC_SET( FERR_NOT_FOUND); + goto Exit; + } + +Exit: + + if (bFreeFormData) + { + f_free( &m_pszFormData); + } + + if (bFreeUserData && *ppszBuf) + { + f_free( ppszBuf); + } + + return (rc); +} + +/**************************************************************************** +Desc: Prints the standard style sheet +****************************************************************************/ +void F_WebPage::printStyle(void) +{ + fnPrintf( m_pHRequest, + "\n", + m_pszURLString); +} + +/**************************************************************************** +Desc: Outputs a column heading using elements from the standard style sheet +****************************************************************************/ +void F_WebPage::printColumnHeading( + const char * pszHeading, + JustificationType eJustification, + const char * pszBackground, + FLMUINT uiColSpan, + FLMUINT uiRowSpan, + FLMBOOL bClose, + FLMUINT uiWidth) +{ + fnPrintf( m_pHRequest, + "\n"); + + if (pszHeading) + { + printEncodedString( pszHeading); + } + + if (bClose) + { + fnPrintf( m_pHRequest, "\n"); + } +} + +/**************************************************************************** +Desc: Closes a column heading +****************************************************************************/ +void F_WebPage::printColumnHeadingClose(void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: Encodes a string for rendering in an HTML page or for inclusion in + an URL +****************************************************************************/ +void F_WebPage::printEncodedString( + const char * pszString, + FStringEncodeType eEncodeType, + FLMBOOL bMapSlashes) +{ + char ucChar; + + while ((ucChar = *pszString) != 0) + { + if ((ucChar >= '0' && ucChar <= '9') || + (ucChar >= 'A' && ucChar <= 'Z') || + (ucChar >= 'a' && ucChar <= 'z') || + ucChar == '_' || + ( + eEncodeType == URL_PATH_ENCODING && + (ucChar == '.' || (bMapSlashes && (ucChar == '/' || ucChar == '\\'))) + )) + { + if (ucChar == '\\') + { + ucChar = '/'; + } + + fnPrintf( m_pHRequest, "%c", ucChar); + } + else if (eEncodeType == URL_PATH_ENCODING) + { + fnPrintf( m_pHRequest, "%%%02X", (unsigned) ucChar); + } + else if (eEncodeType == URL_QUERY_ENCODING) + { + if (ucChar == ' ') + { + ucChar = '+'; + } + + fnPrintf( m_pHRequest, "%%%02X", (unsigned) ucChar); + } + else // HTML encoding + { + fnPrintf( m_pHRequest, "&#%u;", (unsigned) ucChar); + } + + pszString++; + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printDocStart( + const char * pszTitle, + FLMBOOL bPrintTitle, + FLMBOOL bStdHeader, + const char * pszBackground) +{ + if (bStdHeader) + { + stdHdr(); + } + + fnPrintf( m_pHRequest, HTML_DOCTYPE); + fnPrintf( m_pHRequest, "\n"); + fnPrintf( m_pHRequest, "\n"); + printRecordStyle(); + printStyle(); + fnPrintf( m_pHRequest, "Database iMonitor - "); + printEncodedString( pszTitle); + fnPrintf( m_pHRequest, "\n"); + fnPrintf( m_pHRequest, "\n"); + fnPrintf( m_pHRequest, "\n", + pszBackground ? pszBackground : "white"); + + if (bPrintTitle) + { + printTableStart( pszTitle, 1); + printTableEnd(); + fnPrintf( m_pHRequest, "
\n"); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printDocEnd(void) +{ + fnPrintf( m_pHRequest, "\n"); + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printMenuReload(void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableStart( + const char* pszTitle, + FLMUINT uiColumns, + FLMUINT uiWidthFactor) +{ + fnPrintf( m_pHRequest, "\n"); + + if (pszTitle) + { + printTableRowStart(); + fnPrintf( m_pHRequest, ""); + printTableRowEnd(); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableEnd(void) +{ + fnPrintf( m_pHRequest, "
\n"); + printEncodedString( pszTitle); + fnPrintf( m_pHRequest, "
\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableRowStart( + FLMBOOL bHighlight) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableRowEnd(void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableDataStart( + FLMBOOL bNoWrap, + JustificationType eJustification, + FLMUINT uiWidth) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableDataEnd(void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printTableDataEmpty(void) +{ + fnPrintf( m_pHRequest, " "); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printErrorPage( + RCODE rc, + FLMBOOL bStdHeader, + const char * pszWhat) +{ + printDocStart( "Error", TRUE, bStdHeader); + + fnPrintf( m_pHRequest, "

\n"); + fnPrintf( m_pHRequest, "%s
%s (0x%04X).\n", pszWhat, FlmErrorString( rc), + (unsigned) rc); + fnPrintf( m_pHRequest, "

\n"); + + printDocEnd(); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printErrorPage( + const char * pszErrStr, + const char * pszErrStr2, + FLMBOOL bStdHeader) +{ + printDocStart( "Error", TRUE, bStdHeader); + + fnPrintf( m_pHRequest, "

\n"); + fnPrintf( m_pHRequest, "%s\n", pszErrStr); + if (pszErrStr2 && *pszErrStr2) + { + fnPrintf( m_pHRequest, "
%s\n", pszErrStr2); + } + + fnPrintf( m_pHRequest, "

\n"); + + printDocEnd(); +} + +/**************************************************************************** +Desc: Start an input form +****************************************************************************/ +void F_WebPage::printStartInputForm( + const char * pszFormName, + const char * pszPage, + FLMUINT uiFormValue) +{ + fnPrintf( m_pHRequest, + "
\n" + "\n", + pszFormName, m_pszURLString, pszPage, (unsigned) uiFormValue); +} + +/**************************************************************************** +Desc: End an input form +****************************************************************************/ +void F_WebPage::printEndInputForm(void) +{ + fnPrintf( m_pHRequest, "
"); +} + +/**************************************************************************** +Desc: Generic function to output HTML that gererates a button +****************************************************************************/ +void F_WebPage::printButton( + const char * pszContents, + ButtonTypes eBType, + const char * pszName, + const char * pszValue, + const char * pszExtra, + FLMBOOL bDisabled, + FLMBYTE ucAccessKey, + FLMUINT uiTabIndex) +{ + fnPrintf( m_pHRequest, "\n", + (char*) (pszContents ? pszContents : "")); +} + + +/**************************************************************************** +Desc: Format and output date. +****************************************************************************/ +void F_WebPage::printDate( + FLMUINT uiGMTTime, + char * pszBuffer) +{ + F_TMSTAMP timeStamp; + FLMUINT uiLocalTime; + char * pszAmPm; + const char * pszMonth; + + uiLocalTime = (FLMUINT) (uiGMTTime - f_timeGetLocalOffset()); + f_timeSecondsToDate( uiLocalTime, &timeStamp); + + pszAmPm = (char*) ((timeStamp.hour >= 12) ? (char*) "pm" : (char*) "am"); + if (timeStamp.hour > 12) + { + timeStamp.hour -= 12; + } + + if (timeStamp.hour == 0) + { + timeStamp.hour = 12; + } + + switch (timeStamp.month) + { + case 0: + pszMonth = "Jan"; + break; + case 1: + pszMonth = "Feb"; + break; + case 2: + pszMonth = "Mar"; + break; + case 3: + pszMonth = "Apr"; + break; + case 4: + pszMonth = "May"; + break; + case 5: + pszMonth = "Jun"; + break; + case 6: + pszMonth = "Jul"; + break; + case 7: + pszMonth = "Aug"; + break; + case 8: + pszMonth = "Sep"; + break; + case 9: + pszMonth = "Oct"; + break; + case 10: + pszMonth = "Nov"; + break; + default: + case 11: + pszMonth = "Dec"; + break; + } + + if (pszBuffer != NULL) + { + f_sprintf( (char*) pszBuffer, "%s %u, %u %u:%02u:%02u %s", pszMonth, + (unsigned) timeStamp.day, (unsigned) timeStamp.year, + (unsigned) timeStamp.hour, (unsigned) timeStamp.minute, + (unsigned) timeStamp.second, pszAmPm); + } + else + { + fnPrintf( m_pHRequest, "%s %u, %u %u:%02u:%02u %s", pszMonth, + (unsigned) timeStamp.day, (unsigned) timeStamp.year, + (unsigned) timeStamp.hour, (unsigned) timeStamp.minute, + (unsigned) timeStamp.second, pszAmPm); + } +} + +/**************************************************************************** +Desc: Outputs a Yes or No value based on the passed-in boolean +****************************************************************************/ +void F_WebPage::printYesNo( + FLMBOOL bYes) +{ + fnPrintf( m_pHRequest, "%s", bYes ? "Yes" : "No"); +} + +/**************************************************************************** +Desc: Outputs a number with commas, for easier reading. +****************************************************************************/ +void F_WebPage::printCommaNumText( + FLMUINT64 ui64Num) +{ + FLMUINT uiTerm; + FLMUINT64 ui64Divisor = 1; + FLMBOOL bFirstPass = TRUE; + + while ((FLMUINT64) (ui64Num / (ui64Divisor * (FLMUINT64) 1000))) + { + ui64Divisor *= 1000; + } + + while (ui64Divisor) + { + uiTerm = (FLMUINT) (ui64Num / ui64Divisor); + ui64Num -= ((FLMUINT64) uiTerm) * ui64Divisor; + + if (bFirstPass) + { + fnPrintf( m_pHRequest, "%u", (unsigned) uiTerm); + bFirstPass = FALSE; + } + else + { + fnPrintf( m_pHRequest, "%03u", (unsigned) uiTerm); + } + + if ((ui64Divisor /= (FLMUINT64) 1000) > (FLMUINT64) 0) + { + fnPrintf( m_pHRequest, ","); + } + } +} + +/**************************************************************************** +Desc: Outputs a number with commas, for easier reading. +****************************************************************************/ +void F_WebPage::printCommaNum( + FLMUINT64 ui64Num, + JustificationType eJustify, + FLMBOOL bChangedValue) +{ + printTableDataStart( TRUE, eJustify); + if (bChangedValue) + { + fnPrintf( m_pHRequest, ""); + } + + printCommaNumText( ui64Num); + + if (bChangedValue) + { + fnPrintf( m_pHRequest, ""); + } + + printTableDataEnd(); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_WebPage::acquireSession(void) +{ + RCODE rc = FERR_OK; + FLMBOOL bHttpSessionMutexLocked = FALSE; + FLMUINT uiSize; + void * pvHttpSession = NULL; + char szSessionKey[F_SESSION_KEY_LEN]; + + m_pFlmSession = NULL; + + if (!gv_FlmSysData.HttpConfigParms.fnAcquireSession) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + + if ((pvHttpSession = fnAcquireSession()) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + f_mutexLock( gv_FlmSysData.hHttpSessionMutex); + bHttpSessionMutexLocked = TRUE; + + uiSize = sizeof(szSessionKey); + if (fnGetSessionValue( pvHttpSession, FLM_SESSION_ID_NAME, + (void*) szSessionKey, (size_t*) &uiSize) != 0) + { +CreateSession: + + if (RC_BAD( rc = gv_FlmSysData.pSessionMgr->createSession( &m_pFlmSession))) + { + goto Exit; + } + + fnSetSessionValue( pvHttpSession, FLM_SESSION_ID_NAME, + m_pFlmSession->getKey(), sizeof(szSessionKey)); + } + else + { + if (RC_BAD( rc = gv_FlmSysData.pSessionMgr->getSession( szSessionKey, + &m_pFlmSession))) + { + if (rc == FERR_NOT_FOUND) + { + goto CreateSession; + } + } + } + +Exit: + + if (RC_BAD( rc)) + { + if (m_pFlmSession) + { + releaseSession(); + } + } + + if (pvHttpSession) + { + fnReleaseSession( pvHttpSession); + } + + if (bHttpSessionMutexLocked) + { + f_mutexUnlock( gv_FlmSysData.hHttpSessionMutex); + } + + return (rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::releaseSession(void) +{ + if (m_pFlmSession) + { + gv_FlmSysData.pSessionMgr->releaseSession( &m_pFlmSession); + m_pFlmSession = NULL; + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +void F_WebPage::printSpaces( + FLMUINT uiCount) +{ + while (uiCount--) + { + fnPrintf( m_pHRequest, " "); + } +} + +/**************************************************************************** +Desc: Outputs elapsed milliseconds as seconds.milli. The optional parameter + pszBuffer will cause the time to be written to pszBuffer instead of the + web page. That way it can be incorporated into more complex structures + if desired. +****************************************************************************/ +void F_WebPage::printElapTime( + FLMUINT64 ui64ElapTime, + char* pszBuffer, + JustificationType eJustify, + FLMBOOL bTimeIsMilli) +{ + FLMUINT uiHours; + FLMUINT uiMinutes; + FLMUINT uiSeconds; + FLMUINT uiMilli = 0; + + if (bTimeIsMilli) + { + uiHours = (FLMUINT) (ui64ElapTime / (FLMUINT64) (1000 * 3600)); + uiMinutes = (FLMUINT) ((ui64ElapTime / (FLMUINT64) (1000 * 60)) % (FLMUINT64) 60); + uiSeconds = (FLMUINT) ((ui64ElapTime / (FLMUINT64) 1000) % (FLMUINT64) 60); + uiMilli = (FLMUINT) (ui64ElapTime % (FLMUINT64) 1000); + } + else + { + uiHours = (FLMUINT) (ui64ElapTime / (FLMUINT64) 3600); + uiMinutes = (FLMUINT) ((ui64ElapTime / (FLMUINT64) 60) % (FLMUINT64) 60); + uiSeconds = (FLMUINT) (ui64ElapTime % (FLMUINT64) 60); + } + + if (!pszBuffer) + { + printTableDataStart( TRUE, eJustify); + } + + if (pszBuffer) + { + f_sprintf( (char*) pszBuffer, "%02u:%02u:%02u", (unsigned) uiHours, + (unsigned) uiMinutes, (unsigned) uiSeconds); + } + else + { + fnPrintf( m_pHRequest, "%02u:%02u:%02u", (unsigned) uiHours, + (unsigned) uiMinutes, (unsigned) uiSeconds); + } + + if (bTimeIsMilli) + { + if (pszBuffer) + { + char szTemp[5]; + + f_sprintf( szTemp, ".%03u", (unsigned) uiMilli); + f_strncat( (char*) pszBuffer, szTemp, 4); + } + else + { + fnPrintf( m_pHRequest, ".%03u", (unsigned) uiMilli); + } + } + + if (!pszBuffer) + { + printTableDataEnd(); + } +} + +/**************************************************************************** +Desc: This function will output a form in an already existing page that will + present a formatted display of the record passed in. An optional parameter + bReadOnly will determine if the form should allow editing of the record + or not. The default value is TRUE (No editing capability). A null may + be passed in for the FlmRecord pointer, in which case an empty display + will be created. Normally, a bReadOnly value of false would accompany + a null record so that a record can be created. The printRecordStyle() + must be called in the header section of the page prior to calling this + function. Multiple calls may be made to display multiple records per page. + The puiContext parameter must be initialized to zero before the first + (and possibly the only) call, otherwise the scripts need to run this page + will not be loaded. +****************************************************************************/ +void F_WebPage::printRecord( + const char * pszDbKey, + FlmRecord * pRec, + F_NameTable * pNameTable, + FLMUINT * puiContext, + FLMBOOL bReadOnly, + FLMUINT uiSelectedField, + FLMUINT uiFlags) +{ + #define SP " " + + FLMBOOL bEmpty = FALSE; + FLMUINT uiContainer; + FLMUINT uiDrn; + void * pvField; + FLMUINT uiFieldCounter; + FLMUINT uiFldCnt; + FLMUINT uiTagNum; + FLMUINT uiLevel; + FLMUINT uiType; + FLMUINT uiContext = 0; + char szNameBuf[128]; + + flmAssert( pNameTable); + + if (puiContext) + { + uiContext = *puiContext; + (*puiContext)++; + } + + // See if we need to write out the scripts + + if (uiContext == 0) + { + printRecordScripts(); + } + + if (!pRec) + { + bEmpty = TRUE; + uiDrn = 0; + uiContainer = 0; + } + else + { + + // Get the Drn & Container + + uiDrn = pRec->getID(); + uiContainer = pRec->getContainerID(); + } + + // Count the fields + + uiFldCnt = 0; + if (pRec != NULL) + { + pvField = pRec->root(); + while (pvField) + { + pvField = pRec->next( pvField); + uiFldCnt++; + } + } + + // Begin the form that displays the record data (if any) + + fnPrintf( m_pHRequest, + "
\n", + uiContext, gv_FlmSysData.HttpConfigParms.pszURLString); + printHiddenField( "ReadOnly", (char*) (bReadOnly ? "TRUE" : "FALSE")); + + if (pszDbKey) + { + printHiddenField( "dbhandle", (char*) (pszDbKey)); + } + + printHiddenField( (char*) "Action", "none"); + printHiddenField( (char*) "FieldLevel", (FLMUINT) 0); + printHiddenField( (char*) "FieldNumber", (FLMUINT) 0); + printHiddenField( (char*) "FieldCount", uiFldCnt); + + // Print out the block that displays the DRN and Container list + + fnPrintf( m_pHRequest, "
\n"); + fnPrintf( m_pHRequest, + "\n"); + fnPrintf( m_pHRequest, "\n\n\n", + uiDrn, pszDbKey == NULL ? "disabled" : ""); + + if (pszDbKey != NULL) + { + fnPrintf( m_pHRequest, "\n\n\n"); + } + + fnPrintf( m_pHRequest, "\n\n\n", uiContainer); + } + + fnPrintf( m_pHRequest, "\n\n"); + + if (pszDbKey != NULL) + { + + // Print out the field list drop down box. + + fnPrintf( m_pHRequest, "\n\n\n"); + + // Print out the Add, Modify, Delete action buttons. + + fnPrintf( m_pHRequest, + "\n"); + } + + fnPrintf( m_pHRequest, "
DRN  
Flags \n"); + printRetrievalFlagsPulldown( uiFlags); + fnPrintf( m_pHRequest, "
Container \n"); + if (pszDbKey != NULL) + { + printContainerPulldown( pNameTable, uiContainer); + } + else + { + fnPrintf( m_pHRequest, + " 
Field list "); + printFieldPulldown( pNameTable, uiSelectedField); + fnPrintf( m_pHRequest, "
", uiContext); + if (pRec != NULL) + { + if (!bReadOnly) + { + fnPrintf( m_pHRequest, "", uiContext); + fnPrintf( m_pHRequest, "", uiContext); + } + + fnPrintf( m_pHRequest, "", uiContext); + } + + fnPrintf( m_pHRequest, "", uiContext); + if (pRec != NULL && bReadOnly) + { + fnPrintf( m_pHRequest, "", uiContext); + } + + fnPrintf( m_pHRequest, "
\n
\n"); + + // Print out the record fields (if there are any) + + if (pRec != NULL) + { + fnPrintf( m_pHRequest, "
\n"); + if (!bReadOnly) + { + fnPrintf( m_pHRequest, "", uiContext); + if (uiFldCnt > 1) + { + fnPrintf( m_pHRequest, "", uiContext); + fnPrintf( m_pHRequest, "", uiContext); + fnPrintf( m_pHRequest, "\n", uiContext); + } + } + + fnPrintf( m_pHRequest, "
\n");
+
+		// Now for the actual data. Start with the root field.
+
+		pvField = pRec->root();
+
+		uiFieldCounter = 0;
+
+		while (pvField)
+		{
+			uiTagNum = pRec->getFieldID( pvField);
+			uiLevel = pRec->getLevel( pvField);
+			uiType = pRec->getDataType( pvField);
+
+			if (uiLevel != 0 && !bReadOnly)
+			{
+				fnPrintf( m_pHRequest,
+							"",
+						uiFieldCounter, uiContext, uiFieldCounter, uiLevel);
+			}
+
+			pNameTable->getFromTagNum( uiTagNum, NULL, szNameBuf, sizeof(szNameBuf));
+			printSpaces( uiLevel + 5);
+
+			fnPrintf( m_pHRequest, "%s%d%s%s%s", SP,
+						uiLevel, SP, szNameBuf, SP);
+
+			if (pRec->getDataLength( pvField))
+			{
+				switch (uiType)
+				{
+					case FLM_TEXT_TYPE:
+						printTextField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+					case FLM_NUMBER_TYPE:
+						printNumberField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+					case FLM_BINARY_TYPE:
+						printBinaryField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+					case FLM_CONTEXT_TYPE:
+						printContextField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+					case FLM_BLOB_TYPE:
+						printBlobField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+					default:
+						printDefaultField( pRec, pvField, uiFieldCounter, bReadOnly);
+						break;
+				}
+			}
+			else if (!bReadOnly)
+			{
+				fnPrintf( m_pHRequest,
+							"",
+						uiFieldCounter, MAX_FIELD_SIZE( 0));
+			}
+
+			// Print the hidden field Ids
+
+			printFieldIds( uiFieldCounter, uiLevel, uiType, uiTagNum);
+			fnPrintf( m_pHRequest, "\n");
+
+			pvField = pRec->next( pvField);
+			uiFieldCounter++;
+		}
+
+		fnPrintf( m_pHRequest, "
\n
\n
\n"); + } + + fnPrintf( m_pHRequest, "
\n"); + + return; +} + + +/**************************************************************************** +Desc: Prints out a style sheet specific to displaying records. +****************************************************************************/ +void F_WebPage::printRecordStyle(void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: Prints out the required scripts for displaying and updating records. +****************************************************************************/ +void F_WebPage::printRecordScripts( void) +{ + fnPrintf( m_pHRequest, "\n"); +} + +/**************************************************************************** +Desc: Prints out a hidden field with a character string value +****************************************************************************/ +void F_WebPage::printHiddenField( + const char * pszName, + const char * pszValue) +{ + fnPrintf( m_pHRequest, "", + pszName, pszValue); +} + +// +/**************************************************************************** +Desc: Prints out a hidden with an unsigned long value +****************************************************************************/ +void F_WebPage::printHiddenField( + const char * pszName, + FLMUINT uiValue) +{ + fnPrintf( m_pHRequest, "", + pszName, (unsigned) uiValue); +} + +// +/**************************************************************************** +Desc: Prints out the value for the field, assuming the field is a text field. +****************************************************************************/ +void F_WebPage::printTextField( + FlmRecord * pRec, + void * pvField, + FLMUINT uiFieldCounter, + FLMBOOL bReadOnly) +{ + RCODE rc = FERR_OK; + FLMUNICODE * puzBuf = NULL; + FLMUNICODE * puzTmp = NULL; + F_DynamicBuffer * pBuffer = NULL; + FLMUINT uiLen; + + if (RC_BAD( rc = pRec->getUnicodeLength( pvField, &uiLen))) + { + fnPrintf( m_pHRequest, + "** Error retrieving Unicode field length (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + // The length returned does not allow for 2 NULL terminators. We must + // allow for them when allocating a buffer. + + uiLen += 2; + if (RC_BAD( rc = f_alloc( uiLen, &puzBuf))) + { + fnPrintf( m_pHRequest, + "** Error allocating memory buffer (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + if (RC_BAD( rc = pRec->getUnicode( pvField, puzBuf, &uiLen))) + { + fnPrintf( m_pHRequest, + "** Error retrieving Unicode field (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + puzTmp = puzBuf; + if ((pBuffer = f_new F_DynamicBuffer) == NULL) + { + fnPrintf( m_pHRequest, "** Error allocating memory **"); + goto Exit; + } + + // Start the text field if not read only mode. + + if (!bReadOnly) + { + fnPrintf( m_pHRequest, + ""); + } + + while (*puzTmp) + { + + // Check for ASCII characters + + if ((*puzTmp >= 32) && (*puzTmp <= 126)) + { + if (RC_BAD( rc = pBuffer->addChar( (char) *puzTmp))) + { + fnPrintf( m_pHRequest, + "** Error adding Unicode character to buffer (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + } + else + { + + // Treat as though these are NON-ASCII. They will be printed in + // the form ~[0x ] + + char szTempBuff[20]; + + f_sprintf( szTempBuff, "~[0x%04X]", (unsigned) (*puzTmp)); + + if (RC_BAD( rc = pBuffer->addString( szTempBuff))) + { + fnPrintf( m_pHRequest, + "** Error formatting Unicode string (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + } + + // We are attempting to not let our buffer get any larger than the + // Http stack buffer size. We don't really know what the limit is, + // but we are using what seems to reasonable to us... + + if ((pBuffer->getBufferSize() + 9) >= RESP_WRITE_BUF_SIZE) + { + fnPrintf( m_pHRequest, "%s", pBuffer->printBuffer()); + pBuffer->reset(); + } + + puzTmp++; + } + + if (bReadOnly) + { + fnPrintf( m_pHRequest, "%s", pBuffer->printBuffer()); + } + else + { + fnPrintf( m_pHRequest, "%s\" size=\"%d\">", pBuffer->printBuffer(), + MAX_FIELD_SIZE( uiLen)); + } + +Exit: + + if (puzBuf) + { + f_free( &puzBuf); + } + + if (pBuffer) + { + pBuffer->Release(); + } +} + +// +/**************************************************************************** +Desc: Prints out the value for the field, assuming the field is a number field. +****************************************************************************/ +void F_WebPage::printNumberField( + FlmRecord * pRec, + void * pvField, + FLMUINT uiFieldCounter, + FLMBOOL bReadOnly) +{ + RCODE rc = FERR_OK; + FLMINT iVal; + FLMUINT uiVal; + + if (RC_BAD( rc = pRec->getUINT( pvField, &uiVal))) + { + if (RC_OK( rc = pRec->getINT( pvField, &iVal))) + { + if (bReadOnly) + { + fnPrintf( m_pHRequest, "%d", (int) iVal); + } + else + { + fnPrintf( m_pHRequest, + "", + uiFieldCounter, (int) iVal, MAX_FIELD_SIZE( 0)); + } + } + else + { + fnPrintf( m_pHRequest, + "** Error retrieving number field (Return Code = 0x%04X, %s)**\n", + (unsigned) rc, FlmErrorString( rc)); + } + } + else + { + if (bReadOnly) + { + fnPrintf( m_pHRequest, "%lu", + (unsigned long) uiVal); + } + else + { + fnPrintf( m_pHRequest, + "", + uiFieldCounter, (unsigned long) uiVal); + } + } +} + +/**************************************************************************** +Desc: Prints out the value for the field, assuming the field is a binary field. +****************************************************************************/ +void F_WebPage::printBinaryField( + FlmRecord * pRec, + void * pvField, + FLMUINT uiFieldCounter, + FLMBOOL bReadOnly) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucBuf = NULL; + FLMBYTE * pszTmpBuf = NULL; + FLMBYTE * pszTmp = NULL; + FLMUINT uiLoop; + FLMUINT uiLen; + FLMUINT uiBufLen; + + uiLen = pRec->getDataLength( pvField); + + if (RC_BAD( rc = f_alloc( uiLen, &pucBuf))) + { + fnPrintf( m_pHRequest, + "** Error occured allocating memory to retrieve binary field (Return Code = 0x%04X, %s) **\n", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + if (RC_BAD( rc = pRec->getBinary( pvField, pucBuf, &uiLen))) + { + if (rc != FERR_NOT_FOUND) + { + fnPrintf( m_pHRequest, + "** Error occured retrieving binary field (Return Code = 0x%04X, %s) **\n", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + } + + if (RC_BAD( rc = f_alloc( RESP_WRITE_BUF_SIZE + 1, &pszTmpBuf))) + { + fnPrintf( m_pHRequest, + "** Error occured allocating memory to format binary field (Return Code = 0x%04X, %s) **\n", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + if (!bReadOnly) + { + fnPrintf( m_pHRequest, + ""); + } + + // Scan through the binary data, present all data as Hex. + + for (pszTmp = pszTmpBuf, uiLoop = 0, uiBufLen = 0; uiLoop < uiLen; uiLoop++) + { + if (uiLoop) + { + *pszTmp++ = ' '; + uiBufLen++; + } + + f_sprintf( (char*) pszTmp, "%2.2X", (unsigned) pucBuf[uiLoop]); + + pszTmp += 2; + uiBufLen += 2; + + if ((uiBufLen + 3) >= RESP_WRITE_BUF_SIZE) + { + + // Flush the current buffer + + *pszTmp = '\0'; + fnPrintf( m_pHRequest, "%s", pszTmpBuf); + pszTmp = pszTmpBuf; + uiBufLen = 0; + } + } + + *pszTmp = '\0'; + + if (bReadOnly) + { + fnPrintf( m_pHRequest, "%s", pszTmpBuf); + } + else + { + fnPrintf( m_pHRequest, "%s\" size=\"%d\">", pszTmpBuf, + MAX_FIELD_SIZE( uiLen * 3)); + } + +Exit: + + if (pucBuf) + { + f_free( &pucBuf); + } + + if (pszTmpBuf) + { + f_free( &pszTmpBuf); + } +} + +/**************************************************************************** +Desc: Prints out the value for the field, assuming the field is a context field. +****************************************************************************/ +void F_WebPage::printContextField( + FlmRecord * pRec, + void * pvField, + FLMUINT uiFieldCounter, + FLMBOOL bReadOnly) +{ + RCODE rc = FERR_OK; + FLMUINT uiRecPointer; + + if (RC_OK( rc = pRec->getRecPointer( pvField, &uiRecPointer))) + { + if (bReadOnly) + { + fnPrintf( m_pHRequest, "%lu", + (unsigned long) uiRecPointer); + } + else + { + fnPrintf( m_pHRequest, + "", uiFieldCounter, + (unsigned long) uiRecPointer, MAX_FIELD_SIZE( 0)); + } + } + else + { + fnPrintf( m_pHRequest, + "** Error retrieving context field (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + } +} + +/**************************************************************************** +Desc: Prints out the value for the field, assuming the field is a blob field. +****************************************************************************/ +void F_WebPage::printBlobField( + FlmRecord * pRec, + void * pvField, + FLMUINT uiFieldCounter, + FLMBOOL bReadOnly) +{ + RCODE rc = FERR_OK; + FlmBlob * pBlob = NULL; + char szPath[F_PATH_MAX_SIZE]; + FLMUINT uiLen; + + if (RC_BAD( rc = pRec->getBlob( pvField, &pBlob))) + { + fnPrintf( m_pHRequest, + "** Failed to retrieve Blob object (Return Code = 0x%04X, %s) **", + (unsigned long) rc, FlmErrorString( rc)); + goto Exit; + } + + uiLen = ((FlmBlobImp *) pBlob)->getDataLength(); + if (uiLen == 0) + { + if (!bReadOnly) + { + fnPrintf( m_pHRequest, + "", uiFieldCounter, + MAX_FIELD_SIZE( 0)); + } + + goto Exit; + } + + if (RC_BAD( rc = pBlob->buildFileName( szPath))) + { + fnPrintf( m_pHRequest, + "** Failed to retrieve Blob filename (Return Code = 0x%04X, %s) **", + (unsigned) rc, FlmErrorString( rc)); + goto Exit; + } + + if (bReadOnly) + { + fnPrintf( m_pHRequest, ""); + printEncodedString( szPath, HTML_ENCODING); + fnPrintf( m_pHRequest, ""); + } + else + { + fnPrintf( m_pHRequest, + ""); + } + +Exit: + + if (pBlob) + { + pBlob->Release(); + } +} + +/**************************************************************************** +Desc: Prints out a string identifying this as a default field - error condition. +****************************************************************************/ +void F_WebPage::printDefaultField( + FlmRecord *, + void *, + FLMUINT, + FLMBOOL) +{ + fnPrintf( m_pHRequest, "**Default Field**"); +} + +/**************************************************************************** +Desc: Prints out the hidden field identifiers +****************************************************************************/ +void F_WebPage::printFieldIds( + FLMUINT uiFieldCounter, + FLMUINT uiFieldLevel, + FLMUINT uiType, + FLMUINT uiTagNum) +{ + char szTmp[20]; + + f_sprintf( szTmp, "fieldLevel%u", (unsigned) uiFieldCounter); + printHiddenField( szTmp, uiFieldLevel); + f_sprintf( szTmp, "fieldType%u", (unsigned) uiFieldCounter); + printHiddenField( szTmp, uiType); + f_sprintf( szTmp, "fieldTag%u", (unsigned) uiFieldCounter); + printHiddenField( szTmp, uiTagNum); +} + +/**************************************************************************** +Desc: Prints a table listing the fields of the supplied Log Headers. Any of + the log header pointers may be null, in which case a series of blank + entries will be created in the table for that entry. +****************************************************************************/ +void F_WebPage::printLogHeaders( + FLMBYTE * pucLastCommitted, + FLMBYTE * pucCheckpoint, + FLMBYTE * pucUncommitted) +{ + FLMBOOL bHighlight = FALSE; + + // Start the table and headings... + + printTableStart( NULL, 5, 100); + + printTableRowStart( FALSE); + printColumnHeading( "Offset (hex)"); + printColumnHeading( "Field"); + printColumnHeading( "Last Committed"); + printColumnHeading( "Checkpoint"); + printColumnHeading( "Uncommitted"); + printTableRowEnd(); + + // Fill in the table here. LOG_RFL_FILE_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_FILE_NUM); + fnPrintf( m_pHRequest, "Current RFL file"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_FILE_NUM); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_FILE_NUM); + printLogFileEntryUD( pucUncommitted, LOG_RFL_FILE_NUM); + printTableRowEnd(); + + // LOG_RFL_LAST_TRANS_OFFSET + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_TRANS_OFFSET); + fnPrintf( m_pHRequest, "Current RFL offset"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_TRANS_OFFSET); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_TRANS_OFFSET); + printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_TRANS_OFFSET); + printTableRowEnd(); + + // LOG_RFL_LAST_CP_FILE_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_CP_FILE_NUM); + fnPrintf( m_pHRequest, "Last CP RFL file"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_CP_FILE_NUM); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_CP_FILE_NUM); + printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_CP_FILE_NUM); + printTableRowEnd(); + + // LOG_RFL_LAST_CP_OFFSET + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_LAST_CP_OFFSET); + fnPrintf( m_pHRequest, "Last CP RFL offset"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_LAST_CP_OFFSET); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_LAST_CP_OFFSET); + printLogFileEntryUD( pucUncommitted, LOG_RFL_LAST_CP_OFFSET); + printTableRowEnd(); + + // LOG_ROLLBACK_EOF + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_ROLLBACK_EOF); + fnPrintf( m_pHRequest, "End of file"); + printLogFileEntryUD( pucLastCommitted, LOG_ROLLBACK_EOF); + printLogFileEntryUD( pucCheckpoint, LOG_ROLLBACK_EOF); + printLogFileEntryUD( pucUncommitted, LOG_ROLLBACK_EOF); + printTableRowEnd(); + + // LOG_INC_BACKUP_SEQ_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_INC_BACKUP_SEQ_NUM); + fnPrintf( m_pHRequest, "Incremental backup sequence number"); + printLogFileEntryUD( pucLastCommitted, LOG_INC_BACKUP_SEQ_NUM); + printLogFileEntryUD( pucCheckpoint, LOG_INC_BACKUP_SEQ_NUM); + printLogFileEntryUD( pucUncommitted, LOG_INC_BACKUP_SEQ_NUM); + printTableRowEnd(); + + // LOG_CURR_TRANS_ID + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_CURR_TRANS_ID); + fnPrintf( m_pHRequest, "Transaction ID"); + printLogFileEntryUD( pucLastCommitted, LOG_CURR_TRANS_ID); + printLogFileEntryUD( pucCheckpoint, LOG_CURR_TRANS_ID); + printLogFileEntryUD( pucUncommitted, LOG_CURR_TRANS_ID); + printTableRowEnd(); + + // LOG_COMMIT_COUNT + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_COMMIT_COUNT); + fnPrintf( m_pHRequest, "Commit count"); + printLogFileEntryUD( pucLastCommitted, LOG_COMMIT_COUNT); + printLogFileEntryUD( pucCheckpoint, LOG_COMMIT_COUNT); + printLogFileEntryUD( pucUncommitted, LOG_COMMIT_COUNT); + printTableRowEnd(); + + // LOG_PL_FIRST_CP_BLOCK_ADDR + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_PL_FIRST_CP_BLOCK_ADDR); + fnPrintf( m_pHRequest, "First CP block address"); + printLogFileEntryUDX( pucLastCommitted, LOG_PL_FIRST_CP_BLOCK_ADDR); + printLogFileEntryUDX( pucCheckpoint, LOG_PL_FIRST_CP_BLOCK_ADDR); + printLogFileEntryUDX( pucUncommitted, LOG_PL_FIRST_CP_BLOCK_ADDR); + printTableRowEnd(); + + // LOG_LAST_RFL_FILE_DELETED + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LAST_RFL_FILE_DELETED); + fnPrintf( m_pHRequest, "Last RFL file deleted"); + printLogFileEntryUD( pucLastCommitted, LOG_LAST_RFL_FILE_DELETED); + printLogFileEntryUD( pucCheckpoint, LOG_LAST_RFL_FILE_DELETED); + printLogFileEntryUD( pucUncommitted, LOG_LAST_RFL_FILE_DELETED); + printTableRowEnd(); + + // LOG_RFL_MIN_FILE_SIZE + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_MIN_FILE_SIZE); + fnPrintf( m_pHRequest, "Minimum RFL file size"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_MIN_FILE_SIZE); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_MIN_FILE_SIZE); + printLogFileEntryUD( pucUncommitted, LOG_RFL_MIN_FILE_SIZE); + printTableRowEnd(); + + // LOG_HDR_CHECKSUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_HDR_CHECKSUM); + fnPrintf( m_pHRequest, "Header checksum"); + printLogFileEntryUW( pucLastCommitted, LOG_HDR_CHECKSUM); + printLogFileEntryUW( pucCheckpoint, LOG_HDR_CHECKSUM); + printLogFileEntryUW( pucUncommitted, LOG_HDR_CHECKSUM); + printTableRowEnd(); + + // LOG_FLAIM_VERSION + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_FLAIM_VERSION); + fnPrintf( m_pHRequest, "Flaim version"); + printLogFileEntryUW( pucLastCommitted, LOG_FLAIM_VERSION); + printLogFileEntryUW( pucCheckpoint, LOG_FLAIM_VERSION); + printLogFileEntryUW( pucUncommitted, LOG_FLAIM_VERSION); + printTableRowEnd(); + + // LOG_LAST_BACKUP_TRANS_ID + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LAST_BACKUP_TRANS_ID); + fnPrintf( m_pHRequest, "Last backup trans ID"); + printLogFileEntryUD( pucLastCommitted, LOG_LAST_BACKUP_TRANS_ID); + printLogFileEntryUD( pucCheckpoint, LOG_LAST_BACKUP_TRANS_ID); + printLogFileEntryUD( pucUncommitted, LOG_LAST_BACKUP_TRANS_ID); + printTableRowEnd(); + + // LOG_BLK_CHG_SINCE_BACKUP + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_BLK_CHG_SINCE_BACKUP); + fnPrintf( m_pHRequest, "Blocks changed since backup"); + printLogFileEntryUD( pucLastCommitted, LOG_BLK_CHG_SINCE_BACKUP); + printLogFileEntryUD( pucCheckpoint, LOG_BLK_CHG_SINCE_BACKUP); + printLogFileEntryUD( pucUncommitted, LOG_BLK_CHG_SINCE_BACKUP); + printTableRowEnd(); + + // LOG_LAST_CP_TRANS_ID + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LAST_CP_TRANS_ID); + fnPrintf( m_pHRequest, "Last CP trans ID"); + printLogFileEntryUD( pucLastCommitted, LOG_LAST_CP_TRANS_ID); + printLogFileEntryUD( pucCheckpoint, LOG_LAST_CP_TRANS_ID); + printLogFileEntryUD( pucUncommitted, LOG_LAST_CP_TRANS_ID); + printTableRowEnd(); + + // LOG_PF_FIRST_BACKCHAIN + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_PF_FIRST_BACKCHAIN); + fnPrintf( m_pHRequest, "Backchain block address"); + if (pucLastCommitted && + FB2UD( &pucLastCommitted[LOG_PF_FIRST_BACKCHAIN]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucLastCommitted, LOG_PF_FIRST_BACKCHAIN); + } + + if (pucCheckpoint && + FB2UD( &pucCheckpoint[LOG_PF_FIRST_BACKCHAIN]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucCheckpoint, LOG_PF_FIRST_BACKCHAIN); + } + + if (pucUncommitted && + FB2UD( &pucUncommitted[LOG_PF_FIRST_BACKCHAIN]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucUncommitted, LOG_PF_FIRST_BACKCHAIN); + } + + printTableRowEnd(); + + // LOG_PF_AVAIL_BLKS + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_PF_AVAIL_BLKS); + fnPrintf( m_pHRequest, "Available blocks"); + if (pucLastCommitted && + FB2UD( &pucLastCommitted[LOG_PF_AVAIL_BLKS]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucLastCommitted, LOG_PF_AVAIL_BLKS); + } + + if (pucCheckpoint && FB2UD( &pucCheckpoint[LOG_PF_AVAIL_BLKS]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucCheckpoint, LOG_PF_AVAIL_BLKS); + } + + if (pucUncommitted && FB2UD( &pucUncommitted[LOG_PF_AVAIL_BLKS]) == BT_END) + { + fnPrintf( m_pHRequest, "none"); + } + else + { + printLogFileEntryUDX( pucUncommitted, LOG_PF_AVAIL_BLKS); + } + + printTableRowEnd(); + + // LOG_LOGICAL_EOF + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LOGICAL_EOF); + fnPrintf( m_pHRequest, "Logical EOF"); + printLogFileEntryUD_X( pucLastCommitted, LOG_LOGICAL_EOF); + printLogFileEntryUD_X( pucCheckpoint, LOG_LOGICAL_EOF); + printLogFileEntryUD_X( pucUncommitted, LOG_LOGICAL_EOF); + printTableRowEnd(); + + // LOG_LAST_RFL_COMMIT_ID + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LAST_RFL_COMMIT_ID); + fnPrintf( m_pHRequest, "Last RFL commit ID"); + printLogFileEntryUD( pucLastCommitted, LOG_LAST_RFL_COMMIT_ID); + printLogFileEntryUD( pucCheckpoint, LOG_LAST_RFL_COMMIT_ID); + printLogFileEntryUD( pucUncommitted, LOG_LAST_RFL_COMMIT_ID); + printTableRowEnd(); + + // LOG_KEEP_ABORTED_TRANS_IN_RFL + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_KEEP_ABORTED_TRANS_IN_RFL); + fnPrintf( m_pHRequest, "Keep aborted trans in RFL"); + printLogFileEntryBool( pucLastCommitted, LOG_KEEP_ABORTED_TRANS_IN_RFL); + printLogFileEntryBool( pucCheckpoint, LOG_KEEP_ABORTED_TRANS_IN_RFL); + printLogFileEntryBool( pucUncommitted, LOG_KEEP_ABORTED_TRANS_IN_RFL); + printTableRowEnd(); + + // LOG_PF_FIRST_BC_CNT + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_PF_FIRST_BC_CNT); + fnPrintf( m_pHRequest, "First BC count"); + printLogFileEntryUC( pucLastCommitted, LOG_PF_FIRST_BC_CNT); + printLogFileEntryUC( pucCheckpoint, LOG_PF_FIRST_BC_CNT); + printLogFileEntryUC( pucUncommitted, LOG_PF_FIRST_BC_CNT); + printTableRowEnd(); + + // LOG_KEEP_RFL_FILES + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_KEEP_RFL_FILES); + fnPrintf( m_pHRequest, "Keep RFL files"); + printLogFileEntryBool( pucLastCommitted, LOG_KEEP_RFL_FILES); + printLogFileEntryBool( pucCheckpoint, LOG_KEEP_RFL_FILES); + printLogFileEntryBool( pucUncommitted, LOG_KEEP_RFL_FILES); + printTableRowEnd(); + + // LOG_AUTO_TURN_OFF_KEEP_RFL + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_AUTO_TURN_OFF_KEEP_RFL); + fnPrintf( m_pHRequest, "Auto turn off keep RFL"); + printLogFileEntryBool( pucLastCommitted, LOG_AUTO_TURN_OFF_KEEP_RFL); + printLogFileEntryBool( pucCheckpoint, LOG_AUTO_TURN_OFF_KEEP_RFL); + printLogFileEntryBool( pucUncommitted, LOG_AUTO_TURN_OFF_KEEP_RFL); + printTableRowEnd(); + + // LOG_PF_NUM_AVAIL_BLKS + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_PF_NUM_AVAIL_BLKS); + fnPrintf( m_pHRequest, "Avail Blocks"); + printLogFileEntryUD( pucLastCommitted, LOG_PF_NUM_AVAIL_BLKS); + printLogFileEntryUD( pucCheckpoint, LOG_PF_NUM_AVAIL_BLKS); + printLogFileEntryUD( pucUncommitted, LOG_PF_NUM_AVAIL_BLKS); + printTableRowEnd(); + + // LOG_RFL_MAX_FILE_SIZE + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_MAX_FILE_SIZE); + fnPrintf( m_pHRequest, "Max file size"); + printLogFileEntryUD( pucLastCommitted, LOG_RFL_MAX_FILE_SIZE); + printLogFileEntryUD( pucCheckpoint, LOG_RFL_MAX_FILE_SIZE); + printLogFileEntryUD( pucUncommitted, LOG_RFL_MAX_FILE_SIZE); + printTableRowEnd(); + + // LOG_DB_SERIAL_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_DB_SERIAL_NUM); + fnPrintf( m_pHRequest, "DB serial number"); + printSerialNum( pucLastCommitted ? &pucLastCommitted[LOG_DB_SERIAL_NUM] : NULL); + printSerialNum( pucCheckpoint ? &pucCheckpoint[LOG_DB_SERIAL_NUM] : NULL); + printSerialNum( pucUncommitted ? &pucUncommitted[LOG_DB_SERIAL_NUM] : NULL); + printTableRowEnd(); + + // LOG_LAST_TRANS_RFL_SERIAL_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_LAST_TRANS_RFL_SERIAL_NUM); + fnPrintf( m_pHRequest, "Last Trans RFL serial number"); + printSerialNum( pucLastCommitted ? &pucLastCommitted[LOG_LAST_TRANS_RFL_SERIAL_NUM] : + NULL); + printSerialNum( pucCheckpoint ? &pucCheckpoint[LOG_LAST_TRANS_RFL_SERIAL_NUM] : NULL); + printSerialNum( pucUncommitted ? &pucUncommitted[LOG_LAST_TRANS_RFL_SERIAL_NUM] : NULL); + printTableRowEnd(); + + // LOG_RFL_NEXT_SERIAL_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_RFL_NEXT_SERIAL_NUM); + fnPrintf( m_pHRequest, "Next RFL serial number"); + printSerialNum( pucLastCommitted ? &pucLastCommitted[LOG_RFL_NEXT_SERIAL_NUM] : NULL); + printSerialNum( pucCheckpoint ? &pucCheckpoint[LOG_RFL_NEXT_SERIAL_NUM] : NULL); + printSerialNum( pucUncommitted ? &pucUncommitted[LOG_RFL_NEXT_SERIAL_NUM] : NULL); + printTableRowEnd(); + + // LOG_INC_BACKUP_SERIAL_NUM + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_INC_BACKUP_SERIAL_NUM); + fnPrintf( m_pHRequest, "Incremental backup serial number"); + printSerialNum( pucLastCommitted ? &pucLastCommitted[LOG_INC_BACKUP_SERIAL_NUM] : NULL); + printSerialNum( pucCheckpoint ? &pucCheckpoint[LOG_INC_BACKUP_SERIAL_NUM] : NULL); + printSerialNum( pucUncommitted ? &pucUncommitted[LOG_INC_BACKUP_SERIAL_NUM] : NULL); + printTableRowEnd(); + + // LOG_MAX_FILE_SIZE + + printTableRowStart( bHighlight = !bHighlight); + fnPrintf( m_pHRequest, "0x%X", LOG_MAX_FILE_SIZE); + fnPrintf( m_pHRequest, "Maximum file size (64K units)"); + printLogFileEntryUW( pucLastCommitted, LOG_MAX_FILE_SIZE); + printLogFileEntryUW( pucCheckpoint, LOG_MAX_FILE_SIZE); + printLogFileEntryUW( pucUncommitted, LOG_MAX_FILE_SIZE); + printTableRowEnd(); + + printTableEnd(); +} + +/******************************************************************* +Desc: +********************************************************************/ +void F_WebPage::printSerialNum( + FLMBYTE * pucSerialNum) +{ + if (pucSerialNum) + { + printTableDataStart( FALSE, JUSTIFY_LEFT); + + // fnPrintf( m_pHRequest, "0x"); + + for (int iLoop = 0; iLoop < F_SERIAL_NUM_SIZE; iLoop++) + { + fnPrintf( m_pHRequest, "%02X ", pucSerialNum[iLoop]); + } + + printTableDataEnd(); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as unsigned 4 digit hex minimum. +********************************************************************/ +void F_WebPage::printLogFileEntryUDX( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + fnPrintf( m_pHRequest, "0x%04X", FB2UD( &pucLog[uiOffset])); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as unsigned decimal hex in parenthesis. +********************************************************************/ +void F_WebPage::printLogFileEntryUD_X( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + printTableDataStart( TRUE, JUSTIFY_LEFT); + printCommaNumText( (FLMUINT64) FB2UD( &pucLog[uiOffset])); + fnPrintf( m_pHRequest, " (0x%X)", FB2UD( &pucLog[uiOffset])); + printTableDataEnd(); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as unsigned decimal. +********************************************************************/ +void F_WebPage::printLogFileEntryUD( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + printCommaNum( (FLMUINT64) FB2UD( &pucLog[uiOffset]), JUSTIFY_LEFT); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as unsigned word. +********************************************************************/ +void F_WebPage::printLogFileEntryUW( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + printCommaNum( (FLMUINT64) FB2UW( &pucLog[uiOffset]), JUSTIFY_LEFT); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as unsigned char. +********************************************************************/ +void F_WebPage::printLogFileEntryUC( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + fnPrintf( m_pHRequest, "%u", (unsigned char) pucLog[uiOffset]); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} + +/******************************************************************* +Desc: Print a table entry as yes or no (FLMBOOL) +********************************************************************/ +void F_WebPage::printLogFileEntryBool( + FLMBYTE * pucLog, + FLMUINT uiOffset) +{ + if (pucLog) + { + printTableDataStart( TRUE, JUSTIFY_LEFT); + printYesNo( (FLMBOOL) pucLog[uiOffset]); + printTableDataEnd(); + } + else + { + fnPrintf( m_pHRequest, "-"); + } +} diff --git a/flaim/src/imonfact.cpp b/flaim/src/imonfact.cpp index b58db34..662f674 100644 --- a/flaim/src/imonfact.cpp +++ b/flaim/src/imonfact.cpp @@ -473,11 +473,6 @@ static F_WebPage * createHttpConfigParmsPage() return new F_HttpConfigParmsPage; } -static F_WebPage * createEventHdrPage() -{ - return new F_EventHdrPage; -} - static F_WebPage * createFlmThreadsPage() { return new F_FlmThreadsPage; @@ -631,7 +626,6 @@ CREATE_FN F_WebPageFactory::m_fnGblAccess = createGblAccessPage; CREATE_FN F_WebPageFactory::m_fnSessionAccess = createSessionAccessPage; RegistryEntry F_WebPageFactory::m_Registry[] = { - {"EventHdr", createEventHdrPage, FALSE}, {"FDB", createFDBPage, FALSE}, {"FFile", createFFilePage, FALSE}, {"FileHashTbl", createFileHashTblPage, FALSE}, diff --git a/flaim/src/imonfdb.cpp b/flaim/src/imonfdb.cpp index b86c0e2..004e092 100644 --- a/flaim/src/imonfdb.cpp +++ b/flaim/src/imonfdb.cpp @@ -43,8 +43,8 @@ RCODE F_FDBPage::display( char szBucket[20]; FLMINT uiBucket; FDB LocalFDB; - FDB_p pDb=NULL; - FFILE_p pFile = NULL; + FDB * pDb=NULL; + FFILE * pFile = NULL; char szTemp[GENERIC_SIZE_A]; FLMBOOL bpFileInc = FALSE; char szAddress[20]; @@ -111,7 +111,7 @@ RCODE F_FDBPage::display( // Now we will search for the FFile first, then look for the FDB. f_mutexLock( gv_FlmSysData.hShareMutex); - pFile = (FFILE_p)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; + pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; while ((pFile != NULL) && ((void *)pFile != pvFFileAddress)) { @@ -286,7 +286,7 @@ Exit: the contents of the FDB structure ****************************************************************************/ void F_FDBPage::write_data( - FDB_p pDb, + FDB * pDb, const char * pszFDBAddress, FLMUINT uiBucket) { @@ -315,7 +315,7 @@ void F_FDBPage::write_data( } - printHTMLLink( "pFile", "FFILE_p", (void *)pDb, (void *)&pDb->pFile, + printHTMLLink( "pFile", "FFILE *", (void *)pDb, (void *)&pDb->pFile, (void *)pDb->pFile, szTemp, (bHighlight = ~bHighlight)); @@ -331,7 +331,7 @@ void F_FDBPage::write_data( printHTMLLink( "pDict", - "FDICT_p", + "FDICT *", (void *)pDb, (void *)&pDb->pDict, (void *)pDb->pDict, @@ -343,7 +343,7 @@ void F_FDBPage::write_data( printAddress( pDb->pDict, szAddress); printHTMLString( "pDict", - "FDICT_p", + "FDICT *", (void *)pDb, (void *)&pDb->pDict, szAddress, @@ -366,7 +366,7 @@ void F_FDBPage::write_data( printHTMLLink( "pNextForFile", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pNextForFile, (void *)pDb->pNextForFile, @@ -378,7 +378,7 @@ void F_FDBPage::write_data( printAddress( pDb->pNextForFile, szAddress); printHTMLString( "pNextForFile", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pNextForFile, szAddress, @@ -403,7 +403,7 @@ void F_FDBPage::write_data( printHTMLLink( "pPrevForFile", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pPrevForFile, (void *)pDb->pPrevForFile, @@ -415,7 +415,7 @@ void F_FDBPage::write_data( printAddress( pDb->pPrevForFile, szAddress); printHTMLString( "pPrevForFile", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pPrevForFile, szAddress, @@ -485,7 +485,7 @@ void F_FDBPage::write_data( printHTMLLink( "pSFileHdl", - "F_SuperFileHdl_p", + "F_SuperFileHdl *", (void *)pDb, (void *)&pDb->pSFileHdl, (void *)pDb->pSFileHdl, @@ -497,7 +497,7 @@ void F_FDBPage::write_data( printAddress( pDb->pSFileHdl, szAddress); printHTMLString( "pSFileHdl", - "F_SuperFileHdl_p", + "F_SuperFileHdl *", (void *)pDb, (void *)&pDb->pSFileHdl, szAddress, @@ -897,7 +897,7 @@ void F_FDBPage::write_data( printHTMLLink( "pNextReadTrans", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pNextReadTrans, (void *)pDb->pNextReadTrans, @@ -909,7 +909,7 @@ void F_FDBPage::write_data( printAddress( pDb->pNextReadTrans, szAddress); printHTMLString( "pNextReadTrans", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pNextReadTrans, szAddress, @@ -937,7 +937,7 @@ void F_FDBPage::write_data( printHTMLLink( "pPrevReadTrans", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pPrevReadTrans, (void *)pDb->pPrevReadTrans, @@ -949,7 +949,7 @@ void F_FDBPage::write_data( printAddress( pDb->pPrevReadTrans, szAddress); printHTMLString( "pPrevReadTrans", - "FDB_p", + "FDB *", (void *)pDb, (void *)&pDb->pPrevReadTrans, szAddress, diff --git a/flaim/src/imonffil.cpp b/flaim/src/imonffil.cpp index 9c7c39e..733fb16 100644 --- a/flaim/src/imonffil.cpp +++ b/flaim/src/imonffil.cpp @@ -39,7 +39,7 @@ RCODE F_FFilePage::display( char szBucket[ 4]; FLMUINT uiBucket; FFILE localFFile; - FFILE_p pFile; + FFILE * pFile; FLMBOOL bRefresh; void * pvAddress; char szAddress[GENERIC_SIZE_B]; @@ -96,7 +96,7 @@ RCODE F_FFilePage::display( } uiBucket = f_atoud( szBucket); - pFile = (FFILE_p)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; + pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; } else if ( (f_stricmp( szFrom, "SCacheBlock") == 0) || (f_stricmp( szFrom, "RCache") == 0) || @@ -124,7 +124,7 @@ RCODE F_FFilePage::display( pvAddress = (void *)f_atoud( szAddress); - pFile = (FFILE_p)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; + pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; while (pFile && (void *)pFile != pvAddress) { @@ -216,7 +216,7 @@ RCODE F_FFilePage::display( if (gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket) { - pFile = (FFILE_p)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; + pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; } // Now let's make sure we are looking at the right FFile... @@ -413,7 +413,7 @@ Exit: the contents of the FFile structure ****************************************************************************/ void F_FFilePage::write_data( - FFILE_p pFile, + FFILE * pFile, void * pvFFileAddress, DATASTRUCT * pDataStruct) { @@ -447,7 +447,7 @@ void F_FFilePage::write_data( printHTMLLink( "pNext", - "FFILE_p", + "FFILE *", (void *)pFile, (void *)&pFile->pNext, (void *)pFile->pNext, @@ -468,7 +468,7 @@ void F_FFilePage::write_data( printHTMLLink( "pPrev", - "FFILE_p", + "FFILE *", (void *)pFile, (void *)&pFile->pPrev, (void *)pFile->pPrev, @@ -528,7 +528,7 @@ void F_FFilePage::write_data( printHTMLLink( "pFirstDb", - "FDB_p", + "FDB *", (void *)pFile, (void *)&pFile->pFirstDb, (void *)pFile->pFirstDb, @@ -572,7 +572,7 @@ void F_FFilePage::write_data( printHTMLLink( "pNextNUFile", - "FFILE_p", + "FFILE *", (void *)pFile, (void *)&pFile->pNextNUFile, (void *)pFile->pNextNUFile, @@ -593,7 +593,7 @@ void F_FFilePage::write_data( printHTMLLink( "pPrevNUFile", - "FFILE_p", + "FFILE *", (void *)pFile, (void *)&pFile->pPrevNUFile, (void *)pFile->pPrevNUFile, @@ -816,7 +816,7 @@ void F_FFilePage::write_data( printHTMLLink( "pOpenNotifies", - "FNOTIFY_p", + "FNOTIFY *", (void *)pFile, (void *)&pFile->pOpenNotifies, (void *)pFile->pOpenNotifies, @@ -835,7 +835,7 @@ void F_FFilePage::write_data( printHTMLLink( "pCloseNotifies", - "FNOTIFY_p", + "FNOTIFY *", (void *)pFile, (void *)&pFile->pCloseNotifies, (void *)pFile->pCloseNotifies, @@ -854,7 +854,7 @@ void F_FFilePage::write_data( printHTMLLink( "pDictList", - "FDICT_p", + "FDICT *", (void *)pFile, (void *)&pFile->pDictList, (void *)pFile->pDictList, @@ -1170,7 +1170,7 @@ void F_FFilePage::write_data( printHTMLLink( "pLockNotifies", - "FNOTIFY_p", + "FNOTIFY *", (void *)pFile, (void *)&pFile->pLockNotifies, (void *)pFile->pLockNotifies, @@ -1207,7 +1207,7 @@ void F_FFilePage::write_data( printHTMLLink( "pFirstReadTrans", - "FDB_p", + "FDB *", (void *)pFile, (void *)&pFile->pFirstReadTrans, (void *)pFile->pFirstReadTrans, @@ -1233,7 +1233,7 @@ void F_FFilePage::write_data( printHTMLLink( "pLastReadTrans", - "FDB_p", + "FDB *", (void *)pFile, (void *)&pFile->pLastReadTrans, (void *)pFile->pLastReadTrans, @@ -1259,7 +1259,7 @@ void F_FFilePage::write_data( printHTMLLink( "pFirstKilledTrans", - "FDB_p", + "FDB *", (void *)pFile, (void *)&pFile->pFirstKilledTrans, (void *)pFile->pFirstKilledTrans, diff --git a/flaim/src/imonfhsh.cpp b/flaim/src/imonfhsh.cpp index 4c95e10..85883b6 100644 --- a/flaim/src/imonfhsh.cpp +++ b/flaim/src/imonfhsh.cpp @@ -37,7 +37,7 @@ RCODE F_FileHashTblPage::display( FLMINT iSindex; FLMINT iNindex; FLMBOOL found = FALSE; - FBUCKET_p pFileHashTbl; + FBUCKET * pFileHashTbl; FLMBOOL buckets[FILE_HASH_ENTRIES]; FLMINT next[FILE_HASH_ENTRIES]; FLMBOOL bRefresh; diff --git a/flaim/src/imonfmgr.cpp b/flaim/src/imonfmgr.cpp index c654e37..33c3b34 100644 --- a/flaim/src/imonfmgr.cpp +++ b/flaim/src/imonfmgr.cpp @@ -33,7 +33,7 @@ RCODE F_FileHdlMgrPage::display( const char ** ppszParams) { RCODE rc = FERR_OK; - F_FileHdlMgr_p pFileHdlMgr; + F_FileHdlMgr * pFileHdlMgr; F_ListMgr * pListMgr; FLMUINT uiNumAvailItems; FLMUINT uiNumUsedItems; diff --git a/flaim/src/imonfsys.cpp b/flaim/src/imonfsys.cpp index bd05cb6..a8d1127 100644 --- a/flaim/src/imonfsys.cpp +++ b/flaim/src/imonfsys.cpp @@ -146,7 +146,7 @@ void F_FlmSysDataPage::write_data( printHTMLLink( "pMrnuFile", - "FFILE_p", + "FFILE *", (void *)&gv_FlmSysData, (void *)&gv_FlmSysData.pMrnuFile, (void *)gv_FlmSysData.pMrnuFile, @@ -168,7 +168,7 @@ void F_FlmSysDataPage::write_data( printHTMLLink( "pLrnuFile", - "FFILE_p", + "FFILE *", (void *)&gv_FlmSysData, (void *)&gv_FlmSysData.pLrnuFile, (void *)gv_FlmSysData.pLrnuFile, @@ -183,7 +183,7 @@ void F_FlmSysDataPage::write_data( printHTMLLink( "pFileHashTbl", - "FFILE_p", + "FFILE *", (void *)&gv_FlmSysData, (void *)&gv_FlmSysData.pFileHashTbl, (void *)gv_FlmSysData.pFileHashTbl, @@ -235,7 +235,7 @@ void F_FlmSysDataPage::write_data( printHTMLLink( "pFileHdlMgr", - "FFILE_p", + "FFILE *", (void *)&gv_FlmSysData, (void *)&gv_FlmSysData.pFileHdlMgr, (void *)gv_FlmSysData.pFileHdlMgr, @@ -622,24 +622,6 @@ void F_FlmSysDataPage::write_data( - // EventHdrs - Event Headers - f_sprintf( (char *)pszTemp, "EventHdrs", - m_pszURLString); - printAddress( (void *)&gv_FlmSysData.EventHdrs, szAddress); - f_sprintf( (char *)pszTemp2, "%s", - m_pszURLString, szAddress); - - printHTMLString( - (char *)pszTemp, - "FEVENT_HDR", - (void *)&gv_FlmSysData, - (void *)&gv_FlmSysData.EventHdrs[0], - (char *)szAddress, - (bHighlight = !bHighlight)); - - - - // KRefPool - Update Pool printAddress( (void *)&gv_FlmSysData.KRefPool, szAddress); printHTMLString( @@ -1129,136 +1111,5 @@ RCODE F_HttpConfigParmsPage::display( fnEmit(); - return( rc); -} - -/**************************************************************************** -Desc: This implements the display method of the F_FEventHdr class -*****************************************************************************/ -RCODE F_EventHdrPage::display( - FLMUINT uiNumParams, - const char ** ppszParams) -{ - RCODE rc = FERR_OK; - FLMUINT uiLoop = 0; - FEVENT_p pCurrentEvent = NULL; - - char szAddress[20]; - char szOffset[8]; - - F_UNREFERENCED_PARM( uiNumParams); - F_UNREFERENCED_PARM( ppszParams); - - - printDocStart( "EventHdrs", FALSE); - - for (uiLoop = 0; uiLoop < F_MAX_EVENT_CATEGORIES; uiLoop++) - { - - - f_sprintf( (char *)szAddress, "EventHdrs[%lu]\n", uiLoop); - printTableStart( (char *)szAddress, 4); - - printColumnHeading( "Byte Offset (hex)"); - printColumnHeading( "Field Name"); - printColumnHeading( "Field Type"); - printColumnHeading( "Value"); - - printAddress( (void *)gv_FlmSysData.EventHdrs[uiLoop].pEventCBList, szAddress); - printOffset( &gv_FlmSysData.EventHdrs[uiLoop], - &gv_FlmSysData.EventHdrs[uiLoop].pEventCBList, - szOffset); - printTableRowStart(); - fnPrintf( m_pHRequest, TD_s "pEventCBList FEVENT_p" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printAddress( (void *)gv_FlmSysData.EventHdrs[uiLoop].hMutex, szAddress); - printOffset( &gv_FlmSysData.EventHdrs[uiLoop], - &gv_FlmSysData.EventHdrs[uiLoop].hMutex, - szOffset); - printTableRowStart( TRUE); - fnPrintf( m_pHRequest, TD_s "hMutex F_MUTEX" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printTableEnd(); - - f_mutexLock( gv_FlmSysData.EventHdrs[uiLoop].hMutex); - pCurrentEvent = gv_FlmSysData.EventHdrs[uiLoop].pEventCBList; - while (pCurrentEvent) - { - displayEvent( pCurrentEvent); - pCurrentEvent = pCurrentEvent->pNext; - } // end of while loop - f_mutexUnlock( gv_FlmSysData.EventHdrs[uiLoop].hMutex); - fnPrintf( m_pHRequest, "
\n"); - - } // end of for loop - - - fnPrintf( m_pHRequest, " \n"); - fnEmit(); - return( rc); -} - - -/**************************************************************************** -Desc: Displays a single FEVENT struct. Assumes that the event mutex has - already been locked! -*****************************************************************************/ -RCODE F_EventHdrPage::displayEvent( - FEVENT_p pCurrentEvent) -{ - RCODE rc = FERR_OK; - char szOffset[8]; - char szAddress[20]; - char szTitle[30]; - - printAddress( (void *)pCurrentEvent, szAddress); - f_sprintf( (char *)szTitle, "FEVENT %s", szAddress); - printTableStart( (char *)szTitle, 4); - - printColumnHeading( "Byte Offset (hex)"); - printColumnHeading( "Field Name"); - printColumnHeading( "Field Type"); - printColumnHeading( "Value"); - - printOffset( pCurrentEvent, &pCurrentEvent->eCategory, szOffset); - printTableRowStart(); - fnPrintf( m_pHRequest, TD_s "eCategory FEventCategory" TD_lu, - szOffset, pCurrentEvent->eCategory); - printTableRowEnd(); - - printAddress( *((void **)&pCurrentEvent->fnEventCB), szAddress); - printOffset( pCurrentEvent, &pCurrentEvent->fnEventCB, szOffset); - printTableRowStart( TRUE); - fnPrintf( m_pHRequest, TD_s "fnEventCB FEVENT_CB" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printAddress( (void *)pCurrentEvent->pvAppData, szAddress); - printOffset( pCurrentEvent, &pCurrentEvent->pvAppData, szOffset); - printTableRowStart(); - fnPrintf( m_pHRequest, TD_s "pvAppData void *" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printAddress( (void *)pCurrentEvent->pNext, szAddress); - printOffset( pCurrentEvent, &pCurrentEvent->pNext, szOffset); - printTableRowStart( TRUE); - fnPrintf( m_pHRequest, TD_s "pNext FEVENT_p" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printAddress( (void *)pCurrentEvent->pPrev, szAddress); - printOffset( pCurrentEvent, &pCurrentEvent->pPrev, szOffset); - printTableRowStart(); - fnPrintf( m_pHRequest, TD_s "pPrev FEVENT_p" TD_s, - szOffset, szAddress); - printTableRowEnd(); - - printTableEnd(); - return( rc); } diff --git a/flaim/src/imonix.cpp b/flaim/src/imonix.cpp index 0f214ce..90fdc89 100644 --- a/flaim/src/imonix.cpp +++ b/flaim/src/imonix.cpp @@ -1267,16 +1267,13 @@ Desc: Output the current thread status to the web page. void F_IndexListPage::getIndexListStatus( FLMUINT uiIndexListThreadId, FLMBOOL bStopIndexList, - IXLIST_STATUS * pIndexListStatus - ) + IXLIST_STATUS * pIndexListStatus) { FLMUINT uiThreadId; F_Thread * pThread = NULL; IXLIST_STATUS * pThreadIndexListStatus; FLMBOOL bMutexLocked = FALSE; - // pIndexListStatus->bHaveIndexListStatus should be set to FALSE by the caller. - flmAssert( !pIndexListStatus->bHaveIndexListStatus); // See if the thread is still running. diff --git a/flaim/src/imonlhdr.cpp b/flaim/src/imonlhdr.cpp index b25b859..ec1fd47 100644 --- a/flaim/src/imonlhdr.cpp +++ b/flaim/src/imonlhdr.cpp @@ -94,7 +94,7 @@ RCODE F_LogHeaderPage::display( bFlmLocked = TRUE; // Get the pFile. - pFile = ((FDB_p)hDb)->pFile; + pFile = ((FDB *)hDb)->pFile; } else { @@ -120,7 +120,7 @@ RCODE F_LogHeaderPage::display( f_mutexLock( gv_FlmSysData.hShareMutex); bFlmLocked = TRUE; - pFile = (FFILE_p)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; + pFile = (FFILE *)gv_FlmSysData.pFileHashTbl[uiBucket].pFirstInBucket; while (pFile && (void *)pFile != pvAddress) { pFile = pFile->pNext; diff --git a/flaim/src/imonqury.cpp b/flaim/src/imonqury.cpp index 9ce7725..cea6842 100644 --- a/flaim/src/imonqury.cpp +++ b/flaim/src/imonqury.cpp @@ -34,8 +34,8 @@ #define Q_DOT_COLOR FLM_BLACK FSTATIC FLMBOOL findSubQuery( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery); + CURSOR * pCursor, + SUBQUERY * pSubQuery); /**************************************************************************** Desc: Class for formatting a query into HTML @@ -49,14 +49,14 @@ public: void formatQuery( HRequest * pHRequest, F_WebPage * pWebPage, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bSingleLineOnly, FLMUINT uiMaxChars); void outputSubqueryStats( HRequest * pHRequest, F_WebPage * pWebPage, - SUBQUERY_p pSubQuery); + SUBQUERY * pSubQuery); private: @@ -113,13 +113,13 @@ private: void outputSubQuery( FLMUINT uiIndent, QTYPES eParentOp, - CURSOR_p pReferenceCursor, + CURSOR * pReferenceCursor, SUBQUERY * pSubQuery); void outputQuery( FLMUINT uiIndent, - CURSOR_p pReferenceCursor, - CURSOR_p pCursor); + CURSOR * pReferenceCursor, + CURSOR * pCursor); void outputLabel( const char * pszLabel, @@ -209,12 +209,12 @@ RCODE F_QueriesPage::display( while (pQueryHdr) { char szAddress [20]; - CURSOR_p pCursor; - SUBQUERY_p pSubQuery; + CURSOR * pCursor; + SUBQUERY * pSubQuery; FLMUINT uiRecCount; hCursor = pQueryHdr->hCursor; - pCursor = (CURSOR_p)hCursor; + pCursor = (CURSOR *)hCursor; // Setup a hyperlink for the query. @@ -822,7 +822,7 @@ void F_QueryFormatter::outputText( } ucChar = *pucBuf; - uiObjType = GedTextObjType( ucChar); + uiObjType = flmTextObjType( ucChar); switch (uiObjType) { case ASCII_CHAR_CODE: // 0nnnnnnn @@ -1046,12 +1046,12 @@ Desc: This routine outputs a subquery. void F_QueryFormatter::outputSubQuery( FLMUINT uiIndent, QTYPES eParentOp, - CURSOR_p pReferenceCursor, + CURSOR * pReferenceCursor, SUBQUERY * pSubQuery ) { char * pszURL = NULL; - FQNODE_p pQNode; + FQNODE * pQNode; QTYPES eCurrentOp; QTYPES eTmpParentOp; FLMBOOL bIndentOptInfo = TRUE; @@ -1140,7 +1140,7 @@ void F_QueryFormatter::outputSubQuery( newline(); } uiIndent += 2; - outputQuery( uiIndent, pReferenceCursor, (CURSOR_p)hCursor); + outputQuery( uiIndent, pReferenceCursor, (CURSOR *)hCursor); uiIndent -= 2; if (!m_bSingleLineOnly) { @@ -1255,7 +1255,7 @@ Desc: This routine formats the query criteria for a cursor and optionally void F_QueryFormatter::formatQuery( HRequest * pHRequest, F_WebPage * pWebPage, - CURSOR_p pCursor, + CURSOR * pCursor, FLMBOOL bSingleLineOnly, FLMUINT uiMaxChars ) @@ -1276,8 +1276,8 @@ Desc: This routine formats the query criteria for a cursor and optionally ****************************************************************************/ void F_QueryFormatter::outputQuery( FLMUINT uiIndent, - CURSOR_p pReferenceCursor, - CURSOR_p pCursor + CURSOR * pReferenceCursor, + CURSOR * pCursor ) { SUBQUERY * pSubQuery; @@ -1387,7 +1387,7 @@ RCODE F_QueryPage::display( { // Output query - qf.formatQuery( m_pHRequest, this, (CURSOR_p)hCursor, FALSE, 0); + qf.formatQuery( m_pHRequest, this, (CURSOR *)hCursor, FALSE, 0); } else { @@ -1417,11 +1417,11 @@ Exit: Desc: Find a sub-query within a cursor. ****************************************************************************/ FSTATIC FLMBOOL findSubQuery( - CURSOR_p pCursor, - SUBQUERY_p pSubQuery + CURSOR * pCursor, + SUBQUERY * pSubQuery ) { - SUBQUERY_p pTmpSubQuery; + SUBQUERY * pTmpSubQuery; FLMBOOL bFound = FALSE; HFCURSOR hTmpCursor; FLMUINT uiLoop; @@ -1446,7 +1446,7 @@ FSTATIC FLMBOOL findSubQuery( if ((hTmpCursor = pCursor->QTInfo.ppPredicates [uiLoop]->getCursor()) != HFCURSOR_NULL) { - if (findSubQuery( (CURSOR_p)hTmpCursor, pSubQuery)) + if (findSubQuery( (CURSOR *)hTmpCursor, pSubQuery)) { bFound = TRUE; goto Exit; @@ -1470,7 +1470,7 @@ RCODE F_QueryStatsPage::display( RCODE rc = FERR_OK; QUERY_HDR * pQueryHdr; HFCURSOR hCursor; - SUBQUERY_p pSubQuery; + SUBQUERY * pSubQuery; char szPtr [100]; F_QueryFormatter qf; FLMBOOL bMutexLocked = FALSE; @@ -1493,7 +1493,7 @@ RCODE F_QueryStatsPage::display( { goto Exit; } - pSubQuery = (SUBQUERY_p)f_atoud( szPtr); + pSubQuery = (SUBQUERY *)f_atoud( szPtr); // Lock the mutex on the queries @@ -1513,7 +1513,7 @@ RCODE F_QueryStatsPage::display( // Make sure we can find the sub-query. - if (!findSubQuery( (CURSOR_p)hCursor, pSubQuery)) + if (!findSubQuery( (CURSOR *)hCursor, pSubQuery)) { fnPrintf( m_pHRequest, "
SubQuery is no longer in the query!
\n"); @@ -1723,7 +1723,7 @@ Desc: This routine formats the sub-query statistics. void F_QueryFormatter::outputSubqueryStats( HRequest * pHRequest, F_WebPage * pWebPage, - SUBQUERY_p pSubQuery + SUBQUERY * pSubQuery ) { FLMBYTE * pucFromKey = NULL; diff --git a/flaim/src/imonrche.cpp b/flaim/src/imonrche.cpp index bc9acf6..2d99d1b 100644 --- a/flaim/src/imonrche.cpp +++ b/flaim/src/imonrche.cpp @@ -459,7 +459,7 @@ RCODE F_RCachePage::display( RCACHE * pOlderRCache; RCACHE * pNewerRCache; char szFile[GENERIC_SIZE]; - FFILE_p pFile; + FFILE * pFile; char szFrom[GENERIC_SIZE]; char szBucket[GENERIC_SIZE]; FLMUINT uiBucket; @@ -563,7 +563,7 @@ RCODE F_RCachePage::display( { goto Exit; } - pFile = (FFILE_p)f_atoud( szFile); + pFile = (FFILE *)f_atoud( szFile); // Version tag if (RC_BAD(rc = ExtractParameter( uiNumParams, @@ -799,7 +799,7 @@ void F_RCachePage::write_data( printHTMLLink( "pFile", - "FFILE_p", + "FFILE *", (void *)pRCache, (void *)&pRCache->pFile, (void *)pRCache->pFile, @@ -1064,7 +1064,7 @@ void F_RCachePage::write_data( printHTMLLink( "pNotifyList", - "FNOTIFY_p", + "FNOTIFY *", (void *)pRCache, (void *)&pRCache->pNotifyList, (void *)pRCache->pNotifyList, @@ -1108,7 +1108,7 @@ RCODE F_RecordPage::display( RCACHE * pOlderRCache; RCACHE * pNewerRCache; char szFile[GENERIC_SIZE]; - FFILE_p pFile; + FFILE * pFile; FlmRecord * pRecord = NULL; FLMBOOL bpFileInc = FALSE; FLMBYTE * pszTemp = NULL; @@ -1150,7 +1150,7 @@ RCODE F_RecordPage::display( { goto Exit; } - pFile = (FFILE_p)f_atoud( szFile); + pFile = (FFILE *)f_atoud( szFile); diff --git a/flaim/src/imonsche.cpp b/flaim/src/imonsche.cpp index e06cc6d..c49d3a7 100644 --- a/flaim/src/imonsche.cpp +++ b/flaim/src/imonsche.cpp @@ -47,7 +47,7 @@ RCODE F_SCacheBlockPage::display( FLMUINT uiBlkAddress = 0; FLMUINT uiLowTransID = 0; FLMUINT uiHighTransID = 0; - FFILE_p pFile; + FFILE * pFile; FLMBOOL bHighlight = FALSE; char * pszTemp = NULL; char * pszTemp1 = NULL; @@ -326,7 +326,7 @@ RCODE F_SCacheBlockPage::display( printTableRowStart( bHighlight = ~bHighlight); fnPrintf( m_pHRequest, TD_s "pFile\n" - "FFILE_p\n%s\n", + "FFILE *\n%s\n", szOffsetTable[1], pszFFileRequest, pszFFileRequest, szAddressTable[1]); printTableRowEnd(); @@ -355,7 +355,7 @@ RCODE F_SCacheBlockPage::display( { fnPrintf( m_pHRequest, TD_s - " pNotifyList FNOTIFY_p " + " pNotifyList FNOTIFY * " " %s ", szOffsetTable[3], pszSCacheNotifyListRequest, pszSCacheNotifyListRequest, szAddressTable[2]); @@ -363,7 +363,7 @@ RCODE F_SCacheBlockPage::display( else { fnPrintf( m_pHRequest, - TD_s " pNotifyList FNOTIFY_p " + TD_s " pNotifyList FNOTIFY * " " 0x0 ", szOffsetTable[3]); } printTableRowEnd(); @@ -545,7 +545,7 @@ RCODE F_SCacheDataPage::display( FLMUINT uiBlkAddress = 0; FLMUINT uiLowTransID = 0; FLMUINT uiHighTransID = 0; - FFILE_p pFile = NULL; + FFILE * pFile = NULL; FLMBOOL bFlaimLocked = FALSE; SCACHE LocalSCacheBlock; char * pucData = NULL; @@ -1174,7 +1174,7 @@ RCODE F_SCacheBase::locateSCacheBlock( FLMUINT * puiBlkAddress, FLMUINT * puiLowTransID, FLMUINT * puiHighTransID, - FFILE_p * ppFile) + FFILE * * ppFile) { RCODE rc = FERR_OK; @@ -1220,7 +1220,7 @@ RCODE F_SCacheBase::locateSCacheBlock( { goto Exit; } - *ppFile = (FFILE_p)f_atoud( szFile); + *ppFile = (FFILE *)f_atoud( szFile); flmAssert( *ppFile); uiSigBitsInBlkSize = (*ppFile)->FileHdr.uiSigBitsInBlkSize; diff --git a/flaim/src/imonslmg.cpp b/flaim/src/imonslmg.cpp index 8668ad4..163f83e 100644 --- a/flaim/src/imonslmg.cpp +++ b/flaim/src/imonslmg.cpp @@ -135,7 +135,7 @@ RCODE F_ServerLockMgrPage::display( printAddress( pServerLockMgr->m_pHashTbl, szAddress); printHTMLString( "m_pHashTbl", - "FBUCKET_p", + "FBUCKET *", (void *)pServerLockMgr, (void *)&pServerLockMgr->m_pHashTbl, szAddress, diff --git a/flaim/src/imonstat.cpp b/flaim/src/imonstat.cpp index aab5f94..9e21237 100644 --- a/flaim/src/imonstat.cpp +++ b/flaim/src/imonstat.cpp @@ -976,7 +976,7 @@ Desc: Gets the LOCK_USER information for the specified pFile. ****************************************************************************/ void F_StatsPage::gatherLockStats( STAT_GATHER * pStatGather, - FFILE_p pFile + FFILE * pFile ) { LOCK_USER_HEADER_p pTmp; @@ -1043,7 +1043,7 @@ Desc: Gets the CHECKPOINT_INFO information for the specified pFile. ****************************************************************************/ void F_StatsPage::gatherCPStats( STAT_GATHER * pStatGather, - FFILE_p pFile + FFILE * pFile ) { CP_INFO_HEADER_p pTmp; diff --git a/flaim/src/imonutil.cpp b/flaim/src/imonutil.cpp index 021a06e..9823566 100644 --- a/flaim/src/imonutil.cpp +++ b/flaim/src/imonutil.cpp @@ -3469,7 +3469,7 @@ RCODE F_DatabasePage::display( f_memset( &createOpts, 0, sizeof( CREATE_OPTS)); createOpts.uiBlockSize = DEFAULT_BLKSIZ; - createOpts.uiVersionNum = FLM_CURRENT_VERSION_NUM; + createOpts.uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM; createOpts.uiDefaultLanguage = uiLanguage; // Create the database diff --git a/flaim/src/kyasia1.cpp b/flaim/src/kyasia1.cpp deleted file mode 100644 index b1db25a..0000000 --- a/flaim/src/kyasia1.cpp +++ /dev/null @@ -1,357 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: String collation for Asian languages. -// Tabs: 3 -// -// Copyright (c) 1993-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyasia1.cpp 12312 2006-01-19 15:14:03 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: Convert a text string to a collated string. -****************************************************************************/ -RCODE AsiaFlmTextToColStr( - const FLMBYTE * Str, /* Points to the internal TEXT string */ - FLMUINT StrLen, /* Length of the internal TEXT string */ - FLMBYTE * ColStr, /* Output collated string */ - FLMUINT * ColStrLenRV, /* Collated string length return value */ - /* Input value is MAX num of bytes in buffer*/ - FLMUINT UppercaseFlag, /* Set if to convert to uppercase */ - FLMUINT * puiCollationLen, /* Returns the collation bytes length */ - FLMUINT * puiCaseLen, /* Returns length of case bytes */ - FLMUINT uiCharLimit, /* Max number of characters in this key piece */ - FLMBOOL bFirstSubstring, /* TRUE is this is the first substring key */ - FLMBOOL * pbDataTruncated) -{ - RCODE rc = FERR_OK; - const FLMBYTE * pszStrEnd; /* Points to the end of the String */ - FLMUINT Length; /* Temporary variable for length */ - FLMUINT uiTargetColLen = *ColStrLenRV - 12;/* 6=ovhd,6=worst char*/ - FLMBYTE SubColBuf[ MAX_SUBCOL_BUF+1]; /* Holds Sub-col values (diac) */ - FLMBYTE LowUpBuf[ MAX_LOWUP_BUF+MAX_LOWUP_BUF+2]; /* 2 case bits/wpchar */ - FLMUINT ColLen; /* Return value of collated length */ - FLMUINT SubColBitPos; /* Index into Sub-collation buffer */ - FLMUINT LowUpBitPos; /* Lower upper bit position */ - FLMUINT Flags; /* Clear all bit flags */ - FLMUINT16 NextWpChar; /* next WP character */ - FLMUINT16 UnicodeChar; /* Unicode character */ - FLMUINT16 ColValue; /* Set to zero for the first time */ - FLMBOOL bDataTruncated = FALSE; - - ColLen = SubColBitPos = LowUpBitPos = Flags = 0; - UnicodeChar = ColValue = 0; - - // Don't allow any key component to exceed 256 bytes regardless of the - // user-specified character or byte limit. The goal is to prevent - // any single key piece from consuming too much of the key (which is - // limited to 640 bytes) and thus "starving" other pieces, resulting - // in a key overflow error. - - if( uiTargetColLen > 256) - { - uiTargetColLen = 256; - } - - // Make sure SubColBuf and LowUpBuf are set to 0's - - f_memset( SubColBuf, 0, sizeof( SubColBuf)); - f_memset( LowUpBuf, 0, sizeof( LowUpBuf)); - - pszStrEnd = &Str[ StrLen]; - NextWpChar = 0; - - while( (Str < pszStrEnd) || NextWpChar || UnicodeChar) - { - FLMUINT16 WpChar; /* Current WP character */ - FLMUINT ObjLength; - FLMUINT16 SubColVal; /* Sub-collated value (diacritic) */ - FLMBYTE CaseFlags; - - // Get the next character from the TEXT String. NOTE: OEM characters - // will be returned as character set ZERO, the character will be - // greater than 127. - - WpChar = NextWpChar; - - for( NextWpChar = 0; - (!WpChar || !NextWpChar) && !UnicodeChar && (Str < pszStrEnd); - Str += ObjLength ) /* Inc Str to skip what its pointing at*/ - { - FLMBYTE ObjType; - FLMBYTE CurByte; - FLMUINT16 CurWpChar = 0; - - CurByte = *Str; - ObjType = (FLMBYTE)(GedTextObjType( CurByte)); - ObjLength = 1; - switch( ObjType) - { - case ASCII_CHAR_CODE: /* 0nnnnnnn */ - CurWpChar = (FLMUINT16)CurByte; /* Character set zero is assumed */ - break; - case CHAR_SET_CODE: /* 10nnnnnn */ - ObjLength = 2; - CurWpChar = - (FLMUINT16)(((FLMUINT16)(CurByte & (~CHAR_SET_MASK)) << 8) /* Char set */ - + (FLMUINT16)*(Str + 1)); /* Character */ - break; - case WHITE_SPACE_CODE: /* 110nnnnn */ - CurByte &= (~WHITE_SPACE_MASK); - CurWpChar = ((CurByte == HARD_HYPHEN) || - (CurByte == HARD_HYPHEN_EOL) || - (CurByte == HARD_HYPHEN_EOP) - ) - ? 0x2D /* Minus sign - character set zero*/ - : 0x20; /* Space -- character set zero */ - break; - - /* Skip all of the unknown stuff */ - case UNK_GT_255_CODE: - ObjLength = 1 + sizeof( FLMUINT16) + FB2UW( Str + 1); - break; - case UNK_LE_255_CODE: - ObjLength = 2 + (FLMUINT16)*(Str + 1); - break; - case UNK_EQ_1_CODE: - ObjLength = 2; - break; - case EXT_CHAR_CODE: - ObjLength = 3; - CurWpChar = - (FLMUINT16)(((FLMUINT16)*(Str + 1) << 8) /* Character set */ - + (FLMUINT16)*(Str + 2)); /* Character */ - break; - case OEM_CODE: /* Should never get these */ - ObjLength = 2; - - /* OEM characters are always >= 128. */ - /* We use character set zero to process them. */ - CurWpChar = (FLMUINT16)*(Str + 1); - break; - case UNICODE_CODE: /* Unconvertable UNICODE code */ - ObjLength = 3; - UnicodeChar = (FLMUINT16)(((FLMUINT16)*(Str + 1) << 8) /* Char set */ - + (FLMUINT16)*(Str + 2)); /* Character */ - CurWpChar = 0; - break; - - default: /* should NEVER happen: bug if does */ - continue; - } /* end switch */ - - if( !WpChar) /* Change which needs changing */ - WpChar = CurWpChar; - else - NextWpChar = CurWpChar; - } /* end of FOR statement */ - - - /**----------------------------------------------------------- - *** If we didn't get a character, break out of the outer - *** processing loop. - ***----------------------------------------------------------*/ - - if( !WpChar && !UnicodeChar) - break; /* leave WHILE statement */ - - if( WpChar) - { - if( fwpAsiaGetCollation( WpChar, NextWpChar, ColValue, &ColValue, - &SubColVal, &CaseFlags, (FLMUINT16)UppercaseFlag ) == 2) - { - /* Took the NextWpChar value */ - NextWpChar = 0; /* Force to skip this value */ - } - } - else // use the UnicodeChar value for this pass - { - // This handles all of the UNICODE characters that could not - // be converted to WP characters - which will include most - // of the Asian characters. - - CaseFlags = 0; - if (UnicodeChar < 0x20) - { - ColValue = 0xFFFF; - - // Setting SubColVal to a high code will ensure - // that the code that the UnicodeChar will be stored - // in its full 16 bits in the sub-collation area. - - SubColVal = 0xFFFF; - - // NOTE: UnicodeChar SHOULD NOT be set to zero here. - // It will be set to zero below. - - } - else - { - ColValue = UnicodeChar; - SubColVal = 0; - UnicodeChar = 0; - } - } - - /* Store the values in 2 bytes */ - ColStr[ ColLen++ ] = (FLMBYTE)(ColValue >> 8); - ColStr[ ColLen++ ] = (FLMBYTE)(ColValue & 0xFF); - - if( SubColVal) - { - Flags |= HAD_SUB_COLLATION; - if( SubColVal <= 31) /* 5 bit - store bits 10 */ - { - SET_BIT( SubColBuf, SubColBitPos); - SubColBitPos += 1 + 1; /* Stores a zero */ - SETnBITS( 5, SubColBuf, SubColBitPos, SubColVal); - - SubColBitPos += 5; - } - else /* 2 bytes - store bits 110 or 11110 */ - { - FLMUINT Temp; - - SET_BIT( SubColBuf, SubColBitPos); - SubColBitPos++; - SET_BIT( SubColBuf, SubColBitPos); - SubColBitPos++; - - if( !WpChar && UnicodeChar) /* Store as "11110" */ - { - SubColVal = UnicodeChar; - UnicodeChar = 0; - SET_BIT( SubColBuf, SubColBitPos ); - SubColBitPos++; - SET_BIT( SubColBuf, SubColBitPos ); - SubColBitPos++; - } - SubColBitPos++; /* Skip past the zero */ - - /* Go to the next byte boundary to write the WP char */ - SubColBitPos = (SubColBitPos + 7) & (~7); - Temp = BYTES_IN_BITS( SubColBitPos); - - /* Need to store HIGH-Low - PC format is Low-high! */ - SubColBuf[ Temp ] = (FLMBYTE) (SubColVal >> 8); - SubColBuf[ Temp+1] = (FLMBYTE) (SubColVal); - - SubColBitPos += 16; - } - } - else - SubColBitPos++; - - /* Save case information - always 2 bits worth for asian */ - - if( CaseFlags & 0x02) - { - SET_BIT( LowUpBuf, LowUpBitPos); - } - LowUpBitPos++; - - if( CaseFlags & 0x01) - { - SET_BIT( LowUpBuf, LowUpBitPos); - } - LowUpBitPos++; - - // Check to see if ColLen is within 1 byte of max - - if( (ColLen >= uiCharLimit) || - (ColLen + BYTES_IN_BITS( SubColBitPos) + - BYTES_IN_BITS( LowUpBitPos) >= uiTargetColLen)) - { - // Still something left? - - if ((Str < pszStrEnd) || NextWpChar || UnicodeChar) - { - bDataTruncated = TRUE; - } - - // Hit the max. number of characters - - break; - } - } - - if( puiCollationLen) - { - *puiCollationLen = ColLen; - } - - // Add the first substring marker - also serves as making the string non-null. - if( bFirstSubstring) - { - ColStr[ ColLen++ ] = 0; - ColStr[ ColLen++ ] = COLL_FIRST_SUBSTRING; - } - - if( bDataTruncated) - { - ColStr[ ColLen++ ] = 0; - ColStr[ ColLen++ ] = COLL_TRUNCATED; - } - - if( !ColLen && !SubColBitPos) - { - if( puiCaseLen) - { - *puiCaseLen = 0; - } - goto Exit; - } - - // Done putting the String into 3 sections - build the COLLATED KEY - - if( Flags & HAD_SUB_COLLATION) - { - ColStr[ ColLen++ ] = 0; - ColStr[ ColLen++ ] = COLL_MARKER | SC_SUB_COL; - - // Move the Sub-collation (diacritics) into the collating String - - Length = (FLMUINT)(BYTES_IN_BITS(SubColBitPos)); - f_memcpy( &ColStr[ColLen], SubColBuf, Length); - ColLen += Length; - } - - // Always represent the marker as 2 bytes and case bits in asia - - ColStr[ ColLen++ ] = 0; - ColStr[ ColLen++ ] = COLL_MARKER | SC_MIXED; - - Length = (FLMUINT)(BYTES_IN_BITS( LowUpBitPos )); - f_memcpy( &ColStr[ ColLen ], LowUpBuf, Length); - if( puiCaseLen) - { - *puiCaseLen = (FLMUINT)(Length + 2); - } - ColLen += Length; - -Exit: - - if( pbDataTruncated) - { - *pbDataTruncated = bDataTruncated; - } - - *ColStrLenRV = (FLMUINT)ColLen; - return( rc); -} diff --git a/flaim/src/kyasia2.cpp b/flaim/src/kyasia2.cpp deleted file mode 100644 index 29347f2..0000000 --- a/flaim/src/kyasia2.cpp +++ /dev/null @@ -1,602 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Convert collated string to WP string - for Asian languages. -// Tabs: 3 -// -// Copyright (c) 1993-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyasia2.cpp 12312 2006-01-19 15:14:03 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define SET_CASE_BIT 0x01 -#define SET_KATAKANA_BIT 0x01 -#define SET_WIDTH_BIT 0x02 -#define COLS_ASIAN_MARK_VAL 0x40 /* With out 0x100 */ - - -extern FLMUINT16 colToWPChr[]; /* Converts collated value to WP character */ -extern FLMBYTE ml1_COLtoD[]; /* Diacritic conversions */ -extern FLMBYTE KanaSubColTbl[]; -/* Position in the table+1 is subColValue */ -extern BYTE_WORD_TBL fwp_Ch24ColTbl[]; - -FLMBYTE ColToKanaTbl[ 48 ] /* Only 48 values + 0x40, 0x41, 0x42 (169..171) */ -= { - 0, /* a=0, A=1 */ - 2, /* i=2, I=3 */ - 4, /* u=4, U=5, VU=83 */ - 6, /* e=6, E=7 */ - 8, /* o=8, O=9 */ - 84, /* KA=10, GA=11, ka=84 - remember voicing table is optimized */ - /* so that zero value is position and */ - /* if voice=1 and no 0 is changed to 0 */ - 12, /* KI=12, GI=13 */ - 14, /* KU=14, GU=15 */ - 85, /* KE=16, GE=17, ke=85 */ - 18, /* KO=18, GO=19 */ -/*10*/ - 20, /* SA=20, ZA=21 */ - 22, /* SHI=22, JI=23 */ - 24, /* SU=24, ZU=25 */ - 26, /* SE=26, ZE=27 */ - 28, /* SO=28, ZO=29 */ - 30, /* TA=30, DA=31 */ - 32, /* CHI=32, JI=33 */ - 34, /* tsu=34, TSU=35, ZU=36 */ - 37, /* TE=37, DE=38 */ - 39, /* TO=39, DO=40 */ -/*20*/ - 41, /* NA */ - 42, /* NI */ - 43, /* NU */ - 44, /* NE */ - 45, /* NO */ - 46, /* HA, BA, PA */ - 49, /* HI, BI, PI */ - 52, /* FU, BU, PU */ - 55, /* HE, BE, PE */ - 58, /* HO, BO, PO */ -/*30*/ - 61, /* MA */ - 62, /* MI */ - 63, /* MU */ - 64, /* ME */ - 65, /* MO */ - 66, /* ya, YA */ - 68, /* yu, YU */ - 70, /* yo, YO */ - 72, /* RA */ - 73, /* RI */ -/*40*/ - 74, /* RU */ - 75, /* RE */ - 76, /* RO */ - 77, /* wa, WA */ - 79, /* WI */ - 80, /* WE */ - 81, /* WO */ - 82 /* N */ -}; - -/*************************************************************************** -Desc: Get the original string from an asian collation string -Ret: Length of the word string in bytes -****************************************************************************/ - -FLMUINT AsiaConvertColStr( - FLMBYTE * CollatedStr, /* Points to the Flaim collated string */ - FLMUINT * CollatedStrLenRV, /* Length of the Flaim collated string */ - FLMBYTE * WordStr, /* Output string to build - WP word string */ - FLMBOOL * pbDataTruncated, /* Set to TRUE if data was truncated */ - FLMBOOL * pbFirstSubstring) /* Set to TRUE if marker exists */ -{ - FLMBYTE * pWordStr = WordStr; /* Points to the word string data area */ - FLMUINT Length = *CollatedStrLenRV;/* May optimize as a register */ - FLMUINT CollStrPos = 0; /* Position in CollatedStr[] */ - FLMBOOL bHadExtended = FALSE; - FLMUINT WordStrLen; - FLMUINT16 ColChar; /* 2 byte value for asian */ - - while( Length) - { - FLMBYTE CharVal, CharSet; - CharSet = CollatedStr[ CollStrPos ]; - CharVal = CollatedStr[ CollStrPos + 1 ]; - ColChar = (FLMUINT16)((CharSet << 8) + CharVal); - - if( ColChar <= MAX_COL_OPCODE) - break; - - CollStrPos += 2; - Length -= 2; - if( CharSet == 0) /* Normal Latin/Greek/Cyrillic value */ - { - ColChar = colToWPChr[ CharVal - COLLS ]; - } - else if( CharSet == 1) /* katakana or hiragana character */ - { - if( CharVal > sizeof( ColToKanaTbl )) /* Special cases below */ - { - if( CharVal == COLS_ASIAN_MARK_VAL) /* dakuten */ - ColChar = 0x240a; - else if( CharVal == COLS_ASIAN_MARK_VAL + 1) /* handakuten */ - ColChar = 0x240b; - else if( CharVal == COLS_ASIAN_MARK_VAL + 2) /* chuuten */ - ColChar = 0x2405; - else - ColChar = 0xFFFF; /* error */ - } - else - { - ColChar = (FLMUINT16)(0x2600 + ColToKanaTbl[ CharVal ]); - } - } - else if( CharSet != 0xFF || CharVal != 0xFF) // Asian characters - { - // Insert zeroes that will be treated as a signal for - // uncoverted unicode characters later on. NOTE: Cannot - // use 0xFFFF, because we need to be able to detect this - // case in the sub-collation stuff, and we don't want - // to confuse it with the 0xFFFF that may have been inserted - // in another case. - // THIS IS A REALLY BAD HACK, BUT IT IS THE BEST WE CAN DO - // FOR NOW! - *pWordStr++ = 0; - *pWordStr++ = 0; - bHadExtended = TRUE; - } - /* else does not have a collation value - found in sub-collation part */ - - UW2FBA( ColChar, pWordStr ); /* Put the uncollation value back */ - pWordStr += 2; - } - - UW2FBA( 0, pWordStr); /* NULL Terminate the string */ - WordStrLen = (FLMUINT) (pWordStr - WordStr); - - /**-------------------------------------------------------------------- - *** Parse through the sub-collation and case information. - *** Watch out for COMP CollStrPosT indexes-doesn't have case info after - *** Here are values for some of the codes: - *** [ 0x01] - end for fields case info follows - for COMP POST indexes - *** [ 0x02] - compound marker - *** [ 0x05] - case bits follow - *** [ 0x06] - case information is all uppercase - *** [ 0x07] - beginning of sub-collation information - *** [ 0x08] - first substring field that is made - *** [ 0x09] - truncation marker for text and binary - *** - *** Asian chars the case information should always be there and not - *** compressed out. This is because the case information could change - *** the actual width of the character from 0x26xx to charset 11. - ***-------------------------------------------------------------------*/ - - /** - *** Does truncation marker or sub-collation follow? - **/ - if( Length) - { - ColChar = (FLMUINT16)((CollatedStr[CollStrPos] << 8) + - CollatedStr[CollStrPos+1]); - - // First substring is before truncated. - if( ColChar == COLL_FIRST_SUBSTRING) - { - if( pbFirstSubstring) - *pbFirstSubstring = TRUE; // Don't need to initialize to FALSE. - Length -= 2; - CollStrPos += 2; - ColChar = (FLMUINT16)((CollatedStr[CollStrPos] << 8) + - CollatedStr[CollStrPos+1]); - } - if( ColChar == COLL_TRUNCATED) - { - if( pbDataTruncated) - *pbDataTruncated = TRUE; // Don't need to initialize to FALSE. - Length -= 2; - CollStrPos += 2; - ColChar = (FLMUINT16)((CollatedStr[CollStrPos] << 8) + - CollatedStr[CollStrPos+1]); - } - if( ColChar == (COLL_MARKER | SC_SUB_COL)) - { - FLMUINT TempLen; - - /* Do another pass on the word string adding diacritics/voicings */ - CollStrPos += 2; - Length -= 2; - TempLen = AsiaParseSubCol( WordStr, &WordStrLen, - &CollatedStr[ CollStrPos ]); - CollStrPos += TempLen; - Length -= TempLen; - } - else - goto check_case; - } - - /** - *** Does the case info follow? - It may not because of post indexes - **/ - if( Length) - { - ColChar = (FLMUINT16)((CollatedStr[CollStrPos] << 8) + - CollatedStr[CollStrPos+1]); -check_case: - if( ColChar == (COLL_MARKER | SC_MIXED)) - { - CollStrPos += 2; - CollStrPos += AsiaParseCase( WordStr, &WordStrLen, - &CollatedStr[CollStrPos]); - - // Set bHadExtended to FALSE, because they will have - // been taken care of in this pass. - - bHadExtended = FALSE; - } - } - - // Change embedded zeroes to 0xFFFFs - - if (bHadExtended) - { - FLMUINT uiCnt; - FLMBYTE * pucTmp; - - for (uiCnt = 0, pucTmp = WordStr; - uiCnt < WordStrLen; - uiCnt += 2, pucTmp += 2) - { - if (FB2UW( pucTmp) == 0) - { - UW2FBA( 0xFFFF, pucTmp); - } - } - } - - /* Follow marker is 2 bytes if post otherwise will be 1 byte */ - - /* Should make a pass and count the extended characters */ - - *CollatedStrLenRV = CollStrPos; /* value should be on 0x01 or 0x02 flag */ - return( WordStrLen); /* Return the length of the word string */ -} - -/**************************************************************************** -Desc: Combine the diacritic 5 and 16 bit values to an existing word string. -Ret: FLMUINT - Number of bytes parsed -Notes: For each bit in the sub-collation section: - 0 - no subcollation information - 10 - take next 5 bits - will tell about diacritics or japanese vowel - 110 - align to next byte & take word value as extended character - -****************************************************************************/ - -FLMUINT AsiaParseSubCol( - FLMBYTE * WordStr, /* Existing word string to modify */ - FLMUINT * puiWordStrLen, /* Wordstring length in bytes */ - FLMBYTE * SubColBuf /* Diacritic values in 5 bit sets */ - ) -{ - FLMUINT SubColBitPos = 0; - FLMUINT NumWords = *puiWordStrLen >> 1; - FLMUINT16 Diac; - FLMUINT16 WpChar; - - /* For each word in the word string ... */ - while( NumWords--) - { - - // Have to skip 0, because it is not accounted for - // in the sub-collation bits. It was inserted when we - // encountered unconverted unicode characters (Asian). - // Will be converted to something else later on. - // SEE NOTE ABOVE. - - if (FB2UW( WordStr) == 0) - { - WordStr += 2; - continue; - } - - /* This macro DOESN'T increment bitPos */ - if( TEST1BIT( SubColBuf, SubColBitPos)) - { - /** - *** Bits 10 - take next 5 bits - *** Bits 110 align and take next word - *** Bits 11110 align and take unicode value - **/ - - SubColBitPos++; - if( ! TEST1BIT( SubColBuf, SubColBitPos)) - { - SubColBitPos++; - Diac = (FLMUINT16)(GETnBITS( 5, SubColBuf, SubColBitPos)); - SubColBitPos += 5; - - if( (WpChar = FB2UW( WordStr )) < 0x100) - { - if( (WpChar >= 'A') && (WpChar <= 'Z')) - { - - /* Convert to WP diacritic and combine characters */ - fwpCh6Cmbcar( &WpChar, WpChar, (FLMUINT16) ml1_COLtoD[Diac] ); - /* Even if cmbcar fails, WpChar is still set to a valid value */ - } - else /* Symbols from charset 0x24 */ - { - WpChar = (FLMUINT16)(0x2400 + fwp_Ch24ColTbl[ Diac - 1 ].ByteValue); - } - } - else if( WpChar >= 0x2600) /* Katakana */ - { - /** - *** Voicings - will allow to select original char - *** 000 - some 001 are changed to 000 to save space - *** 001 - set if large char (uppercase) - *** 010 - set if voiced - *** 100 - set if half voiced - *** - *** Should NOT match voicing or wouldn't be here! - **/ - - FLMBYTE CharVal = (FLMBYTE)(WpChar & 0xFF); - - /* Try exceptions first so don't access out of bounds */ - - if( CharVal == 84) - WpChar = (FLMUINT16)(0x2600 + - ((Diac == 1) - ? (FLMUINT16)10 - : (FLMUINT16)11)); - - else if( CharVal == 85) - WpChar = (FLMUINT16)(0x2600 + - ((Diac == 1) - ? (FLMUINT16)16 - : (FLMUINT16)17)); - - /* Try the next 2 slots, if not then value is 83,84 or 85 */ - - else if( KanaSubColTbl[ CharVal + 1 ] == Diac ) - WpChar++; - else if( /* (Diac == 5) && ZU is an exception! */ - (KanaSubColTbl[ CharVal + 2 ] == Diac )) - WpChar += 2; - - /* last exception below */ - - else if( CharVal == 4) - WpChar = 0x2600 + 83; - - /* else leave alone! - invalid storage */ - } - - UW2FBA( WpChar, WordStr ); /* Set if changed or not */ - } - else /* "110" */ - { - FLMUINT Temp; - - SubColBitPos++; /* Skip second '1' */ - - if( TEST1BIT( SubColBuf, SubColBitPos)) /* 11?10 ? */ - { - /* Unconvertable UNICODE character */ - /* The format will be 4 bytes, 0xFF, 0xFF, 2 byte Unicode */ - - shiftN( WordStr, (FLMUINT16)(NumWords + NumWords + 4), 2 ); - WordStr += 2; /* Skip the 0xFFFF for now */ - SubColBitPos += 2; /* Skip next "11" */ - (*puiWordStrLen) += 2; - } - SubColBitPos++; /* Skip the zero */ - - /* Round up to next byte */ - SubColBitPos = (SubColBitPos + 7) & (~7); - Temp = BYTES_IN_BITS( SubColBitPos ); - WordStr[1] = SubColBuf[ Temp ]; /* Character set */ - WordStr[0] = SubColBuf[ Temp + 1 ]; /* Character */ - SubColBitPos += 16; - } - } - else - SubColBitPos++; /* Be sure to increment this! */ - - WordStr += 2; /* Next WP character */ - } - - return( BYTES_IN_BITS( SubColBitPos )); -} - -/**************************************************************************** -Desc: The case bits for asia are: - Latin/Greek/Cyrillic - 01 - case bit set if character is uppercase - 10 - double wide character in CS 0x25xx, 0x26xx and 0x27xx - Japanese - 00 - double wide hiragana 0x255e..25b0 - 01 - double wide katakana 0x2600..2655 - 10 - single wide symbols from charset 11 that map to CS24?? - 11 - single wide katakana from charset 11 -Ret: -Notes: This is tricky to really understand the inputs. - This looks at the bits according to the current character value. -****************************************************************************/ - -FLMUINT AsiaParseCase( - FLMBYTE * WordStr, /* Existing word string to modify */ - FLMUINT * WordStrLenRV, /* Length of the WordString in bytes */ - FLMBYTE * pCaseBits /* Lower/upper case bit string */ - ) -{ - FLMUINT WordStrLen = *WordStrLenRV; - FLMUINT uiWordCnt; - FLMUINT uiExtraBytes = 0; - FLMUINT16 WpChar; - FLMBYTE TempByte = 0; - FLMBYTE MaskByte; - - /* For each character in the word string ... */ - - for( uiWordCnt = WordStrLen >> 1,/* Total number of words in word string */ - MaskByte = 0; /* Force first time to get a byte */ - - uiWordCnt--;) /* Test */ - { - FLMBYTE CharSet, CharVal; - - WpChar = FB2UW( WordStr ); /* Get the next character */ - - // Must skip any 0xFFFFs or zeroes that were inserted. - - if (WpChar == 0xFFFF || WpChar == 0) - { - // Put back 0xFFFF in case it was a zero. - - UW2FBA( 0xFFFF, WordStr); - WordStr += 2; - uiExtraBytes += 2; - continue; - } - if( MaskByte == 0) /* Time to get another byte */ - { - TempByte = *pCaseBits++; - MaskByte = 0x80; - } - CharSet = (FLMBYTE)(WpChar >> 8); - CharVal = (FLMBYTE)(WpChar & 0xFF); - - if( WpChar < 0x2400 ) /*** SINGLE WIDE - NORMAL CHARACTERS ***/ - { - if( TempByte & MaskByte) /* convert to double wide? */ - { - /** - *** Latin/greek/cyrillic - *** Convert to uppercase double wide char - **/ - - if( CharSet == 0) /* Latin - uppercase */ - { - /* May convert to 0x250F (Latin) or CS24 */ - if( WpChar >= 'A' && WpChar <= 'Z') - WpChar = (FLMUINT16)(WpChar - 0x30 + 0x250F); /* Convert to double wide*/ - else - HanToZenkaku( WpChar, 0, &WpChar ); - } - else if( CharSet == 8) /* Greek */ - { - if( CharVal > 38) /* Adjust for spaces in greek */ - CharVal -= 2; - if( CharVal > 4) - CharVal -= 2; - - WpChar = (FLMUINT16)((CharVal >> 1) + 0x265E); - } - else if( CharSet == 10) /* Cyrillic */ - { - WpChar = (FLMUINT16)((CharVal >> 1) + 0x2700); - } - else - HanToZenkaku( WpChar, 0, &WpChar ); - - CharSet = (FLMBYTE)(WpChar >> 8); /* Less code this way */ - CharVal = (FLMBYTE)(WpChar & 0xFF); - } - - MaskByte >>= 1; /* Next bit */ - - if( ( TempByte & MaskByte) == 0) /* Change to lower case? */ - { - switch( CharSet) /* Convert WpChar to lower case */ - { - case 0: - WpChar |= 0x20; /* Bit zero only if lower case */ - break; - case 1: - if( CharVal >= 26) /* in upper/lower case region? */ - WpChar++; - break; - case 8: - if( CharVal <= 69) /* All lowercase after 69 */ - WpChar++; - break; - case 10: - if( CharVal <= 199) /* No cases after 199 */ - WpChar++; - break; - case 0x25: - case 0x26: - /* should be double wide latin or greek */ - WpChar += 0x20; /* Add offset to convert to lowercase */ - break; - case 0x27: /* double wide cyrillic only */ - WpChar += 0x30; /* Add offset to convert to lowercase */ - break; - } - } - } - - else /*** JAPANESE CHARACTERS ***/ - { - if( TempByte & MaskByte) /* Original chars from CharSet 11 */ - { - if( CharSet == 0x26) /* Convert to ZenToHankaku */ - { - FLMUINT16 NextChar = 0; - - WpChar = ZenToHankaku( WpChar, &NextChar ); - - if( NextChar) /* Move everone down */ - { - uiWordCnt++; - shiftN( WordStr, uiWordCnt + uiWordCnt + 2, 2 ); - UW2FBA( WpChar, WordStr ); - WordStr += 2; - WpChar = NextChar; /* Store this below */ - - *WordStrLenRV = *WordStrLenRV + 2; /* Adjust length */ - /* Don't change WordStrLen - returns # bits used */ - } - } - else if( CharSet == 0x24) - { - WpChar = ZenToHankaku( WpChar, (FLMUINT16 *) 0 ); - } - MaskByte >>= 1; /* Eat next bit! */ - } - else - { - MaskByte >>= 1; /* Next bit */ - if( (TempByte & MaskByte) == 0) /* Convert to hiragana? */ - { - /* kanji will also fall through here */ - if( CharSet == 0x26) - WpChar = (FLMUINT16)(0x255E + CharVal); /* Convert to hiragana */ - } - } - } - UW2FBA( WpChar, WordStr ); - WordStr += 2; - MaskByte >>= 1; - } - uiWordCnt = WordStrLen - uiExtraBytes; // Should be 2 bits for each character. - - return( BYTES_IN_BITS( uiWordCnt )); -} diff --git a/flaim/src/kybldkey.cpp b/flaim/src/kybldkey.cpp deleted file mode 100644 index 0976292..0000000 --- a/flaim/src/kybldkey.cpp +++ /dev/null @@ -1,1327 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Build keys for searching in a query. -// Tabs: 3 -// -// Copyright (c) 1996-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kybldkey.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC FLMBOOL flmFindWildcard( - FLMBYTE * pValue, - FLMUINT * puiCharPos); - -FSTATIC RCODE flmAddKeyPiece( - FLMUINT uiMaxKeySize, - IFD * pIfd, - FLMBOOL bDoMatchBegin, - FLMBYTE * pFromKey, - FLMUINT * puiFromKeyPos, - FLMBOOL bFromAtFirst, - FLMBYTE * pUntilKey, - FLMUINT * puiUntilKeyPos, - FLMBOOL bUntilAtEnd, - FLMBYTE * pBuf, - FLMUINT uiBufLen, - FLMBOOL * pbDataTruncated, - FLMBOOL * pbDoneBuilding); - -FSTATIC RCODE flmAddTextPiece( - FLMUINT uiMaxKeySize, - IFD * pIfd, - FLMBOOL bCaseInsensitive, - FLMBOOL bDoMatchBegin, - FLMBOOL bDoFirstSubstring, - FLMBOOL bTrailingWildcard, - FLMBYTE * pFromKey, - FLMUINT * puiFromKeyPos, - FLMBOOL bFromAtFirst, - FLMBYTE * pUntilKey, - FLMUINT * puiUntilKeyPos, - FLMBOOL bUntilAtEnd, - FLMBYTE * pBuf, - FLMUINT uiBufLen, - FLMBOOL * pbDataTruncated, - FLMBOOL * pbDoneBuilding, - FLMBOOL * pbOriginalCharsLost); - -FSTATIC FLMBOOL flmSelectBestSubstr( - FLMBYTE ** ppValue, - FLMUINT * puiValueLen, - FLMUINT uiIfdFlags, - FLMBOOL * pbTrailingWildcard); - -FSTATIC FLMUINT flmCountCharacters( - FLMBYTE * pValue, - FLMUINT uiValueLen, - FLMUINT uiMaxToCount, - FLMUINT uiIfdFlags); - -FSTATIC void flmUintToBCD( - FLMUINT uiValue, - FLMBYTE * pNumberBuf, - FLMUINT * puiValueLen); - -FSTATIC void flmIntToBCD( - FLMINT iValue, - FLMBYTE * pNumberBuf, - FLMUINT * puiValueLen); - -/**************************************************************************** -Desc: Build the from and until keys given a field list with operators and - values and an index. -Notes: The knowledge of query definitions is limited in these routines. -****************************************************************************/ -RCODE flmBuildFromAndUntilKeys( - IXD_p pIxd, - QPREDICATE ** ppQPredicate, // List of field predicates that are parallel - // with the IFD list for the index. - // Same number of elements as the IFD list. - FLMBYTE * pFromKey, // From key to build - FLMUINT * puiFromKeyLen, // return fromKey length - FLMBYTE * pUntilKey, // Until key to build - FLMUINT * puiUntilKeyLen, // return untilKey length. - FLMBOOL * pbDoRecMatch, // [out] Leave alone or set to TRUE. - FLMBOOL * pbDoKeyMatch, // [out] Default = TRUE, Change when needed. - FLMBOOL * pbExclusiveUntilKey) // [out] Leave alone or set to TRUE. -{ - RCODE rc = FERR_OK; - QPREDICATE *pCurPred; - IFD * pIfd = pIxd->pFirstIfd; - FLMUINT uiLanguage = pIxd->uiLanguage; - FLMUINT uiIfdCnt = pIxd->uiNumFlds; - FLMUINT uiFromKeyPos = 0; - FLMUINT uiUntilKeyPos = 0; - FLMBOOL bFromAtFirst; - FLMBOOL bUntilAtEnd; - FLMBOOL bDataTruncated; - FLMBOOL bDoneBuilding; - FLMBOOL bMustNotDoKeyMatch = FALSE; - FLMBOOL bDoKeyMatch = FALSE; - FLMBOOL bOriginalCharsLost; - FLMBOOL bDBCSLanguage = (uiLanguage >= FIRST_DBCS_LANG) && - (uiLanguage <= LAST_DBCS_LANG) ? TRUE : FALSE; - FLMBYTE pNumberBuf[8]; - FLMUINT uiTempLen; - FLMUINT uiMaxKeySize = (pIxd->uiContainerNum) - ? MAX_KEY_SIZ - : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); - - bDataTruncated = bDoneBuilding = FALSE; - *puiFromKeyLen = *puiUntilKeyLen = 0; - uiFromKeyPos = uiUntilKeyPos = 0; - *pbExclusiveUntilKey = TRUE; // Will almost always build an exclusive key. - - for( ; !bDoneBuilding && uiIfdCnt--; ppQPredicate++, pIfd++) - { - // Add the compound marker if not the first piece. - - if( pIfd->uiCompoundPos) - { - IFD * pPrevIfd = (pIfd - 1); - - // Add the compound markers for this key piece. - - if( bDBCSLanguage - && (IFD_GET_FIELD_TYPE( pPrevIfd) == FLM_TEXT_TYPE) - && (!((pPrevIfd)->uiFlags & IFD_CONTEXT))) - { - pFromKey[ uiFromKeyPos++] = 0; - pUntilKey[ uiUntilKeyPos++] = 0; - } - pFromKey [uiFromKeyPos++] = COMPOUND_MARKER; - pUntilKey [uiUntilKeyPos++] = COMPOUND_MARKER; - } - - bFromAtFirst = bUntilAtEnd = FALSE; - pCurPred = *ppQPredicate; - - if( !pCurPred) - { - /* - There is not a predicate that matches this compound key piece. - Done processing, yet may need to look for a predicate - that will force a doKeyMatch or a doRecMatch. - */ - - if( RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, - pIfd, FALSE, pFromKey, &uiFromKeyPos, TRUE, - pUntilKey, &uiUntilKeyPos, TRUE, NULL, 0, - &bDataTruncated, &bDoneBuilding))) - { - goto Exit; - } - continue; - } - - // Handle special cases for indexing context and/or exists predicate. - - else if( pIfd->uiFlags & IFD_CONTEXT) - { - // Indexed only the TAG. Simple to set the tag as the key. - - if( RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, - pFromKey, &uiFromKeyPos, FALSE, - pUntilKey, &uiUntilKeyPos, FALSE, NULL, 0, - &bDataTruncated, &bDoneBuilding))) - { - goto Exit; - } - - // If we don't have an exists predicate we need to read the record. - if( pCurPred->eOperator != FLM_EXISTS_OP) - { - bMustNotDoKeyMatch = TRUE; - } - continue; - } - else - { - FLMBOOL bMatchedBadOperator = FALSE; - switch( pCurPred->eOperator) - { - case FLM_EXISTS_OP: - case FLM_NE_OP: - bMatchedBadOperator = TRUE; - bUntilAtEnd = TRUE; - bFromAtFirst = TRUE; - break; - default: - if( pCurPred->bNotted) - { - bMatchedBadOperator = TRUE; - bUntilAtEnd = TRUE; - bFromAtFirst = TRUE; - } - break; - } - - if( bMatchedBadOperator) - { - // Does exist is a FIRST to LAST for this piece. - - if( RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, - pFromKey, &uiFromKeyPos, bFromAtFirst, - pUntilKey, &uiUntilKeyPos, bUntilAtEnd, NULL, 0, - &bDataTruncated, &bDoneBuilding))) - { - goto Exit; - } - continue; - } - } - - switch( IFD_GET_FIELD_TYPE( pIfd)) - { - /* - Build TEXT type piece - */ - case FLM_TEXT_TYPE: - { - FLMBOOL bCaseInsensitive = (FLMBOOL) - ((pCurPred->pVal->uiFlags & FLM_NOCASE) ? TRUE : FALSE); - FLMBOOL bDoFirstSubstring = (FLMBOOL) - ((pIfd->uiFlags & IFD_SUBSTRING) ? TRUE : FALSE); - - // True bDoMatchBegin generates high values in UNTIL key. - FLMBOOL bDoMatchBegin; - FLMBOOL bDoSubstringSearch; - FLMBOOL bTrailingWildcard; // If trailing spaces remain - FLMBYTE * pValue = (FLMBYTE *) pCurPred->pVal->val.pucBuf; - FLMUINT uiValueLen = pCurPred->pVal->uiBufLen; - - bDoMatchBegin = bDoSubstringSearch = bTrailingWildcard = FALSE; - switch( pCurPred->eOperator) - { - // The difference between MATCH and EQ_OP is that EQ does - // not support wildcards inbedded in the search key. - - case FLM_MATCH_OP: - case FLM_MATCH_BEGIN_OP: - - if( pCurPred->eOperator == FLM_MATCH_BEGIN_OP) - { - bDoKeyMatch = bDoMatchBegin = TRUE; - } - if( pCurPred->pVal->uiFlags & FLM_WILD) - { - if( !bDoFirstSubstring) - { - FLMBOOL bFoundWildcard = - flmFindWildcard( pValue, &uiValueLen); - - bDoKeyMatch = TRUE; - - if( pCurPred->eOperator == FLM_MATCH_OP) - { - bTrailingWildcard = bDoMatchBegin = bFoundWildcard; - } - else - { - bTrailingWildcard = bDoMatchBegin = TRUE; - } - } - else - { - // If this is a substring index look for a - // better 'contains' string to search for. - // We don't like "A*BCDEFG" searches. - - bTrailingWildcard = - (pCurPred->eOperator == FLM_MATCH_BEGIN_OP) - ? TRUE - : FALSE; - - if( flmSelectBestSubstr( &pValue, &uiValueLen, - pIfd->uiFlags, &bTrailingWildcard)) - { - bDoMatchBegin = bTrailingWildcard; - bMustNotDoKeyMatch = TRUE; - bDoFirstSubstring = FALSE; - } - else if( bTrailingWildcard) - { - bDoKeyMatch = bDoMatchBegin = TRUE; - } - } - } - break; - - case FLM_CONTAINS_OP: - case FLM_MATCH_END_OP: - - // Normal text index this piece goes from first to last. - if( !bDoFirstSubstring) //!(pIfd->uiFlags & IFD_SUBSTRING)) - { - bFromAtFirst = TRUE; - bUntilAtEnd = TRUE; - } - else - { - bDoFirstSubstring = TRUE; - bDoSubstringSearch = TRUE; - - // SPACE/Hyphen rules on SUBSTRING index. - // If the search string starts with " _asdf" then we must do - // a record match so "Z asdf" matches and "Zasdf" doesn't. - // We won't touch key match even though it MAY return - // FLM_TRUE when in fact the key may or may not match. - // VISIT: MatchBegin and Contains could also optimize the - // trailing space by adding the space ONLY to the UNTIL key. - - if( uiValueLen && - ( (*pValue == ASCII_SPACE - && (pIfd->uiFlags & IFD_MIN_SPACES)) - || (*pValue == ASCII_UNDERSCORE - && (pIfd->uiFlags & IFD_NO_UNDERSCORE)))) - { - *pbDoRecMatch = TRUE; - } - - // Take the flags from the pVal and NOT from the predicate. - if( pCurPred->pVal->uiFlags & FLM_WILD) - { - /* - Select the best substring. The case of - "A*BCD*E*FGHIJKLMNOP" will look for "FGHIJKLMNOP". - and TURN OFF doKeyMatch and SET doRecMatch. - */ - - bTrailingWildcard = - (pCurPred->eOperator == FLM_CONTAINS_OP) - ? TRUE - : FALSE; - - if( flmSelectBestSubstr( &pValue, &uiValueLen, - pIfd->uiFlags, &bTrailingWildcard)) - { - bDoMatchBegin = bTrailingWildcard; - bMustNotDoKeyMatch = TRUE; - bDoFirstSubstring = FALSE; - } - if( bTrailingWildcard) - { - bDoKeyMatch = bDoMatchBegin = TRUE; - } - } - if( bDoFirstSubstring) - { - // Setting bDoMatchBegin creates a UNTIL key - // with trailing 0xFF values. - if( pCurPred->eOperator == FLM_CONTAINS_OP) - { - bDoKeyMatch = TRUE; // Because of subcollation values - bDoMatchBegin = TRUE;// Sets high values in UNTIL key. - } - } - - // Special case: Single character contains/MEnd in a substr ix. - if( !bDBCSLanguage && flmCountCharacters( pValue, uiValueLen, - 2, pIfd->uiFlags) < 2) - { - bDoKeyMatch = bFromAtFirst = bUntilAtEnd = TRUE; - } - } - break; - - // No wild card support for the operators below. - case FLM_EQ_OP: - break; - case FLM_GE_OP: - case FLM_GT_OP: - bUntilAtEnd = TRUE; - break; - case FLM_LE_OP: - bFromAtFirst = TRUE; - break; - case FLM_LT_OP: - bFromAtFirst = TRUE; - *pbExclusiveUntilKey = TRUE; - break; - default: - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - // If index is case insensitive, but search is case sensitive - // we must NOT do a key match - we would fail things we should - // not be failing. - - if ((pIfd->uiFlags & IFD_UPPER) && !bCaseInsensitive) - { - bMustNotDoKeyMatch = TRUE; - } - if( RC_BAD( rc = flmAddTextPiece( uiMaxKeySize, - pIfd, bCaseInsensitive, bDoMatchBegin, - bDoFirstSubstring, bTrailingWildcard, - pFromKey, &uiFromKeyPos, bFromAtFirst, - pUntilKey, &uiUntilKeyPos, bUntilAtEnd, - pValue, uiValueLen, - /*pbExclusiveUntilKey, */ - &bDataTruncated, &bDoneBuilding, &bOriginalCharsLost))) - { - goto Exit; - } - if (bOriginalCharsLost) - { - bMustNotDoKeyMatch = TRUE; - } - break; - } - // Build NUMBER or CONTEXT type piece - // VISIT: Add a true number type so we don't have to build a NODE. - - case FLM_NUMBER_TYPE: - case FLM_CONTEXT_TYPE: - switch( pCurPred->pVal->eType) - { - case FLM_INT32_VAL: - { - FLMINT iValue = pCurPred->pVal->val.iVal; - if( pCurPred->eOperator == FLM_GT_OP) - { - iValue++; - } - if( IFD_GET_FIELD_TYPE( pIfd) == FLM_NUMBER_TYPE) - { - flmIntToBCD( iValue, pNumberBuf, &uiTempLen); - } - else - { - UD2FBA( iValue, pNumberBuf); - uiTempLen = 4; - } - break; - } - case FLM_UINT32_VAL: - case FLM_REC_PTR_VAL: - { - FLMUINT uiValue = pCurPred->pVal->val.uiVal; - if( pCurPred->eOperator == FLM_GT_OP) - { - uiValue++; - } - if( IFD_GET_FIELD_TYPE( pIfd) == FLM_NUMBER_TYPE) - { - flmUintToBCD( uiValue, pNumberBuf, &uiTempLen); - } - else - { - UD2FBA( uiValue, pNumberBuf); - uiTempLen = 4; - } - break; - } - default: - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - switch( pCurPred->eOperator) - { - case FLM_EQ_OP: - break; - case FLM_GE_OP: - case FLM_GT_OP: - bUntilAtEnd = TRUE; - break; - case FLM_LE_OP: - bFromAtFirst = TRUE; - break; - case FLM_LT_OP: - bFromAtFirst = TRUE; - *pbExclusiveUntilKey = TRUE; - break; - default: - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - - if( RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, FALSE, - pFromKey, &uiFromKeyPos, bFromAtFirst, - pUntilKey, &uiUntilKeyPos, bUntilAtEnd, - (FLMBYTE *) pNumberBuf, uiTempLen, - &bDataTruncated, &bDoneBuilding))) - { - goto Exit; - } - - break; - - /* - Build BINARY type piece - */ - - case FLM_BINARY_TYPE: - { - FLMBOOL bMatchBegin = FALSE; - - switch( pCurPred->eOperator) - { - case FLM_MATCH_BEGIN_OP: - bMatchBegin = TRUE; - break; - case FLM_EQ_OP: - break; - case FLM_GE_OP: - bUntilAtEnd = TRUE; - break; - case FLM_GT_OP: - bUntilAtEnd = TRUE; - bDoKeyMatch = TRUE; - break; - case FLM_LE_OP: - bFromAtFirst = TRUE; - break; - case FLM_LT_OP: - bFromAtFirst = TRUE; - *pbExclusiveUntilKey = TRUE; - break; - default: - rc = RC_SET( FERR_CURSOR_SYNTAX); - goto Exit; - } - if( RC_BAD( rc = flmAddKeyPiece( uiMaxKeySize, pIfd, bMatchBegin, - pFromKey, &uiFromKeyPos, bFromAtFirst, - pUntilKey, &uiUntilKeyPos, bUntilAtEnd, - pCurPred->pVal->val.pucBuf, pCurPred->pVal->uiBufLen, - &bDataTruncated, &bDoneBuilding))) - { - goto Exit; - } - - break; - } - - default: - flmAssert(0); // Unsupported - break; - } - if( bDataTruncated) - { - bMustNotDoKeyMatch = TRUE; - } - } - - // Really rare case where FROM/UNTIL keys are exactly the same. - if( !bDoneBuilding && (uiIfdCnt + 1 == 0) && - uiUntilKeyPos < uiMaxKeySize - 2) - { - // Always make the until key exclusive. - // *pbExclusiveUntilKey = FALSE; - pUntilKey[ uiUntilKeyPos++ ] = 0xFF; - pUntilKey[ uiUntilKeyPos++ ] = 0xFF; - } - - -Exit: - if( bMustNotDoKeyMatch) - { - *pbDoKeyMatch = FALSE; - *pbDoRecMatch = TRUE; - } - else if( bDoKeyMatch || !pIxd->uiContainerNum) - { - *pbDoKeyMatch = TRUE; - } - // Special case for building FIRST/LAST keys. - if( !uiFromKeyPos) - { - *pFromKey = '\0'; - uiFromKeyPos = 1; - } - if( !uiUntilKeyPos) - { - f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); - uiUntilKeyPos = uiMaxKeySize - 2; - } - *puiFromKeyLen = uiFromKeyPos; - *puiUntilKeyLen = uiUntilKeyPos; - return( rc); -} - -/**************************************************************************** -Desc: Truncate the length of the text buffer on the first wild card. -****************************************************************************/ -FSTATIC FLMBOOL flmFindWildcard( - FLMBYTE * pVal, - FLMUINT * puiCharPos) // [in/out] always returns charPos of * or length -{ - FLMBOOL bHaveChar = FALSE; - FLMBYTE * pSaveVal = pVal; - FLMUINT uiObjLength; - FLMUINT uiLen = *puiCharPos; - - for( ; - *pVal; - pVal += uiObjLength, uiLen = (uiObjLength < uiLen) ? uiLen - uiObjLength : 0) - { - switch( (FLMUINT)(GedTextObjType( *pVal))) - { - case ASCII_CHAR_CODE: // 0nnnnnnn - if( *pVal == ASCII_WILDCARD) - { - bHaveChar = TRUE; - goto Exit; - } - uiObjLength = 1; - - // Check for '*' or '\\' after an escape character. - if( *pVal == ASCII_BACKSLASH && - (*(pVal + 1) == ASCII_WILDCARD - || *(pVal + 1) == ASCII_BACKSLASH)) - { - uiObjLength++; - } - break; - - case WHITE_SPACE_CODE: // 110nnnnn - uiObjLength = 1; - break; - case CHAR_SET_CODE: // 10nnnnnn - case UNK_EQ_1_CODE: - case OEM_CODE: - uiObjLength = 2; - break; - case UNICODE_CODE: // Unconvertable UNICODE code - case EXT_CHAR_CODE: - uiObjLength = 3; - break; - case UNK_GT_255_CODE: - uiObjLength = 1 + sizeof( FLMUINT16) + FB2UW( pVal + 1); - break; - case UNK_LE_255_CODE: - uiObjLength = 2 + (FLMUINT16)*(pVal + 1); - break; - default: // should NEVER happen: bug if does - uiObjLength = 1; - break; // Should not really return an error - } - } -Exit: - *puiCharPos = (FLMUINT)(pVal - pSaveVal); - return bHaveChar; -} - -/**************************************************************************** -Desc: Add a key piece to the from and until key. Text fields are not - handled in this routine because of their complexity. -Notes: The goal of this code is to build a the collated compound piece - for the 'from' and 'until' key only once instead of twice. -****************************************************************************/ -FSTATIC RCODE flmAddKeyPiece( - FLMUINT uiMaxKeySize, - IFD * pIfd, - FLMBOOL bDoMatchBegin, - FLMBYTE * pFromKey, - FLMUINT * puiFromKeyPos, - FLMBOOL bFromAtFirst, - FLMBYTE * pUntilKey, - FLMUINT * puiUntilKeyPos, - FLMBOOL bUntilAtEnd, - FLMBYTE * pBuf, - FLMUINT uiBufLen, - FLMBOOL * pbDataTruncated, - FLMBOOL * pbDoneBuilding) -{ - RCODE rc = FERR_OK; - FLMUINT uiFromKeyPos = *puiFromKeyPos; - FLMUINT uiUntilKeyPos = *puiUntilKeyPos; - FLMBYTE * pDestKey; - FLMUINT uiDestKeyLen; - - if( pIfd->uiCompoundPos == 0 && bFromAtFirst && bUntilAtEnd) - { - // Special case for the first piece - FIRST to LAST - zero length keys. - // so that the caller can get the number of references for the entire index. - // VISIT: May want to set the from key to have 1 byte and set high values - // for the until key. This way the caller never checks this special case. - - *pbDoneBuilding = TRUE; - goto Exit; - } - - // Handle the CONTEXT exception here - this is not done in kyCollate. - - if( pIfd->uiFlags & IFD_CONTEXT) - { - pFromKey [uiFromKeyPos] = KY_CONTEXT_PREFIX; - flmUINT16ToBigEndian( (FLMUINT16) pIfd->uiFldNum, &pFromKey [uiFromKeyPos + 1]); - uiFromKeyPos += KY_CONTEXT_LEN; - - if( uiUntilKeyPos + KY_CONTEXT_LEN < uiMaxKeySize) - { - pUntilKey [uiUntilKeyPos] = KY_CONTEXT_PREFIX; - flmUINT16ToBigEndian( (FLMUINT16) pIfd->uiFldNum, &pUntilKey [uiUntilKeyPos + 1]); - uiUntilKeyPos += KY_CONTEXT_LEN; - } - goto Exit; - } - - if( bFromAtFirst) - { - if( bUntilAtEnd) - { - // Not the first piece and need to go from first to last. - *pbDoneBuilding = TRUE; - - if( uiUntilKeyPos < uiMaxKeySize - 2) - { - if( uiUntilKeyPos > 0) - { - // Instead of filling the key with 0xFF, increment the marker. - pUntilKey [uiUntilKeyPos - 1]++; - } - else - { - f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); - uiUntilKeyPos = uiMaxKeySize - 2; - } - } - goto Exit; - } - - if( uiUntilKeyPos >= uiMaxKeySize - 2) - { - goto Exit; - } - // Have a LAST key but no FROM key. - pDestKey = pUntilKey + uiUntilKeyPos; - uiDestKeyLen = uiMaxKeySize - uiUntilKeyPos; - } - else - { - pDestKey = pFromKey + uiFromKeyPos; - uiDestKeyLen = uiMaxKeySize - uiFromKeyPos; - } - - rc = KYCollateValue( pDestKey, &uiDestKeyLen, - (FLMBYTE *)pBuf, uiBufLen, - pIfd->uiFlags, pIfd->uiLimit, NULL, NULL, - 0, TRUE, FALSE, FALSE, pbDataTruncated); - - if( rc == FERR_CONV_DEST_OVERFLOW) - { - rc = FERR_OK; - } - else if( RC_BAD( rc)) - { - goto Exit; - } - - // If we just built the FROM key, we may want to copy to the UNTIL key. - if( pDestKey == pFromKey + uiFromKeyPos) - { - uiFromKeyPos += uiDestKeyLen; - - // Unless the UNTIL key is full, the length is at or less than FROM key. - if( !bUntilAtEnd) - { - if( uiUntilKeyPos + uiDestKeyLen <= uiMaxKeySize) - { - f_memcpy( &pUntilKey[ uiUntilKeyPos], pDestKey, uiDestKeyLen); - uiUntilKeyPos += uiDestKeyLen; - } - - if( bDoMatchBegin) - { - flmAssert( IFD_GET_FIELD_TYPE( pIfd) == FLM_BINARY_TYPE); - - if( uiUntilKeyPos < MAX_KEY_SIZ - 2) - { - // Optimization - only need to set a single byte to 0xFF. - // We can do this because this routine does not deal with text key - // pieces and binary, number and context will never have 0xFF bytes. - - pUntilKey[ uiUntilKeyPos++] = 0xFF; - } - - // We don't need to set *pbDoneBuilding = TRUE, because we may - // be able to continue building the from key - } - } - else - { - if( uiUntilKeyPos > 0) - { - // Instead of filling the key with 0xFF, increment the marker. - pUntilKey [uiUntilKeyPos - 1]++; - } - else - { - // Optimization - only need to set a single byte to 0xFF. - // We can do this because this routine does not deal with text key - // pieces and binary, number and context will never have 0xFF bytes. - - flmAssert( IFD_GET_FIELD_TYPE( pIfd) != FLM_TEXT_TYPE); - - *pUntilKey = 0xFF; - uiUntilKeyPos++; - } - } - } - else - { - uiUntilKeyPos += uiDestKeyLen; - } - -Exit: - // Set the FROM and UNTIL key length return values. - *puiFromKeyPos = uiFromKeyPos; - *puiUntilKeyPos = uiUntilKeyPos; - return( rc); -} - -/**************************************************************************** -Desc: Add a text piece to the from and until key. Some of the code is - the same with AddKeyPiece above. -Notes: The goal of this code is to build a the collated compound piece - for the 'from' and 'until' key only once instead of twice. -****************************************************************************/ -FSTATIC RCODE flmAddTextPiece( - FLMUINT uiMaxKeySize, - IFD * pIfd, - FLMBOOL bCaseInsensitive, - FLMBOOL bDoMatchBegin, - FLMBOOL bDoFirstSubstring, - FLMBOOL bTrailingWildcard, - FLMBYTE * pFromKey, - FLMUINT * puiFromKeyPos, - FLMBOOL bFromAtFirst, - FLMBYTE * pUntilKey, - FLMUINT * puiUntilKeyPos, - FLMBOOL bUntilAtEnd, - FLMBYTE * pBuf, - FLMUINT uiBufLen, - FLMBOOL * pbDataTruncated, - FLMBOOL * pbDoneBuilding, - FLMBOOL * pbOriginalCharsLost - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiFromKeyPos = *puiFromKeyPos; - FLMUINT uiUntilKeyPos = *puiUntilKeyPos; - FLMUINT uiLanguage = pIfd->pIxd->uiLanguage; - FLMBYTE * pDestKey; - FLMUINT uiDestKeyLen; - FLMUINT uiCollationLen = 0; - FLMUINT uiCaseLen; - FLMBOOL bIsDBCS = (uiLanguage >= FIRST_DBCS_LANG && - uiLanguage <= LAST_DBCS_LANG) - ? TRUE - : FALSE; - - *pbOriginalCharsLost = FALSE; - if( pIfd->uiCompoundPos == 0 && bFromAtFirst && bUntilAtEnd) - { - // Special case for the first piece - FIRST to LAST - zero length keys. - // so that the caller can get the number of references for the entire index. - // VISIT: May want to set the from key to have 1 byte and set high values - // for the until key. This way the caller never checks this special case. - - *pbDoneBuilding = TRUE; - goto Exit; - } - if( bFromAtFirst) - { - if( bUntilAtEnd) - { - // Not the first piece and need to go from first to last. - *pbDoneBuilding = TRUE; - - if( uiUntilKeyPos < uiMaxKeySize - 2) - { - // Instead of filling the key with 0xFF, increment the marker. - pUntilKey [uiUntilKeyPos - 1]++; - } - goto Exit; - } - if( uiUntilKeyPos >= uiMaxKeySize - 2) - { - goto Exit; - } - // Have a LAST key but no FROM key. - pDestKey = pUntilKey + uiUntilKeyPos; - uiDestKeyLen = uiMaxKeySize - uiUntilKeyPos; - } - else // Handle below if UNTIL key is LAST. - { - pDestKey = pFromKey + uiFromKeyPos; - uiDestKeyLen = uiMaxKeySize - uiFromKeyPos; - } - // Add IFD_ESC_CHAR to the ifd flags because - // the search string must have BACKSLASHES and '*' escaped. - - rc = KYCollateValue( pDestKey, &uiDestKeyLen, - (FLMBYTE *)pBuf, uiBufLen, - pIfd->uiFlags | IFD_ESC_CHAR, pIfd->uiLimit, - &uiCollationLen, &uiCaseLen, - uiLanguage, TRUE, bDoFirstSubstring, - bTrailingWildcard, pbDataTruncated, - pbOriginalCharsLost); - if( rc == FERR_CONV_DEST_OVERFLOW) - rc = FERR_OK; - else if( RC_BAD( rc)) - goto Exit; - - if( pIfd->uiFlags & IFD_POST) - { - uiDestKeyLen -= uiCaseLen; - } - else - { - // Special case: The index is NOT an upper index and the search is - // case-insensitive. - // The FROM key must have lower case values and the UNTIL must be the - // upper case values. This will be true for Asian indexes also. - - if (uiDestKeyLen && - (bIsDBCS || - (!(pIfd->uiFlags & IFD_UPPER) && bCaseInsensitive))) - { - - // Subtract off all but the case marker. - // Remember that for DBCS (Asian) the case marker is two bytes. - - uiDestKeyLen -= (uiCaseLen - - ((FLMUINT)(bIsDBCS - ? (FLMUINT)2 - : (FLMUINT)1))); - - // NOTE: SC_LOWER is only used in GREEK indexes, which is why - // we use it here instead of SC_MIXED. - - pDestKey[ uiDestKeyLen - 1] = (FLMBYTE) - (( uiLanguage != (FLMUINT) GR_LANG) ? - COLL_MARKER | SC_MIXED : COLL_MARKER | SC_LOWER); - // Once the FROM key has been approximated, we are done building. - *pbDoneBuilding = TRUE; - } - } - - // Copy or move pieces of the FROM key into the UNTIL key. - - if( pDestKey == pFromKey + uiFromKeyPos) - { - if( uiUntilKeyPos < uiMaxKeySize - 2) - { - if (!bUntilAtEnd) - { - if( bDoMatchBegin) - { - if (uiCollationLen) - { - f_memcpy( &pUntilKey[ uiUntilKeyPos], pDestKey, uiCollationLen); - uiUntilKeyPos += uiCollationLen; - } - - // Fill the rest of the key with high values. - f_memset( &pUntilKey[ uiUntilKeyPos], 0xFF, (uiMaxKeySize - 2) - uiUntilKeyPos); - uiUntilKeyPos = uiMaxKeySize - 2; - // Don't need to set the done building flag to TRUE. - } - else if (uiDestKeyLen) - { - if( !bDoFirstSubstring) - { - f_memcpy( &pUntilKey[ uiUntilKeyPos], pDestKey, uiDestKeyLen); - uiUntilKeyPos += uiDestKeyLen; - } - else - { - // Do two copies so that the first substring byte is gone. - f_memcpy( &pUntilKey[ uiUntilKeyPos], pDestKey, uiCollationLen); - uiUntilKeyPos += uiCollationLen; - if( bIsDBCS) - uiCollationLen++; - uiCollationLen++; - f_memcpy( &pUntilKey[ uiUntilKeyPos], pDestKey + uiCollationLen, - uiDestKeyLen - uiCollationLen); - uiUntilKeyPos += (uiDestKeyLen - uiCollationLen); - } - - // Special case again : raw case in index and search comparison. - // Case has already been completely removed if it is a post index, - // so no need to change the marker byte. - - if (!(pIfd->uiFlags & IFD_POST) && - (bIsDBCS || - (!(pIfd->uiFlags & IFD_UPPER) && bCaseInsensitive))) - { - // Add 1 to make sure the until key is higher than the upper value. - pUntilKey[ uiUntilKeyPos - 1] = (COLL_MARKER | SC_UPPER) + 1; - } - } - } - else - { - if( uiUntilKeyPos > 0) - { - // Instead of filling the key with 0xFF, increment the marker. - pUntilKey [uiUntilKeyPos - 1]++; - } - else - { - // Keys can have 0xFF values in them, so it is not sufficient to - // set only uiDestKeyLen bytes to 0xFF. We must set the entire - // key. - - f_memset( pUntilKey, 0xFF, uiMaxKeySize - 2); - uiUntilKeyPos = uiMaxKeySize - 2; - } - } - } - uiFromKeyPos += uiDestKeyLen; - } - else - { - // We just built the UNTIL key. The FROM key doesn't need to be built. - uiUntilKeyPos += uiDestKeyLen; - } - -Exit: - // Set the FROM and UNTIL keys - *puiFromKeyPos = uiFromKeyPos; - *puiUntilKeyPos = uiUntilKeyPos; - return( rc); -} - -/**************************************************************************** -Desc: Select the best substring for a CONTAINS or MATCH_END search. - Look below for the algorithm. -****************************************************************************/ -FSTATIC FLMBOOL flmSelectBestSubstr( // Returns TRUE if NOT using first of key - FLMBYTE ** ppValue, // [in/out] - FLMUINT * puiValueLen, // [in/out] - FLMUINT uiIfdFlags, - FLMBOOL * pbTrailingWildcard) // [in] change if found a wildcard -{ - FLMBYTE * pValue = *ppValue; - FLMBYTE * pCurValue; - FLMBYTE * pBest; - FLMBOOL bBestTerminatesWithWildCard = *pbTrailingWildcard; - FLMUINT uiCurLen; - FLMUINT uiBestNumChars; - FLMUINT uiBestValueLen; - FLMUINT uiWildcardPos = 0; - FLMUINT uiTargetNumChars; - FLMUINT uiNumChars; - FLMBOOL bNotUsingFirstOfString = FALSE; - -#define GOOD_ENOUGH_CHARS 16 - - // There may not be any wildcards at all. Find the first one. - if( flmFindWildcard( pValue, &uiWildcardPos)) - { - - bBestTerminatesWithWildCard = TRUE; - pBest = pValue; - pCurValue = pValue + uiWildcardPos + 1; - uiCurLen = *puiValueLen - (uiWildcardPos + 1); - - uiBestValueLen = uiWildcardPos; - uiBestNumChars = flmCountCharacters( pValue, uiWildcardPos, - GOOD_ENOUGH_CHARS, uiIfdFlags); - uiTargetNumChars = uiBestNumChars + uiBestNumChars; - - /* - Here is the great FindADoubleLengthThatIsBetter algorithm. - Below are the values to pick a next better contains key. - First Key Size Next Key Size that will be used - 1 * 2 2 // Single char searches are REALLY BAD - 2 * 2 4 - 3 * 2 6 - 4 * 2 8 - ... ... - At each new key piece, increment the target length by 2 so that it - will be even harder to find a better key. - */ - while( uiBestNumChars < GOOD_ENOUGH_CHARS && *pCurValue) - { - if( flmFindWildcard( pCurValue, &uiWildcardPos)) - { - uiNumChars = flmCountCharacters( pCurValue, uiWildcardPos, - GOOD_ENOUGH_CHARS, uiIfdFlags); - if( uiNumChars >= uiTargetNumChars) - { - pBest = pCurValue; - uiBestValueLen = uiWildcardPos; - uiBestNumChars = uiNumChars; - uiTargetNumChars = uiNumChars + uiNumChars; - } - else - { - uiTargetNumChars += 2; - } - pCurValue = pCurValue + uiWildcardPos + 1; - uiCurLen -= uiWildcardPos + 1; - } - else - { - // Check the last section that may or may not have trailing *. - uiNumChars = flmCountCharacters( pCurValue, uiCurLen, - GOOD_ENOUGH_CHARS, uiIfdFlags); - if( uiNumChars >= uiTargetNumChars) - { - pBest = pCurValue; - uiBestValueLen = uiCurLen; - bBestTerminatesWithWildCard = *pbTrailingWildcard; - } - break; - } - } - if( pBest != *ppValue) - { - bNotUsingFirstOfString = TRUE; - } - *ppValue = pBest; - *puiValueLen = uiBestValueLen; - *pbTrailingWildcard = bBestTerminatesWithWildCard; - } - -//Exit: - return bNotUsingFirstOfString; -} - -/**************************************************************************** -Desc: Returns true if this text will generate a single characater key. -****************************************************************************/ -FSTATIC FLMUINT flmCountCharacters( // Returns number of characters in key - FLMBYTE * pValue, - FLMUINT uiValueLen, - FLMUINT uiMaxToCount, - FLMUINT uiIfdFlags) -{ - - FLMUINT uiNumChars = 0; - FLMUINT uiObjLength; - - for( uiObjLength = 0; - uiNumChars <= uiMaxToCount && uiValueLen; - pValue += uiObjLength, - uiValueLen = (uiValueLen >= uiObjLength) ? uiValueLen - uiObjLength : 0) - { - switch( (FLMUINT)(GedTextObjType( *pValue))) - { - case ASCII_CHAR_CODE: // 0nnnnnnn - uiObjLength = 1; - if( *pValue == ASCII_SPACE) - { - // Ignore if using space rules. - // VISIT: Need to address ending spaces before a wildcard. - if( uiIfdFlags & (IFD_MIN_SPACES | IFD_NO_SPACE)) - break; - uiNumChars++; - } - else if( *pValue == ASCII_UNDERSCORE) - { - // Ignore if using the underscore space rules. - // VISIT: Need to address ending spaces before a wildcard. - if( uiIfdFlags & IFD_NO_UNDERSCORE) - break; - uiNumChars++; - } - else if( *pValue == ASCII_DASH) - { - if( uiIfdFlags & IFD_NO_DASH) - break; - uiNumChars++; - } - else if( *pValue == ASCII_BACKSLASH && - (*(pValue + 1) == ASCII_WILDCARD - || *(pValue + 1) == ASCII_BACKSLASH)) - { - uiObjLength++; - uiNumChars++; - } - else - { - uiNumChars++; - } - break; - - case WHITE_SPACE_CODE: // 110nnnnn - uiObjLength = 1; - uiNumChars++; - break; - case CHAR_SET_CODE: // 10nnnnnn - case UNK_EQ_1_CODE: - case OEM_CODE: - uiObjLength = 2; - uiNumChars++; - break; - case UNICODE_CODE: // Unconvertable UNICODE code - case EXT_CHAR_CODE: - uiObjLength = 3; - uiNumChars++; - break; - case UNK_GT_255_CODE: - uiObjLength = 1 + sizeof( FLMUINT16) + FB2UW( pValue + 1); - break; - case UNK_LE_255_CODE: - uiObjLength = 2 + (FLMUINT16)*(pValue + 1); - break; - default: // should NEVER happen: bug if does - uiObjLength = 1; - break; // Should not really return an error - } - } - return uiNumChars; -} -/**************************************************************************** -Desc: Cheating routine to blast out an internal number without using - the pool to allocate space. -****************************************************************************/ -FSTATIC void flmUintToBCD( - FLMUINT uiNum, - FLMBYTE * pNumberBuf, - FLMUINT * puiValueLen) -{ - - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - - /* push spare (undefined) nibble for possible half-used terminating byte */ - - pucNibStk = &ucNibStk[ 1]; - - /* push terminator nibble -- popped last */ - - *pucNibStk++ = 0x0F; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10); /* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - *puiValueLen = (pucNibStk - ucNibStk) >> 1; - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pNumberBuf++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - return; -} - -/**************************************************************************** -Desc: Cheating routine to blast out an internal number without using - the pool to allocate space. - Code taken from gnbcd.cpp. -****************************************************************************/ -FSTATIC void flmIntToBCD( - FLMINT iNum, - FLMBYTE * pNumberBuf, - FLMUINT * puiValueLen) -{ - FLMUINT uiNum; - FLMBYTE ucNibStk[ F_MAX_NUM_BUF + 1]; /* spare byte for odd BCD counts */ - FLMBYTE * pucNibStk; - FLMINT iNegFlag; - - // Initialize byte 0. It doesn't really matter that we do this, but it - // keeps purify quiet - we don't end up accessing unitialized memory. - - ucNibStk [0] = 0; - - // push spare (undefined) nibble for possible half-used terminating byte - // push terminator nibble -- popped last - - ucNibStk [1] = 0x0F; - pucNibStk = &ucNibStk[ 2]; - - /* separate sign from magnituted; (FLMUINT)un = +/- n & flag */ - - uiNum = ((iNegFlag = iNum < 0) != 0) ? -iNum : iNum; - - /* push digits */ - /* do 32 bit division until we get down to 16 bits */ - - while( uiNum >= 10) - { - *pucNibStk++ = (FLMBYTE)(uiNum % 10);/* push BCD nibbles in reverse order */ - uiNum /= 10; - } - *pucNibStk++ = (FLMBYTE)uiNum; /* push last nibble of number */ - - if( iNegFlag) - { - *pucNibStk++ = 0x0B; /* push sign nibble last */ - } - - *puiValueLen = (pucNibStk - ucNibStk) >> 1; - - /* Pop stack and pack nibbles into byte stream a pair at a time */ - - do - { - *pNumberBuf++ = (FLMBYTE)((pucNibStk[ -1] << 4) | pucNibStk[ -2]); - } - while( (pucNibStk -= 2) > &ucNibStk[ 1]); /* spare stack byte stops seg wrap */ - - return; -} diff --git a/flaim/src/kybuild.cpp b/flaim/src/kybuild.cpp index e495c25..834a413 100644 --- a/flaim/src/kybuild.cpp +++ b/flaim/src/kybuild.cpp @@ -24,91 +24,130 @@ #include "flaimsys.h" +#define KREF_TBL_SIZE 512 +#define KREF_TBL_THRESHOLD 400 +#define KREF_POOL_BLOCK_SIZE 8192 +#define KREF_TOTAL_BYTES_THRESHOLD ((KREF_POOL_BLOCK_SIZE * 3) - 250) + +#define KY_SWAP(pKrefTbl, leftP, rightP) \ + pTempKref = pKrefTbl[leftP]; \ + pKrefTbl[leftP] = pKrefTbl[rightP]; \ + pKrefTbl[rightP] = pTempKref + +FSTATIC FLMINT _KrefCompare( + FLMUINT * puiQsortFlags, + KREF_ENTRY * pKreftA, + KREF_ENTRY * pKreftB); + +FSTATIC RCODE KYAddUniqueKeys( + FDB * pDb); + +FSTATIC RCODE _KrefQuickSort( + FLMUINT * puiQsortFlags, + KREF_ENTRY ** pEntryTbl, + FLMUINT uiLowerBounds, + FLMUINT uiUpperBounds); + +FSTATIC RCODE _KrefKillDups( + FLMUINT * puiQsortFlags, + KREF_ENTRY ** pKrefTbl, + FLMUINT * puiKrefTotalRV); + FSTATIC RCODE flmProcessIndexedFld( - FDB * pDb, - IXD_p pUseIxd, - IFD * pIfdChain, - void ** ppPathFlds, - FLMUINT uiLeafFieldLevel, - FLMUINT uiAction, - FLMUINT uiContainerNum, - FLMUINT uiDrn, - FLMBOOL * pbHadUniqueKeys, - FlmRecord * pRecord, - void * pvField); + FDB * pDb, + IXD * pUseIxd, + IFD * pIfdChain, + void ** ppPathFlds, + FLMUINT uiLeafFieldLevel, + FLMUINT uiAction, + FLMUINT uiContainerNum, + FLMUINT uiDrn, + FLMBOOL * pbHadUniqueKeys, + FlmRecord * pRecord, + void * pvField); /**************************************************************************** -Desc: Main driver for processing the fields in a record. +Desc: Main driver for processing the fields in a record. ****************************************************************************/ RCODE flmProcessRecFlds( - FDB * pDb, /* Operation context. */ - IXD_p pIxd, - FLMUINT uiContainerNum, /* Database container number. */ - FLMUINT uiDrn, /* Record Drn */ - FlmRecord * pRecord, /* Record to build keys for */ - FLMUINT uiAction, /* Either DEL or ADD */ - FLMBOOL bPurgedFldsOk, - FLMBOOL * pbHadUniqueKeys) + FDB * pDb, + IXD * pIxd, + FLMUINT uiContainerNum, + FLMUINT uiDrn, + FlmRecord * pRecord, + FLMUINT uiAction, + FLMBOOL bPurgedFldsOk, + FLMBOOL * pbHadUniqueKeys) { - RCODE rc = FERR_OK; - void * pathFlds[ GED_MAXLVLNUM + 1]; - FLMUINT uiLeafFieldLevel; - void * pvField; + RCODE rc = FERR_OK; + void * pathFlds[GED_MAXLVLNUM + 1]; + FLMUINT uiLeafFieldLevel; + void * pvField; - /* Process each field in the record. */ - pvField = pRecord->root(); - for(;;) + if ((pvField = pRecord->root()) == NULL) { - FLMUINT uiItemType; - IFD * pIfdChain; - FLMUINT uiTagNum = pRecord->getFieldID( pvField); - FLMUINT uiFldState; - FLMBOOL bFldEncrypted; - FLMUINT uiEncFlags = 0; - FLMUINT uiEncId = 0; - FLMUINT uiEncState; + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } - if( RC_BAD( rc = fdictGetField( pDb->pDict, uiTagNum, &uiItemType, - &pIfdChain, &uiFldState))) + for (;;) + { + FLMUINT uiItemType; + IFD* pIfdChain; + FLMUINT uiTagNum = pRecord->getFieldID( pvField); + FLMUINT uiFldState; + FLMBOOL bFldEncrypted; + FLMUINT uiEncFlags = 0; + FLMUINT uiEncId = 0; + FLMUINT uiEncState; + + if (RC_BAD( rc = fdictGetField( pDb->pDict, uiTagNum, &uiItemType, + &pIfdChain, &uiFldState))) { + // Fill diagnostic error data. - pDb->Diag.uiInfoFlags |= - (FLM_DIAG_FIELD_NUM | FLM_DIAG_FIELD_TYPE); + + pDb->Diag.uiInfoFlags |= (FLM_DIAG_FIELD_NUM | FLM_DIAG_FIELD_TYPE); pDb->Diag.uiFieldNum = uiTagNum; - pDb->Diag.uiFieldType = (FLMUINT)pRecord->getDataType( pvField); + pDb->Diag.uiFieldType = (FLMUINT) pRecord->getDataType( pvField); goto Exit; } - + // Check for encryption. + bFldEncrypted = pRecord->isEncryptedField( pvField); if (bFldEncrypted) { + // May still proceed if the field is already encrypted. + uiEncFlags = pRecord->getEncFlags( pvField); - + if (!(uiEncFlags & FLD_HAVE_ENCRYPTED_DATA) && !pDb->pFile->bInLimitedMode) { - uiEncId = pRecord->getEncryptionID( pvField); - - if (RC_BAD( rc = fdictGetEncInfo( pDb, - uiEncId, - NULL, - &uiEncState))) + uiEncId = pRecord->getEncryptionID( pvField); + + if (RC_BAD( rc = fdictGetEncInfo( pDb, uiEncId, NULL, &uiEncState))) { + // Fill diagnostic error data. - pDb->Diag.uiInfoFlags |= - (FLM_DIAG_FIELD_NUM | FLM_DIAG_ENC_ID); + + pDb->Diag.uiInfoFlags |= (FLM_DIAG_FIELD_NUM | FLM_DIAG_ENC_ID); pDb->Diag.uiFieldNum = uiTagNum; pDb->Diag.uiEncId = uiEncId; goto Exit; } - + // Check the state of the Encryption Record. + if (uiEncState == ITT_ENC_STATE_PURGE) { - // EncDef record has been marked as 'purged'. So, user is not - // allowed to add new fields that are encrypted with this EncDef Id. + + // EncDef record has been marked as 'purged'. So, user is + // not allowed to add new fields that are encrypted with + // this EncDef Id. + pDb->Diag.uiInfoFlags |= (FLM_DIAG_FIELD_NUM | FLM_DIAG_ENC_ID); pDb->Diag.uiFieldNum = uiTagNum; pDb->Diag.uiEncId = uiEncId; @@ -122,42 +161,44 @@ RCODE flmProcessRecFlds( rc = RC_SET( FERR_ENCRYPTION_UNAVAILABLE); goto Exit; } - } - uiLeafFieldLevel = (FLMINT)pRecord->getLevel( pvField); - pathFlds[ uiLeafFieldLevel] = pvField; + uiLeafFieldLevel = (FLMINT) pRecord->getLevel( pvField); + pathFlds[uiLeafFieldLevel] = pvField; - /* Check the field state */ - if( uiFldState == ITT_FLD_STATE_PURGE && bPurgedFldsOk == FALSE) + // Check the field state + + if (uiFldState == ITT_FLD_STATE_PURGE && bPurgedFldsOk == FALSE) { pDb->Diag.uiInfoFlags |= FLM_DIAG_FIELD_NUM; pDb->Diag.uiFieldNum = uiTagNum; rc = RC_SET( FERR_PURGED_FLD_FOUND); goto Exit; } - else if( (uiFldState == ITT_FLD_STATE_CHECKING - || uiFldState == ITT_FLD_STATE_UNUSED) - && ! (uiAction & KREF_DEL_KEYS) - /* Don't change states while reindexing, because the FDB maynot be in a good state. */ - && ! (uiAction & KREF_INDEXING_ONLY)) - { /* Because a occurance of this field was found update the field's - state to be 'active' */ - if( RC_BAD( rc = flmChangeItemState( pDb, uiTagNum, ITT_FLD_STATE_ACTIVE))) + else if ((uiFldState == ITT_FLD_STATE_CHECKING || + uiFldState == ITT_FLD_STATE_UNUSED) && + !(uiAction & KREF_DEL_KEYS) && !(uiAction & KREF_INDEXING_ONLY)) + { + // Because a occurance of this field was found update the field's + // state to be 'active' + + if (RC_BAD( rc = flmChangeItemState( pDb, uiTagNum, + ITT_FLD_STATE_ACTIVE))) { goto Exit; } - // If this is an encrypted field, see if we need to update the state of - // the EncDef record too. + // If this is an encrypted field, see if we need to update the + // state of the EncDef record too. + if (bFldEncrypted) { - if (( uiEncState == ITT_ENC_STATE_CHECKING || - uiEncState == ITT_ENC_STATE_UNUSED) && - !(uiAction & KREF_DEL_KEYS) && - !(uiAction & KREF_INDEXING_ONLY)) + if ((uiEncState == ITT_ENC_STATE_CHECKING || + uiEncState == ITT_ENC_STATE_UNUSED) && + !(uiAction & KREF_DEL_KEYS) && !(uiAction & KREF_INDEXING_ONLY)) { - if( RC_BAD( rc = flmChangeItemState( pDb, uiEncId, ITT_ENC_STATE_ACTIVE))) + if (RC_BAD( rc = flmChangeItemState( pDb, uiEncId, + ITT_ENC_STATE_ACTIVE))) { goto Exit; } @@ -165,40 +206,38 @@ RCODE flmProcessRecFlds( } } - if( uiItemType != pRecord->getDataType( pvField) && - uiTagNum < FLM_DICT_FIELD_NUMS) + if (uiItemType != pRecord->getDataType( pvField) && + uiTagNum < FLM_DICT_FIELD_NUMS) { rc = RC_SET( FERR_BAD_FIELD_TYPE); - pDb->Diag.uiInfoFlags |= - (FLM_DIAG_FIELD_NUM | FLM_DIAG_FIELD_TYPE); + pDb->Diag.uiInfoFlags |= (FLM_DIAG_FIELD_NUM | FLM_DIAG_FIELD_TYPE); pDb->Diag.uiFieldNum = uiTagNum; - pDb->Diag.uiFieldType = (FLMUINT)pRecord->getDataType( pvField); + pDb->Diag.uiFieldType = (FLMUINT) pRecord->getDataType( pvField); goto Exit; } - if( pRecord->getDataType( pvField) == FLM_BLOB_TYPE && - (!(uiAction & KREF_INDEXING_ONLY))) + if (pRecord->getDataType( pvField) == FLM_BLOB_TYPE && + (!(uiAction & KREF_INDEXING_ONLY))) { - if( RC_BAD( rc = flmBlobPlaceInTransactionList( - pDb, ((uiAction & KREF_DEL_KEYS) - ? BLOB_DELETE_ACTION : BLOB_ADD_ACTION), - pRecord, pvField))) - { - goto Exit; - } - } - - if( pIfdChain) - { - if (RC_BAD( rc = flmProcessIndexedFld( pDb, pIxd, pIfdChain, pathFlds, - uiLeafFieldLevel, uiAction, uiContainerNum, uiDrn, pbHadUniqueKeys, + if (RC_BAD( rc = flmBlobPlaceInTransactionList( pDb, + ((uiAction & KREF_DEL_KEYS) ? BLOB_DELETE_ACTION : BLOB_ADD_ACTION), pRecord, pvField))) { goto Exit; } } - - if( (pvField = pRecord->next( pvField)) == NULL) + + if (pIfdChain) + { + if (RC_BAD( rc = flmProcessIndexedFld( pDb, pIxd, pIfdChain, pathFlds, + uiLeafFieldLevel, uiAction, uiContainerNum, uiDrn, + pbHadUniqueKeys, pRecord, pvField))) + { + goto Exit; + } + } + + if ((pvField = pRecord->next( pvField)) == NULL) { break; } @@ -208,56 +247,53 @@ Exit: // Build and add the compound keys to the KREF table - if( RC_OK( rc)) + if (RC_OK( rc)) { - rc = KYBuildCmpKeys( pDb, uiAction, uiContainerNum, - uiDrn, pbHadUniqueKeys, pRecord); + rc = KYBuildCmpKeys( pDb, uiAction, uiContainerNum, uiDrn, + pbHadUniqueKeys, pRecord); } - - return( rc); + + return (rc); } - -/*************************************************************************** -Desc: See if a field's path matches the path in the IFD. -*****************************************************************************/ +/**************************************************************************** +Desc: See if a field's path matches the path in the IFD. +****************************************************************************/ FLMBOOL flmCheckIfdPath( - IFD * pIfd, - FlmRecord * pRecord, - void ** ppPathFlds, - FLMUINT uiLeafFieldLevel, - void * pvLeafField, - void ** ppvContextField // Return's context field of field in record - // i.e., the first field in the IFD. Only - // returned if the context matches. - ) + IFD * pIfd, + FlmRecord * pRecord, + void ** ppPathFlds, + FLMUINT uiLeafFieldLevel, + void * pvLeafField, + void ** ppvContextField) { - FLMBOOL bMatched = FALSE; - void * pvContextField; - FLMINT iParentPos; - FLMUINT * puiIfdFldPathCToP; + FLMBOOL bMatched = FALSE; + void * pvContextField; + FLMINT iParentPos; + FLMUINT * puiIfdFldPathCToP; // Check the field path to see if field is in context. pvContextField = pvLeafField; - puiIfdFldPathCToP = &pIfd->pFieldPathCToP [1]; - iParentPos = (FLMINT)uiLeafFieldLevel - 1; + puiIfdFldPathCToP = &pIfd->pFieldPathCToP[1]; + iParentPos = (FLMINT) uiLeafFieldLevel - 1; + while (*puiIfdFldPathCToP && iParentPos >= 0) { - pvContextField = ppPathFlds [iParentPos]; + pvContextField = ppPathFlds[iParentPos]; // Check for FLM_ANY_FIELD (wild_tag) and skip it. if (*puiIfdFldPathCToP == FLM_ANY_FIELD) { - // Look at next field in IFD path to see if it matches - // the current field. If it does, continue from there. + // Look at next field in IFD path to see if it matches the + // current field. If it does, continue from there. if (*(puiIfdFldPathCToP + 1)) { - if (pRecord->getFieldID( pvContextField) == - *(puiIfdFldPathCToP + 1)) + if (pRecord->getFieldID( pvContextField) == + *(puiIfdFldPathCToP + 1)) { // Skip wild card and field that matched. @@ -265,34 +301,32 @@ FLMBOOL flmCheckIfdPath( puiIfdFldPathCToP += 2; } - // Go to next field in path being evaluated no matter - // what. If it didn't match, we continue looking at - // the wild card. If it did match, we go to the next - // field in the path. + // Go to next field in path being evaluated no matter what. + // If it didn't match, we continue looking at the wild card. + // If it did match, we go to the next field in the path. iParentPos--; } else { - // Rest of path is an automatic match - had wildcard - // at top of IFD path. - - // It's not really necessary to increment this, but - // it is more efficient because of the comparisons - // that are done when we exit this loop. - + // Rest of path is an automatic match - had wildcard at top + // of IFD path. + // + // It's not really necessary to increment this, but it is more + // efficient because of the comparisons that are done when we + // exit this loop. + puiIfdFldPathCToP++; - pvContextField = ppPathFlds [0]; + pvContextField = ppPathFlds[0]; break; } } else if (pRecord->getFieldID( pvContextField) != *puiIfdFldPathCToP) { - // Field does not match current field in IFD. - // This jump to Exit will return FALSE. bMatched is FALSE at - // this point. + // Field does not match current field in IFD. This jump to Exit + // will return FALSE. bMatched is FALSE at this point. goto Exit; } @@ -306,53 +340,53 @@ FLMBOOL flmCheckIfdPath( } } - // If we got to the end of the field path in the IFD, we have a - // match. + // If we got to the end of the field path in the IFD, we have a match. if (!(*puiIfdFldPathCToP) || - (*puiIfdFldPathCToP == FLM_ANY_FIELD && - !(*(puiIfdFldPathCToP + 1)))) + (*puiIfdFldPathCToP == FLM_ANY_FIELD && !(*(puiIfdFldPathCToP + 1)))) { *ppvContextField = pvContextField; bMatched = TRUE; } + Exit: - return( bMatched); + + return (bMatched); } /**************************************************************************** -Desc: Processes a field in a record - indexing, blob, etc. +Desc: Processes a field in a record - indexing, blob, etc. ****************************************************************************/ FSTATIC RCODE flmProcessIndexedFld( - FDB * pDb, - IXD_p pUseIxd, - IFD * pIfdChain, - void ** ppPathFlds, - FLMUINT uiLeafFieldLevel, - FLMUINT uiAction, - FLMUINT uiContainerNum, - FLMUINT uiDrn, - FLMBOOL * pbHadUniqueKeys, - FlmRecord * pRecord, - void * pvField) + FDB * pDb, + IXD * pUseIxd, + IFD * pIfdChain, + void ** ppPathFlds, + FLMUINT uiLeafFieldLevel, + FLMUINT uiAction, + FLMUINT uiContainerNum, + FLMUINT uiDrn, + FLMBOOL * pbHadUniqueKeys, + FlmRecord * pRecord, + void * pvField) { RCODE rc = FERR_OK; - IFD_p pIfd; - IXD_p pIxd; + IFD * pIfd; + IXD * pIxd; void * pRootContext; const FLMBYTE * pValue; const FLMBYTE * pExportValue; FLMUINT uiValueLen; FLMUINT uiKeyLen; - FLMBYTE pTmpKeyBuf[ MAX_KEY_SIZ ]; + FLMBYTE pTmpKeyBuf[MAX_KEY_SIZ]; pTmpKeyBuf[0] = '\0'; - for ( pIfd = pIfdChain; pIfd; pIfd = pIfd->pNextInChain) + for (pIfd = pIfdChain; pIfd; pIfd = pIfd->pNextInChain) { - if( pUseIxd) + if (pUseIxd) { - if( pUseIxd->uiIndexNum == pIfd->uiIndexNum) + if (pUseIxd->uiIndexNum == pIfd->uiIndexNum) { pIxd = pUseIxd; } @@ -364,7 +398,7 @@ FSTATIC RCODE flmProcessIndexedFld( else { pIxd = pIfd->pIxd; - + // If index is offline or on a different container, skip it. // NOTE: if pIxd->uiContainerNum is zero, the index is indexing // ALL containers. @@ -376,13 +410,15 @@ FSTATIC RCODE flmProcessIndexedFld( continue; } - if( pIxd->uiFlags & IXD_OFFLINE) + if (pIxd->uiFlags & IXD_OFFLINE) { - if( uiDrn > pIxd->uiLastDrnIndexed) + if (uiDrn > pIxd->uiLastDrnIndexed) { continue; } + // Else index the key. + } } else @@ -390,15 +426,17 @@ FSTATIC RCODE flmProcessIndexedFld( // uiContainerNum == 0, indexing all containers - if( pIxd->uiFlags & IXD_OFFLINE) + if (pIxd->uiFlags & IXD_OFFLINE) { - if( uiContainerNum > pIxd->uiLastContainerIndexed || + if (uiContainerNum > pIxd->uiLastContainerIndexed || uiContainerNum == pIxd->uiLastContainerIndexed && uiDrn > pIxd->uiLastDrnIndexed) { continue; } + // Else index the key. + } } } @@ -406,35 +444,40 @@ FSTATIC RCODE flmProcessIndexedFld( // See if field path matches what is defined in the IFD. if (!flmCheckIfdPath( pIfd, pRecord, ppPathFlds, uiLeafFieldLevel, - pvField, &pRootContext)) + pvField, &pRootContext)) { + // Skip this field. + continue; } - // Field passed the path verification. Now output the KEY. + // Field passed the path verification. Now output the KEY. - if( pIfd->uiFlags & IFD_COMPOUND) + if (pIfd->uiFlags & IFD_COMPOUND) { - /* Compound Key. */ - if (RC_BAD( rc = KYCmpKeyAdd2Lst( pDb, pIxd, pIfd, - pvField, pRootContext))) + // Compound Key. + + if (RC_BAD( rc = KYCmpKeyAdd2Lst( pDb, pIxd, pIfd, pvField, + pRootContext))) + { goto Exit; + } } else if (pIfd->uiFlags & IFD_CONTEXT) { - FLMBYTE KeyBuf [4]; + FLMBYTE KeyBuf[4]; - /* Context key (tag number). */ + // Context key (tag number). - KeyBuf [0] = KY_CONTEXT_PREFIX; - flmUINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pvField ), &KeyBuf [1]); + KeyBuf[0] = KY_CONTEXT_PREFIX; + flmUINT16ToBigEndian( (FLMUINT16) pRecord->getFieldID( + pvField), &KeyBuf[1]); - if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, - pbHadUniqueKeys, KeyBuf, KY_CONTEXT_LEN, - TRUE, FALSE, FALSE))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, pIfd, + uiAction, uiDrn, pbHadUniqueKeys, KeyBuf, KY_CONTEXT_LEN, + TRUE, FALSE, FALSE))) { goto Exit; } @@ -442,18 +485,20 @@ FSTATIC RCODE flmProcessIndexedFld( else if ((pIfd->uiFlags & IFD_SUBSTRING) && (pRecord->getDataType( pvField) == FLM_TEXT_TYPE)) { - FLMBOOL bFirstSubstring = TRUE; - FLMUINT uiLanguage = pIxd->uiLanguage; - - // An encrypted field, in limited mode means we use the encrypted data instead. + FLMBOOL bFirstSubstring = TRUE; + FLMUINT uiLanguage = pIxd->uiLanguage; + + // An encrypted field, in limited mode means we use the + // encrypted data instead. + if (pRecord->isEncryptedField( pvField) && pDb->pFile->bInLimitedMode) { pValue = pRecord->getEncryptionDataPtr( pvField); uiValueLen = pRecord->getEncryptedDataLength( pvField); - if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - pValue, uiValueLen, FALSE, bFirstSubstring, TRUE))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, pIfd, + uiAction, uiDrn, pbHadUniqueKeys, pValue, uiValueLen, + FALSE, bFirstSubstring, TRUE))) { goto Exit; } @@ -463,30 +508,30 @@ FSTATIC RCODE flmProcessIndexedFld( pExportValue = pValue = pRecord->getDataPtr( pvField); uiValueLen = pRecord->getDataLength( pvField); - /* Loop for each word in the text field adding it to the table. */ + // Loop for each word in the text field adding it to the + // table. - while (KYSubstringParse( &pValue, &uiValueLen, - pIfd->uiFlags, pIfd->uiLimit, - (FLMBYTE *) pTmpKeyBuf, &uiKeyLen) == TRUE) + while (KYSubstringParse( &pValue, &uiValueLen, pIfd->uiFlags, + pIfd->uiLimit, (FLMBYTE*) pTmpKeyBuf, &uiKeyLen) == TRUE) { - if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - (FLMBYTE *) pTmpKeyBuf, uiKeyLen, FALSE, - bFirstSubstring, FALSE))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, + pIfd, uiAction, uiDrn, pbHadUniqueKeys, + (FLMBYTE *) pTmpKeyBuf, uiKeyLen, FALSE, + bFirstSubstring, FALSE))) { break; } - - if( (uiValueLen == 1 && - !(uiLanguage >= FIRST_DBCS_LANG && - uiLanguage <= LAST_DBCS_LANG))) + + if ((uiValueLen == 1 && + !(uiLanguage >= FIRST_DBCS_LANG && + uiLanguage <= LAST_DBCS_LANG))) { break; } - + bFirstSubstring = FALSE; } - + if (RC_BAD( rc)) { goto Exit; @@ -496,15 +541,18 @@ FSTATIC RCODE flmProcessIndexedFld( else if ((pIfd->uiFlags & IFD_EACHWORD) && (pRecord->getDataType( pvField) == FLM_TEXT_TYPE)) { - // An encrypted field, in limited mode means we use the encrypted data instead. + + // An encrypted field, in limited mode means we use the + // encrypted data instead. + if (pRecord->isEncryptedField( pvField) && pDb->pFile->bInLimitedMode) { pValue = pRecord->getEncryptionDataPtr( pvField); uiValueLen = pRecord->getEncryptedDataLength( pvField); - if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - pValue, uiValueLen, FALSE, FALSE, TRUE))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, pIfd, + uiAction, uiDrn, pbHadUniqueKeys, pValue, uiValueLen, + FALSE, FALSE, TRUE))) { goto Exit; } @@ -514,21 +562,20 @@ FSTATIC RCODE flmProcessIndexedFld( pExportValue = pValue = pRecord->getDataPtr( pvField); uiValueLen = pRecord->getDataLength( pvField); - /* Loop for each word in the text field adding it to the table. */ + // Loop for each word in the text field adding it to the + // table. - while (KYEachWordParse( &pValue, &uiValueLen, - pIfd->uiLimit, - (FLMBYTE *) pTmpKeyBuf, &uiKeyLen) == TRUE) + while (KYEachWordParse( &pValue, &uiValueLen, pIfd->uiLimit, + (FLMBYTE *) pTmpKeyBuf, &uiKeyLen) == TRUE) { - if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - (FLMBYTE *) pTmpKeyBuf, uiKeyLen, FALSE, FALSE, - FALSE))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, + pIfd, uiAction, uiDrn, pbHadUniqueKeys, + (FLMBYTE*) pTmpKeyBuf, uiKeyLen, FALSE, FALSE, FALSE))) { break; } } - + if (RC_BAD( rc)) { goto Exit; @@ -537,10 +584,14 @@ FSTATIC RCODE flmProcessIndexedFld( } else { - /* Index field content - entire field. */ - FLMBOOL bEncryptedKey = FALSE; - - // An encrypted field, in limited mode means we use the encrypted data instead. + + // Index field content - entire field. + + FLMBOOL bEncryptedKey = FALSE; + + // An encrypted field, in limited mode means we use the + // encrypted data instead. + if (pRecord->isEncryptedField( pvField) && pDb->pFile->bInLimitedMode) { pExportValue = pValue = pRecord->getEncryptionDataPtr( pvField); @@ -553,10 +604,9 @@ FSTATIC RCODE flmProcessIndexedFld( uiValueLen = pRecord->getDataLength( pvField); } - if( RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - pExportValue, uiValueLen, - FALSE, FALSE, bEncryptedKey))) + if (RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, pIfd, + uiAction, uiDrn, pbHadUniqueKeys, pExportValue, uiValueLen, + FALSE, FALSE, bEncryptedKey))) { goto Exit; } @@ -565,17 +615,17 @@ FSTATIC RCODE flmProcessIndexedFld( Exit: - return( rc); + return (rc); } /**************************************************************************** -Desc: Add an index key to the buffers +Desc: Add an index key to the buffers ****************************************************************************/ RCODE KYAddToKrefTbl( FDB * pDb, - IXD_p pIxd, + IXD * pIxd, FLMUINT uiContainerNum, - IFD_p pIfd, + IFD * pIfd, FLMUINT uiAction, FLMUINT uiDrn, FLMBOOL * pbHadUniqueKeys, @@ -585,35 +635,21 @@ RCODE KYAddToKrefTbl( FLMBOOL bFirstSubstring, FLMBOOL bFldIsEncrypted) { - RCODE rc = FERR_OK; - KREF_ENTRY_p pKref; - FLMBYTE * pKrefKey; - FLMUINT uiKrefKeyLen; - FLMUINT uiSizeNeeded; - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; + RCODE rc = FERR_OK; + KREF_ENTRY * pKref; + FLMBYTE * pKrefKey; + FLMUINT uiKrefKeyLen; + FLMUINT uiSizeNeeded; + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; - /* - Removed if( !uiKeyLen) goto Exit; - As of Oct98, we need to store keys that have no value. - This may or may not have an inpact on GroupWise (doubtful). - On single value fields, we will store a one byte x03 value. - A Collated key will not be zero length. - */ - -#ifdef FLM_NLM - // GWBug to give up CPU when indexing tons of fields for a record. - if( (pKrefCntrl->uiCount & 0x7F) == 0x7F) - f_yieldCPU(); -#endif - - /* If the table is FULL, commit the keys or expand the table */ + // If the table is FULL, commit the keys or expand the table if (pKrefCntrl->uiCount == pKrefCntrl->uiKrefTblSize) { - FLMUINT uiAllocSize; - FLMUINT uiOrigKrefTblSize = pKrefCntrl->uiKrefTblSize; + FLMUINT uiAllocSize; + FLMUINT uiOrigKrefTblSize = pKrefCntrl->uiKrefTblSize; - if( pKrefCntrl->uiKrefTblSize > 0x8000 / sizeof( KREF_ENTRY_p)) + if (pKrefCntrl->uiKrefTblSize > 0x8000 / sizeof(KREF_ENTRY *)) { pKrefCntrl->uiKrefTblSize += 4096; } @@ -622,11 +658,9 @@ RCODE KYAddToKrefTbl( pKrefCntrl->uiKrefTblSize *= 2; } - // GWBUG #30146 1/13/97: Let the table grow until memory error. + uiAllocSize = pKrefCntrl->uiKrefTblSize * sizeof(KREF_ENTRY *); - uiAllocSize = pKrefCntrl->uiKrefTblSize * sizeof( KREF_ENTRY_p ); - - if( RC_BAD( rc = f_realloc( uiAllocSize, &pKrefCntrl->pKrefTbl))) + if (RC_BAD( rc = f_realloc( uiAllocSize, &pKrefCntrl->pKrefTbl))) { pKrefCntrl->uiKrefTblSize = uiOrigKrefTblSize; rc = RC_SET( FERR_MEM); @@ -634,101 +668,100 @@ RCODE KYAddToKrefTbl( } } - /* Get the collated key. */ + // Get the collated key. if (bAlreadyCollated) { - /* Compound keys are already collated. */ - pKrefKey = (FLMBYTE *)pKey; + // Compound keys are already collated. + + pKrefKey = (FLMBYTE*) pKey; uiKrefKeyLen = uiKeyLen; } else { pKrefKey = pKrefCntrl->pKrefKeyBuf; - uiKrefKeyLen = (pIxd->uiContainerNum) - ? MAX_KEY_SIZ - : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); + uiKrefKeyLen = (pIxd->uiContainerNum) + ? MAX_KEY_SIZ + : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); - if( RC_BAD( rc = KYCollateValue( pKrefKey, &uiKrefKeyLen, - pKey, uiKeyLen, pIfd->uiFlags, pIfd->uiLimit, - NULL, NULL, - (FLMUINT)((pIxd->uiLanguage != 0xFFFF) - ? pIxd->uiLanguage - : pDb->pFile->FileHdr.uiDefaultLanguage), - FALSE, bFirstSubstring, FALSE, NULL, NULL, - bFldIsEncrypted))) + if (RC_BAD( rc = KYCollateValue( pKrefKey, &uiKrefKeyLen, pKey, uiKeyLen, + pIfd->uiFlags, pIfd->uiLimit, NULL, NULL, + (FLMUINT) ((pIxd->uiLanguage != 0xFFFF) + ? pIxd->uiLanguage + : pDb->pFile->FileHdr.uiDefaultLanguage), + FALSE, bFirstSubstring, FALSE, NULL, NULL, bFldIsEncrypted))) { goto Exit; } } - // If indexing all containers, add the container - // number. + // If indexing all containers, add the container number. if (!pIxd->uiContainerNum) { appendContainerToKey( pIxd, uiContainerNum, pKrefKey, &uiKrefKeyLen); } - /* - Allocate memory for the key's KREF and the key itself. - We allocate one extra byte so we can NULL terminate the key - below. The extra NULL character is to ensure that the compare - in the qsort routine will work. GedPoolAlloc machine aligns. - */ + // Allocate memory for the key's KREF and the key itself. We allocate + // one extra byte so we can NULL terminate the key below. The extra + // NULL character is to ensure that the compare in the qsort routine + // will work. GedPoolAlloc machine aligns. - uiSizeNeeded = sizeof( KREF_ENTRY) + uiKrefKeyLen + 1; + uiSizeNeeded = sizeof(KREF_ENTRY) + uiKrefKeyLen + 1; - if( (pKref = (KREF_ENTRY_p) - GedPoolAlloc( pKrefCntrl->pPool, uiSizeNeeded )) == NULL) + if ((pKref = (KREF_ENTRY*) GedPoolAlloc( + pKrefCntrl->pPool, uiSizeNeeded)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } - pKrefCntrl->pKrefTbl [ pKrefCntrl->uiCount++ ] = pKref; + + pKrefCntrl->pKrefTbl[pKrefCntrl->uiCount++] = pKref; pKrefCntrl->uiTotalBytes += uiSizeNeeded; - /* Fill in all of the fields in the KREF structure. */ + // Fill in all of the fields in the KREF structure. - flmAssert( pIxd->uiIndexNum > 0 && - pIxd->uiIndexNum < FLM_UNREGISTERED_TAGS); // Sanity check - pKref->ui16IxNum = (FLMUINT16)pIxd->uiIndexNum; + flmAssert( pIxd->uiIndexNum > 0 && pIxd->uiIndexNum < FLM_UNREGISTERED_TAGS); + + pKref->ui16IxNum = (FLMUINT16) pIxd->uiIndexNum; pKref->uiDrn = uiDrn; if (uiAction & KREF_DEL_KEYS) { - pKref->uiFlags = ((uiAction & KREF_MISSING_KEYS_OK) - ? (FLMUINT)(KREF_DELETE_FLAG | - KREF_MISSING_OK) - : (FLMUINT)(KREF_DELETE_FLAG)); + pKref->uiFlags = ((uiAction & KREF_MISSING_KEYS_OK) + ? (FLMUINT) (KREF_DELETE_FLAG | KREF_MISSING_OK) + : (FLMUINT) (KREF_DELETE_FLAG)); } else { pKref->uiFlags = 0; } - if( pIxd->uiFlags & IXD_UNIQUE) + + if (pIxd->uiFlags & IXD_UNIQUE) { *pbHadUniqueKeys = TRUE; pKref->uiFlags |= KREF_UNIQUE_KEY; } + if (bFldIsEncrypted) { pKref->uiFlags |= KREF_ENCRYPTED_KEY; } - pKref->ui16KeyLen = (FLMUINT16)uiKrefKeyLen; + + pKref->ui16KeyLen = (FLMUINT16) uiKrefKeyLen; pKref->uiTrnsSeq = pKrefCntrl->uiTrnsSeqCntr; // Null terminate the key so compare in qsort will work - - pKrefKey[ uiKrefKeyLen++ ] = '\0'; + + pKrefKey[uiKrefKeyLen++] = '\0'; // Copy the key to just after the KREF structure - - f_memcpy( (FLMBYTE *) (&pKref [1]), pKrefKey, uiKrefKeyLen); + + f_memcpy( (FLMBYTE *) (&pKref[1]), pKrefKey, uiKrefKeyLen); Exit: - return( rc); + return (rc); } /**************************************************************************** @@ -762,46 +795,45 @@ RCODE flmEncryptField( } #endif - if ( !pRecord->isEncryptedField( pvField)) + if (!pRecord->isEncryptedField( pvField)) { flmAssert( 0); rc = RC_SET( FERR_FLD_NOT_ENCRYPTED); goto Exit; } - pCcs = (F_CCS *)pDict->pIttTbl[ uiEncId].pvItem; + pCcs = (F_CCS *) pDict->pIttTbl[uiEncId].pvItem; flmAssert( pCcs); uiEncLength = pRecord->getEncryptedDataLength( pvField); - - pucDataBuffer = (FLMBYTE *)GedPoolAlloc( pPool, uiEncLength); - - if (!pucDataBuffer) + + if( (pucDataBuffer = (FLMBYTE *) GedPoolAlloc( pPool, uiEncLength)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } - pucEncBuffer = (FLMBYTE *)pRecord->getEncryptionDataPtr( pvField); + pucEncBuffer = (FLMBYTE *) pRecord->getEncryptionDataPtr( pvField); uiCheckLength = uiEncLength; #ifdef FLM_DEBUG - // Preset the buffer to a known value so we can check - // it after the encryption. It should NOT be the same! + + // Preset the buffer to a known value so we can check it after the + // encryption. It should NOT be the same! f_memset( pucEncBuffer, 'B', uiEncLength); #endif - // We copy the data into a buffer that is as large as the encrypted data - // because the encryption algorithm is expecting to get a buffer + // We copy the data into a buffer that is as large as the encrypted + // data because the encryption algorithm is expecting to get a buffer // that does not need to be padded to the nearest 16 byte boundary. - f_memcpy( pucDataBuffer, - pRecord->getDataPtr( pvField), - pRecord->getDataLength( pvField)); + + f_memcpy( pucDataBuffer, pRecord->getDataPtr( pvField), + pRecord->getDataLength( pvField)); if (RC_BAD( rc = pCcs->encryptToStore( pucDataBuffer, uiEncLength, - pucEncBuffer, &uiCheckLength))) + pucEncBuffer, &uiCheckLength))) { goto Exit; } @@ -816,14 +848,14 @@ RCODE flmEncryptField( bOk = FALSE; for (uiLoop = 0; uiLoop < uiEncLength; uiLoop++) { - if( pucEncBuffer[ uiLoop] != 'B') + if (pucEncBuffer[uiLoop] != 'B') { bOk = TRUE; break; } } - if ( !bOk) + if (!bOk) { flmAssert( 0); rc = RC_SET( FERR_DATA_ERROR); @@ -831,8 +863,8 @@ RCODE flmEncryptField( } #endif - pRecord->setEncFlags( pvField, FLD_HAVE_DECRYPTED_DATA | - FLD_HAVE_ENCRYPTED_DATA); + pRecord->setEncFlags( pvField, + FLD_HAVE_DECRYPTED_DATA | FLD_HAVE_ENCRYPTED_DATA); #ifdef FLM_CHECK_RECORD if (RC_BAD( rc = pRecord->checkRecord())) @@ -841,15 +873,12 @@ RCODE flmEncryptField( } #endif -Exit: +Exit: GedPoolReset( pPool, pvMark); - - return( rc); - + return (rc); } - /**************************************************************************** Desc: Decrypt an encrypted field in the pRecord. ****************************************************************************/ @@ -877,31 +906,30 @@ RCODE flmDecryptField( } #endif - if ( !pRecord->isEncryptedField( pvField)) + if (!pRecord->isEncryptedField( pvField)) { flmAssert( 0); rc = RC_SET( FERR_FLD_NOT_ENCRYPTED); goto Exit; } - pCcs = (F_CCS *)pDict->pIttTbl[ uiEncId].pvItem; + pCcs = (F_CCS*) pDict->pIttTbl[uiEncId].pvItem; flmAssert( pCcs); uiEncLength = pRecord->getEncryptedDataLength( pvField); - pucDataBuffer = (FLMBYTE *)GedPoolAlloc( pPool, uiEncLength); - if (!pucDataBuffer) + if( (pucDataBuffer = (FLMBYTE *) GedPoolAlloc( pPool, uiEncLength)) == NULL) { rc = RC_SET( FERR_MEM); goto Exit; } - pucEncBuffer = (FLMBYTE *)pRecord->getEncryptionDataPtr( pvField); + pucEncBuffer = (FLMBYTE *) pRecord->getEncryptionDataPtr( pvField); uiCheckLength = uiEncLength; - if( RC_BAD( rc = pCcs->decryptFromStore( pucEncBuffer, uiEncLength, - pucDataBuffer, &uiCheckLength))) + if (RC_BAD( rc = pCcs->decryptFromStore( pucEncBuffer, uiEncLength, + pucDataBuffer, &uiCheckLength))) { goto Exit; } @@ -912,15 +940,14 @@ RCODE flmDecryptField( goto Exit; } - f_memcpy( pRecord->getDataPtr( pvField), - pucDataBuffer, - pRecord->getDataLength(pvField)); + f_memcpy( pRecord->getDataPtr( pvField), pucDataBuffer, + pRecord->getDataLength( pvField)); - pRecord->setEncFlags( pvField, FLD_HAVE_DECRYPTED_DATA | - FLD_HAVE_ENCRYPTED_DATA); + pRecord->setEncFlags( pvField, + FLD_HAVE_DECRYPTED_DATA | FLD_HAVE_ENCRYPTED_DATA); #ifdef FLM_CHECK_RECORD - if( RC_BAD( rc = pRecord->checkRecord())) + if (RC_BAD( rc = pRecord->checkRecord())) { goto Exit; } @@ -929,5 +956,928 @@ RCODE flmDecryptField( Exit: GedPoolReset( pPool, pvMark); + return (rc); +} + +/**************************************************************************** +Desc: Substring-ize the string in a node. +****************************************************************************/ +FLMBOOL KYSubstringParse( + const FLMBYTE ** ppText, // [in][out] points to text + FLMUINT * puiTextLen, // [in][out] length of text + FLMUINT uiIfdFlags, // [in] flags + FLMUINT uiLimitParm, // [in] Max characters + FLMBYTE * pKeyBuf, // [out] key buffer to fill + FLMUINT * puiKeyLen) // [out] returns length +{ + const FLMBYTE * pText = *ppText; + FLMUINT uiLen = *puiTextLen; + FLMUINT uiWordLen = 0; + FLMUINT uiLimit = uiLimitParm ? uiLimitParm : IFD_DEFAULT_SUBSTRING_LIMIT; + FLMUINT uiFlags = 0; + FLMUINT uiLeadingSpace = FLM_NO_SPACE; + FLMBOOL bIgnoreSpaceDefault = (uiIfdFlags & IFD_NO_SPACE) ? TRUE : FALSE; + FLMBOOL bIgnoreSpace = TRUE; + FLMBOOL bIgnoreDash = (uiIfdFlags & IFD_NO_DASH) ? TRUE : FALSE; + FLMBOOL bMinSpaces = (uiIfdFlags & (IFD_MIN_SPACES | IFD_NO_SPACE)) ? TRUE : FALSE; + FLMBOOL bNoUnderscore = (uiIfdFlags & IFD_NO_UNDERSCORE) ? TRUE : FALSE; + FLMBOOL bFirstCharacter = TRUE; + + // Set uiFlags + + if (bIgnoreSpaceDefault) + { + uiFlags |= FLM_NO_SPACE; + } + + if (bIgnoreDash) + { + uiFlags |= FLM_NO_DASH; + } + + if (bNoUnderscore) + { + uiFlags |= FLM_NO_UNDERSCORE; + } + + if (uiIfdFlags & IFD_MIN_SPACES) + { + uiFlags |= FLM_MIN_SPACES; + } + + // The limit must return one more than requested in order for the text + // to collation routine to set the truncated flag. + + uiLimit++; + + while (uiLen && uiLimit--) + { + FLMBYTE ch = *pText; + FLMUINT16 ui16WPValue; + FLMUNICODE ui16UniValue; + FLMUINT uiCharLen; + + if ((ch & ASCII_CHAR_MASK) == ASCII_CHAR_CODE) + { + if (ch == ASCII_UNDERSCORE && bNoUnderscore) + { + ch = ASCII_SPACE; + } + + if (ch == ASCII_SPACE && bMinSpaces) + { + if (!bIgnoreSpace) + { + pKeyBuf[uiWordLen++] = ASCII_SPACE; + } + + bIgnoreSpace = TRUE; + pText++; + uiLen--; + continue; + } + + ui16WPValue = (FLMUINT16) ch; + uiCharLen = 1; + } + else + { + if ((uiCharLen = flmTextGetValue( pText, uiLen, NULL, + uiFlags | uiLeadingSpace, &ui16WPValue, &ui16UniValue)) == 0) + { + break; + } + + flmAssert( uiCharLen <= uiLen); + } + + uiLeadingSpace = 0; + bIgnoreSpace = bIgnoreSpaceDefault; + uiLen -= uiCharLen; + while (uiCharLen--) + { + pKeyBuf[uiWordLen++] = *pText++; + } + + // If on the first word position to start on next character for the + // next call. + + if (bFirstCharacter) + { + bFirstCharacter = FALSE; + + // First character - set return value. + + *ppText = pText; + *puiTextLen = uiLen; + } + } + + pKeyBuf[uiWordLen] = '\0'; + + // Case of all spaces - the FALSE will trigger indexing is done. + + *puiKeyLen = (FLMUINT) uiWordLen; + return ((uiWordLen) ? TRUE : FALSE); +} + +/**************************************************************************** +Desc: Keyword-ize the information in a node - node is assumed to be a + TEXT node. +****************************************************************************/ +FLMBOOL KYEachWordParse( + const FLMBYTE ** pText, + FLMUINT * puiTextLen, + FLMUINT uiLimitParm, // [in] Max characters + FLMBYTE * pKeyBuf, // [out] Buffer of at least MAX_KEY_SIZ + FLMUINT * puiKeyLen) +{ + const FLMBYTE * pKey = NULL; + const FLMBYTE * pTmpKey; + FLMUINT uiLimit = uiLimitParm ? uiLimitParm : IFD_DEFAULT_SUBSTRING_LIMIT; + FLMUINT uiLen; + FLMUINT uiBytesProcessed = 0; + FLMBOOL bSkippingDelim = TRUE; + FLMBOOL bHaveWord = FALSE; + FLMUINT uiWordLen = 0; + FLMUINT16 ui16WPValue; + FLMUNICODE ui16UniValue; + FLMUINT uiCharLen; + FLMUINT uiType; + + uiLen = *puiTextLen; + pTmpKey = *pText; + + while ((uiBytesProcessed < uiLen) && (!bHaveWord) && uiLimit) + { + uiCharLen = flmTextGetCharType( pTmpKey, uiLen, &ui16WPValue, + &ui16UniValue, &uiType); + + // Determine how to handle what we got. + + if (bSkippingDelim) + { + + // If we were skipping delimiters, and we run into a + // non-delimiter character, set the bSkippingDelim flag to FALSE + // to indicate the beginning of a word. + + if (uiType & SDWD_CHR) + { + pKey = pTmpKey; + uiWordLen = uiCharLen; + bSkippingDelim = FALSE; + uiLimit--; + } + } + else + { + + // If we were NOT skipping delimiters, and we run into a + // delimiter output the word. + + if (uiType & (DELI_CHR | WDJN_CHR)) + { + bHaveWord = TRUE; + } + else + { + uiWordLen += uiCharLen; + uiLimit--; + } + } + + // Increment str to skip past what we are pointing at. + + pTmpKey += uiCharLen; + uiBytesProcessed += uiCharLen; + } + + *pText = pTmpKey; + *puiTextLen -= uiBytesProcessed; + + // Return the word, if any. + + if (uiWordLen) + { + *puiKeyLen = uiWordLen; + f_memcpy( pKeyBuf, pKey, uiWordLen); + } + + return ((uiWordLen) ? TRUE : FALSE); +} + +/**************************************************************************** +Desc: Setup routine for the KREF_CNTRL structure for record updates. + Will check to see if all structures, buffers and memory pools + need to be allocated: Kref key buffer, CDL table, KrefTbl and pool. + The goal is to have only one allocation for most small transactions. + As of Nov 96, each DB will have its own KREF_CNTRL struture so the + session temp pool does not have to be used. This means that the + CDL and cmpKeys arrays do not have to be allocated for each + record operation (like we did in the session pool). +****************************************************************************/ +RCODE KrefCntrlCheck( + FDB * pDb) +{ + RCODE rc = FERR_OK; // Set for cleaner code. + KREF_CNTRL * pKrefCntrl; + + pKrefCntrl = &pDb->KrefCntrl; + + /* Check if we need to flush between the records and not during + the processing of a record. This simplifies how we reuse the memory. + */ + + if( pKrefCntrl->bKrefSetup) + { + if( (pKrefCntrl->uiCount >= KREF_TBL_THRESHOLD) + || (pKrefCntrl->uiTotalBytes >= KREF_TOTAL_BYTES_THRESHOLD)) + + { + if( RC_BAD( rc = KYKeysCommit( pDb, FALSE))) + { + goto Exit; + } + } + } + else + { + FLMUINT uiKrefTblSize = KREF_TBL_SIZE * sizeof(KREF_ENTRY *); + FLMUINT uiCDLSize = pDb->pDict->uiIfdCnt * sizeof( CDL *); + FLMUINT uiIxdSize = pDb->pDict->uiIxdCnt; + FLMUINT uiKeyBufSize = MAX_KEY_SIZ + 8; + + f_memset( pKrefCntrl, 0, sizeof( KREF_CNTRL)); + pKrefCntrl->bKrefSetup = TRUE; + if (pDb->uiTransType == FLM_UPDATE_TRANS) + { + pKrefCntrl->pPool = &pDb->pFile->krefPool; + pKrefCntrl->bReusePool = TRUE; + } + else + { + pKrefCntrl->pPool = &pDb->tmpKrefPool; + pKrefCntrl->bReusePool = FALSE; + } + + if (pKrefCntrl->bReusePool) + { + GedPoolReset( pKrefCntrl->pPool, NULL); + } + else + { + GedPoolInit( pKrefCntrl->pPool, KREF_POOL_BLOCK_SIZE); + } + + if( RC_BAD( rc = f_alloc( uiKrefTblSize, + &pKrefCntrl->pKrefTbl)) + || (uiCDLSize && RC_BAD( rc = f_calloc( uiCDLSize, + &pKrefCntrl->ppCdlTbl))) + || (uiIxdSize && RC_BAD( rc = f_calloc( uiIxdSize, + &pKrefCntrl->pIxHasCmpKeys))) + || RC_BAD( rc = f_calloc( uiKeyBufSize, + &pKrefCntrl->pKrefKeyBuf))) + { + KrefCntrlFree( pDb); + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pKrefCntrl->uiKrefTblSize = KREF_TBL_SIZE; + } + + pKrefCntrl->pReset = GedPoolMark( pKrefCntrl->pPool); + +Exit: + return( rc); } + +/**************************************************************************** +Desc: Resets or frees the memory associated with the KREF. +****************************************************************************/ +void KrefCntrlFree( + FDB * pDb) +{ + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; + + if( pKrefCntrl->bKrefSetup) + { + if (pKrefCntrl->bReusePool) + { + GedPoolReset( pKrefCntrl->pPool, NULL); + } + else + { + GedPoolFree( pKrefCntrl->pPool); + } + + if( pKrefCntrl->pKrefTbl) + { + f_free( &pKrefCntrl->pKrefTbl); + } + + if( pKrefCntrl->ppCdlTbl) + { + f_free( &pKrefCntrl->ppCdlTbl); + } + + if( pKrefCntrl->pIxHasCmpKeys) + { + f_free( &pKrefCntrl->pIxHasCmpKeys); + } + + if( pKrefCntrl->pKrefKeyBuf) + { + f_free( &pKrefCntrl->pKrefKeyBuf); + } + + // Just set everyone back to zero. + + f_memset( pKrefCntrl, 0, sizeof(KREF_CNTRL)); + } +} + +/**************************************************************************** +Desc: Checks if the current database has any UNIQUE indexes that need to + checked. Also does duplicate processing for the record. +****************************************************************************/ +RCODE KYProcessDupKeys( + FDB * pDb, + FLMBOOL bHadUniqueKeys) +{ + RCODE rc = FERR_OK; + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; + FLMUINT uiCurRecKrefCnt; + + pKrefCntrl->uiTrnsSeqCntr++; + + // Sort and remove duplicates from the list of this record. + + uiCurRecKrefCnt = pKrefCntrl->uiCount - pKrefCntrl->uiLastRecEnd; + + if (uiCurRecKrefCnt > 1) + { + FLMUINT uiSortFlags = KY_DUP_CHK_SRT; + + if (RC_BAD( rc = _KrefQuickSort( &uiSortFlags, + &pKrefCntrl->pKrefTbl[pKrefCntrl->uiLastRecEnd], 0, + uiCurRecKrefCnt - 1))) + { + goto Exit; + } + + // Found any duplicates? + + if (uiSortFlags & KY_DUPS_FOUND) + { + if (RC_BAD( rc = _KrefKillDups( &uiSortFlags, + &pKrefCntrl->pKrefTbl[pKrefCntrl->uiLastRecEnd], + &uiCurRecKrefCnt))) + { + goto Exit; + } + + pKrefCntrl->uiCount = pKrefCntrl->uiLastRecEnd + uiCurRecKrefCnt; + } + } + + if (bHadUniqueKeys) + { + + // Now check the keys for uniquness in table, and database. + + if (RC_BAD( rc = KYAddUniqueKeys( pDb))) + { + goto Exit; + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Remove anything that was put into the KREF table by the current + record update operation. +****************************************************************************/ +void KYAbortCurrentRecord( + FDB * pDb) +{ + flmAssert( pDb->KrefCntrl.bKrefSetup); + + // Reset the CDL and pIxHasCmpKeys tables + + if (pDb->pDict->uiIfdCnt) + { + f_memset( pDb->KrefCntrl.ppCdlTbl, 0, + pDb->pDict->uiIfdCnt * sizeof(CDL *)); + } + + if (pDb->pDict->uiIxdCnt) + { + f_memset( pDb->KrefCntrl.pIxHasCmpKeys, 0, pDb->pDict->uiIxdCnt); + } + + pDb->KrefCntrl.uiCount = pDb->KrefCntrl.uiLastRecEnd; + GedPoolReset( pDb->KrefCntrl.pPool, pDb->KrefCntrl.pReset); +} + +/**************************************************************************** +Desc: Commit (write out) all reference lists from the current pDb. Will + take care of optimially freeing or resetting memory. +****************************************************************************/ +RCODE KYKeysCommit( + FDB * pDb, + FLMBOOL bCommittingTrans) +{ + RCODE rc = FERR_OK; + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; + + // If KrefCntrl has not been initialized, there is no work to do. + + if (pKrefCntrl->bKrefSetup) + { + LFILE * pLFile = NULL; + FLMUINT uiTotal = pKrefCntrl->uiLastRecEnd; + KREF_ENTRY * pKref; + KREF_ENTRY ** pKrefTbl = pKrefCntrl->pKrefTbl; + FLMUINT uiKrefNum; + FLMUINT uiLastIxNum; + + // We should not have reached this point if bAbortTrans is TRUE + + flmAssert( RC_OK( pDb->AbortRc)); + + // uiTotal and uiLastRecEnd must be the same at this point. If not, + // we have a bug. + + flmAssert( uiTotal == pKrefCntrl->uiLastRecEnd); + + // Sort the KREF table, if it contains more than one record and + // key. This will sort all keys from the same index the same. + + if ((uiTotal > 1) && (pKrefCntrl->uiTrnsSeqCntr > 1)) + { + FLMUINT uiQsortFlags = KY_FINAL_SRT; + + if (RC_BAD( rc = _KrefQuickSort( &uiQsortFlags, + pKrefTbl, 0, uiTotal - 1))) + { + goto Exit; + } + } + + uiLastIxNum = 0; + + // Loop through the KREF table outputting all keys + + for (uiKrefNum = 0; uiKrefNum < uiTotal; uiKrefNum++) + { + pKref = pKrefTbl[uiKrefNum]; + + // See if the LFILE changed + + flmAssert( pKref->ui16IxNum > 0 && + pKref->ui16IxNum < FLM_UNREGISTERED_TAGS); + + if (pKref->ui16IxNum != uiLastIxNum) + { + uiLastIxNum = pKref->ui16IxNum; + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, + pDb->pFile->bInLimitedMode, uiLastIxNum, &pLFile, NULL, + TRUE))) + { + goto Exit; + } + } + + // Flush the key to the index + + if (RC_BAD( rc = FSRefUpdate( pDb, pLFile, pKref))) + { + goto Exit; + } + } + + if (bCommittingTrans) + { + KrefCntrlFree( pDb); + } + else + { + + // Empty the table out so we can add more keys in this trans. + + GedPoolReset( pKrefCntrl->pPool, NULL); + pKrefCntrl->uiCount = 0; + pKrefCntrl->uiTotalBytes = 0; + pKrefCntrl->uiLastRecEnd = 0; + pKrefCntrl->uiTrnsSeqCntr = 0; + } + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Adds all unique key values. Backs out on any unique error so that + the transaction may continue. +Note: All duplicates have been removed as well as matching keys. +****************************************************************************/ +FSTATIC RCODE KYAddUniqueKeys( + FDB * pDb) +{ + RCODE rc = FERR_OK; + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; + KREF_ENTRY ** pKrefTbl = pKrefCntrl->pKrefTbl; + KREF_ENTRY * pKref; + FLMUINT uiCurKrefNum; + FLMUINT uiPrevKrefNum; + FLMUINT uiTargetCount; + FLMUINT uiLastIxNum; + LFILE * pLFile; + FLMBOOL bUniqueErrorHit = FALSE; + + // Unique indexes can't be built in the background + + flmAssert( !(pDb->uiFlags & FDB_BACKGROUND_INDEXING)); + + // Start at the first key for this current record checking for all + // keys that belong to a unique index. We must keep all keys around + // until the last key is added/delete so that we can back out all of + // the changes on a unique error. + + for (uiCurKrefNum = pKrefCntrl->uiLastRecEnd, uiLastIxNum = 0, + uiTargetCount = pKrefCntrl->uiCount; uiCurKrefNum < uiTargetCount;) + { + pKref = pKrefTbl[uiCurKrefNum]; + + if (pKref->uiFlags & KREF_UNIQUE_KEY) + { + flmAssert( pKref->ui16IxNum > 0 && + pKref->ui16IxNum < FLM_UNREGISTERED_TAGS); + + if (pKref->ui16IxNum != uiLastIxNum) + { + uiLastIxNum = pKref->ui16IxNum; + if (RC_BAD( rc = fdictGetIndex( pDb->pDict, + pDb->pFile->bInLimitedMode, uiLastIxNum, &pLFile, NULL))) + { + + // Return the index offline error - should not happen + + flmAssert( rc != FERR_INDEX_OFFLINE); + goto Exit; + } + } + + // Flush the key to the index. + + if (RC_BAD( rc = FSRefUpdate( pDb, pLFile, pKref))) + { + pDb->Diag.uiInfoFlags |= FLM_DIAG_INDEX_NUM; + pDb->Diag.uiIndexNum = pKref->ui16IxNum; + + // Check only for FERR_NOT_UNIQUE + + if (rc != FERR_NOT_UNIQUE) + { + goto Exit; + } + + bUniqueErrorHit = TRUE; + + // Cycle through again backing out all keys. + + uiTargetCount = uiCurKrefNum; + uiCurKrefNum = pKrefCntrl->uiLastRecEnd; + + // Make sure uiCurKrefNum is NOT incremented at the top of + // loop. + + continue; + } + + // Toggle the delete flag so on unique error we can back out. + // This sets the ADD to DELETE and the DELETE to ADD (0) + + pKref->uiFlags ^= KREF_DELETE_FLAG; + } + + uiCurKrefNum++; + } + + if (bUniqueErrorHit) + { + rc = RC_SET( FERR_NOT_UNIQUE); + pKrefCntrl->uiCount = pKrefCntrl->uiLastRecEnd; + } + else + { + + // Move every key down removing the processed keys. + + for (uiCurKrefNum = uiPrevKrefNum = pKrefCntrl->uiLastRecEnd, + uiTargetCount = pKrefCntrl->uiCount; + uiCurKrefNum < uiTargetCount; uiCurKrefNum++) + { + pKref = pKrefTbl[uiCurKrefNum]; + + if (!(pKref->uiFlags & KREF_UNIQUE_KEY)) + { + pKrefTbl[uiPrevKrefNum++] = pKrefTbl[uiCurKrefNum]; + } + } + + pKrefCntrl->uiCount = uiPrevKrefNum; + } + +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: Compare function used to compare two keys. The compare is different + depending on the sort pass this is on. +****************************************************************************/ +FSTATIC FLMINT _KrefCompare( + FLMUINT * puiQsortFlags, + KREF_ENTRY * pKrefA, + KREF_ENTRY * pKrefB) +{ + FLMUINT uiMinLen; + FLMINT iCompare; + + // Compare (SORT1) #1, (SORT2) #2 - Index Number. + + if ((iCompare = ((FLMINT) pKrefA->ui16IxNum) - + ((FLMINT) pKrefB->ui16IxNum)) != 0) + { + return (iCompare); + } + + // Compare (SORT1) #2, (SORT2) #3: KEY - including NULL character at + // end. + // + // Comparing the NULL character advoids checking the key length. + // + // VISIT: There could be a BUG where key length should be checked, but + // it has to do with not storing all compound key pieces in the key. + + uiMinLen = f_min( pKrefA->ui16KeyLen, pKrefB->ui16KeyLen) + 1; + if ((iCompare = f_memcmp( &pKrefA[1], &pKrefB[1], uiMinLen)) == 0) + { + if (*puiQsortFlags & KY_FINAL_SRT) + { + + // Compare (SORT2) The DRN so we load by low DRN to high DRN. + + if (pKrefA->uiDrn < pKrefB->uiDrn) + { + return (-1); + } + else if (pKrefA->uiDrn > pKrefB->uiDrn) + { + return (1); + } + + // Compare (SORT2) Sequence number, so operations occur in + // correct order. - this will ALWAYS set iCompare to -1 or 1. It + // is only possible to have different operations here like ADD - + // DELETE - ADD - DELETE when sorted by uiTrnsSeq. This is why we + // will set KY_DUPS_FOUND to get rid of duplicates. + + iCompare = ((FLMINT) pKrefA->uiTrnsSeq) - ((FLMINT) pKrefB->uiTrnsSeq); + } + else + { + + // Compare (SORT1) Operation Flag, Delete or Add. + + *puiQsortFlags |= KY_DUPS_FOUND; + + // Sort so the delete elements are first. + + if ((iCompare = ((FLMINT) (pKrefB->uiFlags & KREF_DELETE_FLAG)) - + ((FLMINT) (pKrefA->uiFlags & KREF_DELETE_FLAG))) == 0) + { + + // Exact duplicate - will remove later + + pKrefA->uiFlags |= KREF_EQUAL_FLAG; + pKrefB->uiFlags |= KREF_EQUAL_FLAG; + } + else + { + + // Data is same but different operation, (delete then an add). + + pKrefA->uiFlags |= KREF_IGNORE_FLAG; + pKrefB->uiFlags |= KREF_IGNORE_FLAG; + } + } + } + + return (iCompare); +} + +/**************************************************************************** +Desc: Quick sort an array of KREF_ENTRY * values. +****************************************************************************/ +FSTATIC RCODE _KrefQuickSort( + FLMUINT * puiQsortFlags, + KREF_ENTRY ** pEntryTbl, + FLMUINT uiLowerBounds, + FLMUINT uiUpperBounds) +{ + FLMUINT uiLBPos; + FLMUINT uiUBPos; + FLMUINT uiMIDPos; + FLMUINT uiLeftItems; + FLMUINT uiRightItems; + KREF_ENTRY * pCurEntry; + KREF_ENTRY * pTempKref; + FLMINT iCompare; + +Iterate_Larger_Half: + + uiUBPos = uiUpperBounds; + uiLBPos = uiLowerBounds; + uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2; + pCurEntry = pEntryTbl[uiMIDPos]; + for (;;) + { + while( (uiLBPos == uiMIDPos) || ((iCompare = _KrefCompare( puiQsortFlags, + pEntryTbl[uiLBPos], pCurEntry)) < 0)) + { + if (uiLBPos >= uiUpperBounds) + { + break; + } + + uiLBPos++; + } + + while ((uiUBPos == uiMIDPos) || (((iCompare = _KrefCompare( + puiQsortFlags, pCurEntry, pEntryTbl[uiUBPos])) < 0))) + { + if (!uiUBPos) + { + break; + } + + uiUBPos--; + } + + if (uiLBPos < uiUBPos) + { + + // Interchange [uiLBPos] with [uiUBPos]. + + KY_SWAP( pEntryTbl, uiLBPos, uiUBPos); + uiLBPos++; + uiUBPos--; + } + else + { + break; + } + } + + // Check for swap( LB, MID ) - cases 3 and 4 + + if (uiLBPos < uiMIDPos) + { + + // Interchange [uiLBPos] with [uiMIDPos] + + KY_SWAP( pEntryTbl, uiMIDPos, uiLBPos); + uiMIDPos = uiLBPos; + } + else if (uiMIDPos < uiUBPos) + { + + // Interchange [uUBPos] with [uiMIDPos] + + KY_SWAP( pEntryTbl, uiMIDPos, uiUBPos); + uiMIDPos = uiUBPos; + } + + // Check the left piece. + + uiLeftItems = (uiLowerBounds + 1 < uiMIDPos) + ? uiMIDPos - uiLowerBounds + : 0; + + uiRightItems = (uiMIDPos + 1 < uiUpperBounds) + ? uiUpperBounds - uiMIDPos + : 0; + + if (uiLeftItems < uiRightItems) + { + + // Recurse on the LEFT side and goto the top on the RIGHT side. + + if (uiLeftItems) + { + (void) _KrefQuickSort( puiQsortFlags, pEntryTbl, uiLowerBounds, + uiMIDPos - 1); + } + + uiLowerBounds = uiMIDPos + 1; + goto Iterate_Larger_Half; + } + else if (uiLeftItems) + { + + // Recurse on the RIGHT side and goto the top for the LEFT side. + + if (uiRightItems) + { + (void) _KrefQuickSort( puiQsortFlags, pEntryTbl, uiMIDPos + 1, + uiUpperBounds); + } + + uiUpperBounds = uiMIDPos - 1; + goto Iterate_Larger_Half; + } + + return (FERR_OK); +} + +/**************************************************************************** +Desc: Kill all duplicate references out of the kref list +Note: This will ONLY work if EVERY kref has been compared to its neighbor. + We may have to compare every neighbor again if the new quick + sort doesn't work. +****************************************************************************/ +FSTATIC RCODE _KrefKillDups( + FLMUINT * puiQsortFlags, + KREF_ENTRY ** pKrefTbl, + FLMUINT* puiKrefTotalRV) +{ + FLMUINT uiTotal = (*puiKrefTotalRV); + FLMUINT uiCurKrefNum; + KREF_ENTRY * pCurKref; + FLMUINT uiLastUniqueKrefNum = 0; + + for (uiCurKrefNum = 1; uiCurKrefNum < uiTotal; uiCurKrefNum++) + { + pCurKref = pKrefTbl[uiCurKrefNum]; + + // If the current KREF equals the last unique one, we can remove it + // from the list by skipping the current entry. To check if they are + // equal, first look at the KREF_EQUAL_FLAGs on both of them. If + // both KREFs have this flag set, we still have to call the compare + // routine. The flags could have been set for two pairs of different + // keys - such as A, A, B, B. In this sequence of keys, all four + // KREFs would have the flag set, but the 2nd "A" is not equal to + // the 1st "B" - thus the need for the call to krefCompare to + // confirm that the keys are really equal. + + if ((pKrefTbl[uiLastUniqueKrefNum]->uiFlags & KREF_EQUAL_FLAG) && + (pCurKref->uiFlags & KREF_EQUAL_FLAG) && + (_KrefCompare( puiQsortFlags, + pKrefTbl[uiLastUniqueKrefNum], pCurKref) == 0)) + { + + // If the current KREF had it's ignore flag set, propagate that + // to the last unique KREF also and remove the current key. This + // will remove all but the first duplicate key. This is possible + // because quick sort may not compare every item. + + if (pCurKref->uiFlags & KREF_IGNORE_FLAG) + { + pKrefTbl[uiLastUniqueKrefNum]->uiFlags |= KREF_IGNORE_FLAG; + } + } + else + { + + // Increment to the next slot if we like this kref. + + if (!(pKrefTbl[uiLastUniqueKrefNum]->uiFlags & KREF_IGNORE_FLAG)) + { + uiLastUniqueKrefNum++; + } + + // Move the item to the current location. + + pKrefTbl[uiLastUniqueKrefNum] = pCurKref; + } + } + + if (!(pKrefTbl[uiLastUniqueKrefNum]->uiFlags & KREF_IGNORE_FLAG)) + { + uiLastUniqueKrefNum++; + } + + *puiKrefTotalRV = uiLastUniqueKrefNum; + return (FERR_OK); +} diff --git a/flaim/src/kycollat.cpp b/flaim/src/kycollat.cpp index 58f46cc..807716a 100644 --- a/flaim/src/kycollat.cpp +++ b/flaim/src/kycollat.cpp @@ -1,8 +1,8 @@ //------------------------------------------------------------------------- -// Desc: Key collation routines. +// Desc: FLAIM collation routines and tables // Tabs: 3 // -// Copyright (c) 1991-2001,2003-2006 Novell, Inc. All Rights Reserved. +// Copyright (c) 1990-2006 Novell, Inc. All Rights Reserved. // // This program is free software; you can redistribute it and/or // modify it under the terms of version 2 of the GNU General Public @@ -24,6 +24,108 @@ #include "flaimsys.h" +// Collating sequence defines + +#define COLLS 32 // first collating number (space/end of line) +#define COLS1 (COLLS+9) // quotes +#define COLS2 (COLS1+5) // parens +#define COLS3 (COLS2+6) // money +#define COLS4 (COLS3+6) // math ops +#define COLS5 (COLS4+8) // math others +#define COLS6 (COLS5+14) // others: %#&@\_|~ +#define COLS7 (COLS6+13) // greek +#define COLS8 (COLS7+25) // numbers +#define COLS9 (COLS8+10) // alphabet +#define COLS10 (COLS9+60) // cyrillic +#define COLS10h (COLS9+42) // hebrew - writes over european and cyrilic +#define COLS10a (COLS10h+28) // arabic - inclusive from 198(C6)- 252(FC) +#define COLS11 253 // End of list - arabic goes to the end +#define COLS0_ARABIC COLS11 // Set if arabic accent marking +#define COLS0_HEBREW COLS11 // Set if hebrew accent marking +#define COLSOEM 254 // OEM character in upper range - non-collatable +#define COLS0_UNICODE 254 // Use this for UNICODE +#define COLS0 255 // graphics/misc - chars without a collate value + +// State table information for double character sorting + +#define STATE1 1 +#define STATE2 2 +#define STATE3 3 +#define STATE4 4 +#define STATE5 5 +#define STATE6 6 +#define STATE7 7 +#define STATE8 8 +#define STATE9 9 +#define STATE10 10 +#define STATE11 11 +#define AFTERC 12 +#define AFTERH 13 +#define AFTERL 14 +#define INSTAE 15 +#define INSTOE 16 +#define INSTSG 17 +#define INSTIJ 18 +#define WITHAA 19 + +#define START_COL 12 +#define START_ALL (START_COL + 1) // all US and European +#define START_DK (START_COL + 2) // Danish +#define START_IS (START_COL + 3) // Icelandic +#define START_NO (START_COL + 4) // Norwegian +#define START_SU (START_COL + 5) // Finnish +#define START_SV (START_COL + 5) // Swedish +#define START_YK (START_COL + 6) // Ukrain +#define START_TK (START_COL + 7) // Turkish +#define START_CZ (START_COL + 8) // Czech +#define START_SL (START_COL + 8) // Slovak + +#define FIXUP_AREA_SIZE 24 + +#define ASCTBLLEN 95 +#define MNTBLLEN 219 +#define SYMTBLLEN 9 +#define GRKTBLLEN 219 +#define CYRLTBLLEN 200 +#define HEBTBL1LEN 27 +#define HEBTBL2LEN 35 +#define AR1TBLLEN 158 +#define AR2TBLLEN 179 + +#define COMPARE_COLLATION 1 +#define COMPARE_COL_AND_SUBCOL 2 +#define COMPARE_VALUE 3 + +#define NULL_SUB_COL_CHECK NULL +#define NULL_CASE_CHECK NULL +#define NULL_WILD_CARD_CHECK NULL + +#define MAX_SUBCOL_BUF 500 // (((MAX_KEY_SIZ / 4) * 3 + fluff +#define MAX_LOWUP_BUF 150 // ((MAX_KEY_SIZ - (MAX_KEY_SIZ / 8)) / 8) * 2 + +#define SET_CASE_BIT 0x01 +#define SET_KATAKANA_BIT 0x01 +#define SET_WIDTH_BIT 0x02 +#define COLS_ASIAN_MARK_VAL 0x40 +#define COLS_ASIAN_MARKS 0x140 + +FSTATIC RCODE KYCmpKeyElmBld( + FDB * pDb, + IXD * pIxd, + FLMUINT uiContainerNum, + IFD * pIfd, + FLMUINT uiAction, + FLMUINT uiDrn, + FLMBOOL * pbHadUniqueKeys, + FLMUINT uiCdlEntry, + FLMUINT uiCompoundPos, + FLMBYTE * pKeyBuf, + FLMUINT uiKeyLen, + FLMBYTE * pLowUpBuf, + FLMUINT uiLuLen, + FlmRecord * pRecord, + FLD_CONTEXT * pFldContext); + FSTATIC RCODE KYFormatText( const FLMBYTE * psVal, FLMUINT uiSrcLen, @@ -36,16 +138,3497 @@ FSTATIC RCODE KYFormatText( FLMBYTE * psDestBuf, FLMUINT * puiDestLen); +FSTATIC RCODE AsiaFlmTextToColStr( + const FLMBYTE * Str, + FLMUINT uiStrLen, + FLMBYTE * ColStr, + FLMUINT * puiColStrLenRV, + FLMUINT uiUppercaseFlag, + FLMUINT * puiCollationLen, + FLMUINT * puiCaseLenRV, + FLMUINT uiCharLimit, + FLMBOOL bFirstSubstring, + FLMBOOL * pbDataTruncated); + +FSTATIC FLMUINT16 flmTextGetSubCol( + FLMUINT16 ui16WPValue, + FLMUINT16 ui16ColValue, + FLMUINT uiLangId); + +FSTATIC FLMINT flmTextCompareSingleChar( + FLMBYTE ** ppLeftText, + FLMUINT * puiLeftLen, + FLMUINT * puiLeftWpChar2, + FLMBYTE ** ppRightText, + FLMUINT * puiRightLen, + FLMUINT * puiRightWpChar2, + FLMINT * piSubColCompare, + FLMINT * piCaseCompare, + FLMBOOL * pbHitWildCard, + FLMINT iCompareType, + FLMUINT16 * pui16ColVal, + FLMUINT uiFlags, + FLMUINT uiLangId); + +FSTATIC FLMUINT FWWSGetColStr( + FLMBYTE * fColStr, + FLMUINT * fcStrLenRV, + FLMBYTE * wordStr, + FLMUINT fWPLang, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbFirstSubstring); + +FSTATIC FLMUINT FWWSCmbSubColBuf( + FLMBYTE * wordStr, + FLMUINT * wdStrLenRV, + FLMBYTE * subColBuf, + FLMBOOL hebrewArabicFlag); + +FSTATIC FLMUINT FWWSToMixed( + FLMBYTE * wordStr, + FLMUINT wdStrLen, + FLMBYTE * lowUpBitStr, + FLMUINT fWPLang); + +FSTATIC FLMUINT AsiaParseCase( + FLMBYTE * WordStr, + FLMUINT * uiWordStrLenRV, + FLMBYTE * pCaseBits); + +FSTATIC RCODE FTextToColStr( + const FLMBYTE * pucStr, + FLMUINT uiStrLen, + FLMBYTE * pucCollatedStr, + FLMUINT * puiCollatedStrLen, + FLMUINT uiUppercaseFlag, + FLMUINT * puiCollationLen, + FLMUINT * puiCaseLen, + FLMUINT uiLanguage, + FLMUINT uiCharLimit, + FLMBOOL bFirstSubstring, + FLMBOOL * pbOriginalCharsLost, + FLMBOOL * pbDataTruncated); + +FSTATIC FLMUINT16 flmAsiaGetCollation( + FLMUINT16 ui16WpChar, + FLMUINT16 ui16NextWpChar, + FLMUINT16 ui16PrevColValue, + FLMUINT16 * pui16ColValue, + FLMUINT16 * pui16SubColVal, + FLMBYTE * pucCaseBits, + FLMUINT16 uiUppercaseFlag); + +FSTATIC FLMUINT16 flmCheckDoubleCollation( + FLMUINT16 * pui16WpChar, + FLMBOOL * pbTwoIntoOne, + const FLMBYTE ** ppucInputStr, + FLMUINT uiLanguage); + +FSTATIC FLMUINT AsiaParseSubCol( + FLMBYTE * WordStr, + FLMUINT * puiWordStrLen, + FLMBYTE * SubColBuf); + +FSTATIC FLMUINT FColStrToText( + FLMBYTE * fColStr, + FLMUINT * fcStrLenRV, + FLMBYTE * textStr, + FLMUINT fWPLang, + FLMBYTE * postBuf, + FLMUINT * postBytesRV, + FLMBOOL * pbDataTruncated, + FLMBOOL * pbFirstSubstring); + +FSTATIC FLMUINT16 ZenToHankaku( + FLMUINT16 ui16WpChar, + FLMUINT16 * DakutenOrHandakutenRV); + +FSTATIC FLMUINT16 HanToZenkaku( + FLMUINT16 ui16WpChar, + FLMUINT16 ui16NextWpChar, + FLMUINT16 * pui16Zenkaku); + +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct BYTE_WORD_TBL +{ + FLMBYTE ByteValue; + FLMUINT16 WordValue; +} BYTE_WORD_TBL; + +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct TBL_B_TO_BP +{ + FLMBYTE key; + FLMBYTE * charPtr; +} TBL_B_TO_BP; + +/**************************************************************************** +Desc: +****************************************************************************/ +#define BYTES_IN_BITS( bits) \ + ((bits + 7) >> 3) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define TEST1BIT( buf, bPos) \ + ((((buf)[ (bPos) >> 3]) >> (7 - ((bPos) & 7))) & 1) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define GET1BIT( buf, bPos) \ + ((((buf)[ (bPos) >> 3]) >> (7 - ((bPos) & 7))) & 1) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define GETnBITS( n, bf, bit) \ + (((unsigned int)( \ + ((unsigned char)bf[ (bit) >> 3] << 8) \ + | \ + (unsigned char)bf[ ((bit) >> 3) + 1] \ + ) >> (16 - (n) - ((bit) & 7)) \ + ) & ((1 << (n)) - 1) \ + ) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define SET_BIT( buf, bPos) \ + ((buf)[(bPos) >> 3] |= (FLMBYTE)((1 << (7 - ((bPos) & 7))))) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define RESET_BIT( buf, bPos) \ + ((buf)[(bPos) >> 3] &= (FLMBYTE)(~(1 << (7 - ((bPos) & 7))))) + +/**************************************************************************** +Desc: +****************************************************************************/ +#define SETnBITS( n, bf, bit, v) \ +{ (bf)[ (bit) >> 3] |= \ + (FLMBYTE)(((v) << (8 - (n))) \ + >> \ + ((bit) & 7)); \ + (bf)[ ((bit) >> 3) + 1] = \ + (FLMBYTE)((v) \ + << \ + (16 - (n) - ((bit) & 7))); \ +} + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 flmValuea[] = +{ + STATE1, + STATE3, + STATE2, + STATE2, + STATE8, + STATE8, + STATE1, + STATE3, + STATE9, + STATE10, // No longer in use + STATE10, // No longer in use + STATE4, + STATE6, + STATE6, + STATE5, + INSTAE, + INSTOE, + AFTERC, + AFTERH, + AFTERL, + STATE7, + STATE6, + INSTSG, // ss for German + INSTIJ, + STATE11, // aa - no longer in use + WITHAA, // aa - no longer in use + START_CZ, // Czech + START_DK, // Danish + START_NO, // Norwegian + START_SL, // Slovak + START_TK, // Turkish + START_SU, // Finnish + START_IS, // Icelandic + START_SV, // Swedish + START_YK, // Ukrainian + + // Single character fixups + + COLS9, COLS9, COLS9, COLS9, // US and others + COLS9+1, COLS9+1, COLS9+21, COLS9+21, + COLS9+30, COLS9+30, COLS9+21, COLS9+21, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9+45, COLS9+45, COLS9+55, COLS9+55, // DANISH + COLS9+42, COLS9+42, COLS9+53, COLS9+53, + COLS9+30, COLS9+30, COLS9+49, COLS9+49, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9, COLS9, COLS9, COLS9, // Icelandic + COLS9+46, COLS9+46, COLS9+50, COLS9+50, + COLS9+30, COLS9+30, COLS9+54, COLS9+54, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9, COLS9, COLS9+51, COLS9+51, // Norwegian + COLS9+43, COLS9+43, COLS9+21, COLS9+21, + COLS9+30, COLS9+30, COLS9+47, COLS9+47, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9+48, COLS9+48, COLS9+44, COLS9+44, // Finnish/Swedish + COLS9+1, COLS9+1, COLS9+52, COLS9+52, + COLS9+30, COLS9+30, COLS9+21, COLS9+21, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9, COLS9, COLS9, COLS9, // Ukrain + COLS9+1, COLS9+1, COLS9+21, COLS9+21, + COLS9+30, COLS9+30, COLS9+21, COLS9+21, + COLS10+48, COLS10+48, COLS9+12, COLS9+12, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9, COLS9, COLS9, COLS9, // Turkish + COLS9+1, COLS9+1, COLS9+21, COLS9+21, + COLS9+30, COLS9+30, COLS9+21, COLS9+21, + COLS9+43, COLS9+43, COLS9+11, COLS9+11, + COLS9+3, COLS9+3, COLS9+25, COLS9+25, + COLS9+27, COLS9+27, COLS9+35, COLS9+35, + + COLS9, COLS9, COLS9, COLS9, // Czech / Slovak + COLS9+1, COLS9+1, COLS9+21, COLS9+21, + COLS9+30, COLS9+30, COLS9+21, COLS9+21, + COLS10+43, COLS10+43, COLS9+12, COLS9+12, + COLS9+5, COLS9+5, COLS9+26, COLS9+26, + COLS9+28, COLS9+28, COLS9+36, COLS9+36 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmAsc60Tbl[ ASCTBLLEN + 2] = +{ + 0x20, // Initial character offset + ASCTBLLEN, // Length of this table + COLLS, // + COLLS+5, // ! + COLS1, // " + COLS6+1, // # + COLS3, // $ + COLS6, // % + COLS6+2, // & + COLS1+1, // ' + COLS2, // ( + COLS2+1, // ) + COLS4+2, // * + COLS4, // + + COLLS+2, // , + COLS4+1, // - + COLLS+1, // . + COLS4+3, // / + COLS8, // 0 + COLS8+1, // 1 + COLS8+2, // 2 + COLS8+3, // 3 + COLS8+4, // 4 + COLS8+5, // 5 + COLS8+6, // 6 + COLS8+7, // 7 + COLS8+8, // 8 + COLS8+9, // 9 + COLLS+3, // : + COLLS+4, // ; + COLS5, // < + COLS5+2, // = + COLS5+4, // > + COLLS+7, // ? + COLS6+3, // @ + COLS9, // A + COLS9+2, // B + COLS9+3, // C + COLS9+6, // D + COLS9+7, // E + COLS9+8, // F + COLS9+9, // G + COLS9+10, // H + COLS9+12, // I + COLS9+14, // J + COLS9+15, // K + COLS9+16, // L + COLS9+18, // M + COLS9+19, // N + COLS9+21, // O + COLS9+23, // P + COLS9+24, // Q + COLS9+25, // R + COLS9+27, // S + COLS9+29, // T + COLS9+30, // U + COLS9+31, // V + COLS9+32, // W + COLS9+33, // X + COLS9+34, // Y + COLS9+35, // Z + COLS9+40, // [ + COLS6+4, // backslash + COLS9+41, // ] + COLS4+4, // ^ + COLS6+5, // _ + COLS1+2, // ` + COLS9, // a + COLS9+2, // b + COLS9+3, // c + COLS9+6, // d + COLS9+7, // e + COLS9+8, // f + COLS9+9, // g + COLS9+10, // h + COLS9+12, // i + COLS9+14, // j + COLS9+15, // k + COLS9+16, // l + COLS9+18, // m + COLS9+19, // n + COLS9+21, // o + COLS9+23, // p + COLS9+24, // q + COLS9+25, // r + COLS9+27, // s + COLS9+29, // t + COLS9+30, // u + COLS9+31, // v + COLS9+32, // w + COLS9+33, // x + COLS9+34, // y + COLS9+35, // z + COLS2+4, // { + COLS6+6, // | + COLS2+5, // } + COLS6+7 // ~ +}; + +/**************************************************************************** +Desc: Multinational table +****************************************************************************/ +FLMBYTE flmMn60Tbl[ MNTBLLEN + 2] = +{ + 23, // Initial character offset + MNTBLLEN, // Length of this table + COLS9+27, // German Double s + COLS9+15, // Icelandic k + COLS9+14, // Dotless j + + // IBM Charset + + COLS9, // A Acute + COLS9, // a Acute + COLS9, // A Circumflex + COLS9, // a Circumflex + COLS9, // A Diaeresis or Umlaut + COLS9, // a Diaeresis or Umlaut + COLS9, // A Grave + COLS9, // a Grave + COLS9, // A Ring + COLS9, // a Ring + COLS9+1, // AE digraph + COLS9+1, // ae digraph + COLS9+3, // C Cedilla + COLS9+3, // c Cedilla + COLS9+7, // E Acute + COLS9+7, // e Acute + COLS9+7, // E Circumflex + COLS9+7, // e Circumflex + COLS9+7, // E Diaeresis or Umlaut + COLS9+7, // e Diaeresis or Umlaut + COLS9+7, // E Grave + COLS9+7, // e Grave + COLS9+12, // I Acute + COLS9+12, // i Acute + COLS9+12, // I Circumflex + COLS9+12, // i Circumflex + COLS9+12, // I Diaeresis or Umlaut + COLS9+12, // i Diaeresis or Umlaut + COLS9+12, // I Grave + COLS9+12, // i Grave + COLS9+20, // N Tilde + COLS9+20, // n Tilde + COLS9+21, // O Acute + COLS9+21, // o Acute + COLS9+21, // O Circumflex + COLS9+21, // o Circumflex + COLS9+21, // O Diaeresis or Umlaut + COLS9+21, // o Diaeresis or Umlaut + COLS9+21, // O Grave + COLS9+21, // o Grave + COLS9+30, // U Acute + COLS9+30, // u Acute + COLS9+30, // U Circumflex + COLS9+30, // u Circumflex + COLS9+30, // U Diaeresis or Umlaut + COLS9+30, // u Diaeresis or Umlaut + COLS9+30, // U Grave + COLS9+30, // u Grave + COLS9+34, // Y Diaeresis or Umlaut + COLS9+34, // y Diaeresis or Umlaut + + // IBM foreign + + COLS9, // A Tilde + COLS9, // a Tilde + COLS9+6, // D Cross Bar + COLS9+6, // d Cross Bar + COLS9+21, // O Slash + COLS9+21, // o Slash + COLS9+21, // O Tilde + COLS9+21, // o Tilde + COLS9+34, // Y Acute + COLS9+34, // y Acute + COLS9+6, // Uppercase Eth + COLS9+6, // Lowercase Eth + COLS9+37, // Uppercase Thorn + COLS9+37, // Lowercase Thorn + + // Teletex chars + + COLS9, // A Breve + COLS9, // a Breve + COLS9, // A Macron + COLS9, // a Macron + COLS9, // A Ogonek + COLS9, // a Ogonek + COLS9+3, // C Acute + COLS9+3, // c Acute + COLS9+3, // C Caron or Hachek + COLS9+3, // c Caron or Hachek + COLS9+3, // C Circumflex + COLS9+3, // c Circumflex + COLS9+3, // C Dot Above + COLS9+3, // c Dot Above + COLS9+6, // D Caron or Hachek (Apostrophe Beside) + COLS9+6, // d Caron or Hachek (Apostrophe Beside) + COLS9+7, // E Caron or Hachek + COLS9+7, // e Caron or Hachek + COLS9+7, // E Dot Above + COLS9+7, // e Dot Above + COLS9+7, // E Macron + COLS9+7, // e Macron + COLS9+7, // E Ogonek + COLS9+7, // e Ogonek + COLS9+9, // G Acute + COLS9+9, // g Acute + COLS9+9, // G Breve + COLS9+9, // g Breve + COLS9+9, // G Caron or Hachek + COLS9+9, // g Caron or Hachek + COLS9+9, // G Cedilla (Apostrophe Under) + COLS9+9, // g Cedilla (Apostrophe Over) + COLS9+9, // G Circumflex + COLS9+9, // g Circumflex + COLS9+9, // G Dot Above + COLS9+9, // g Dot Above + COLS9+10, // H Circumflex + COLS9+10, // h Circumflex + COLS9+10, // H Cross Bar + COLS9+10, // h Cross Bar + COLS9+12, // I Dot Above (Sharp Accent) + COLS9+12, // i Dot Above (Sharp Accent) + COLS9+12, // I Macron + COLS9+12, // i Macron + COLS9+12, // I Ogonek + COLS9+12, // i Ogonek + COLS9+12, // I Tilde + COLS9+12, // i Tilde + COLS9+13, // IJ Digraph + COLS9+13, // ij Digraph + COLS9+14, // J Circumflex + COLS9+14, // j Circumflex + COLS9+15, // K Cedilla (Apostrophe Under) + COLS9+15, // k Cedilla (Apostrophe Under) + COLS9+16, // L Acute + COLS9+16, // l Acute + COLS9+16, // L Caron or Hachek (Apostrophe Beside) + COLS9+16, // l Caron or Hachek (Apostrophe Beside) + COLS9+16, // L Cedilla (Apostrophe Under) + COLS9+16, // l Cedilla (Apostrophe Under) + COLS9+16, // L Center Dot + COLS9+16, // l Center Dot + COLS9+16, // L Stroke + COLS9+16, // l Stroke + COLS9+19, // N Acute + COLS9+19, // n Acute + COLS9+19, // N Apostrophe + COLS9+19, // n Apostrophe + COLS9+19, // N Caron or Hachek + COLS9+19, // n Caron or Hachek + COLS9+19, // N Cedilla (Apostrophe Under) + COLS9+19, // n Cedilla (Apostrophe Under) + COLS9+21, // O Double Acute + COLS9+21, // o Double Acute + COLS9+21, // O Macron + COLS9+21, // o Macron + COLS9+22, // OE digraph + COLS9+22, // oe digraph + COLS9+25, // R Acute + COLS9+25, // r Acute + COLS9+25, // R Caron or Hachek + COLS9+25, // r Caron or Hachek + COLS9+25, // R Cedilla (Apostrophe Under) + COLS9+25, // r Cedilla (Apostrophe Under) + COLS9+27, // S Acute + COLS9+27, // s Acute + COLS9+27, // S Caron or Hachek + COLS9+27, // s Caron or Hachek + COLS9+27, // S Cedilla + COLS9+27, // s Cedilla + COLS9+27, // S Circumflex + COLS9+27, // s Circumflex + COLS9+29, // T Caron or Hachek (Apostrophe Beside) + COLS9+29, // t Caron or Hachek (Apostrophe Beside) + COLS9+29, // T Cedilla (Apostrophe Under) + COLS9+29, // t Cedilla (Apostrophe Under) + COLS9+29, // T Cross Bar + COLS9+29, // t Cross Bar + COLS9+30, // U Breve + COLS9+30, // u Breve + COLS9+30, // U Double Acute + COLS9+30, // u Double Acute + COLS9+30, // U Macron + COLS9+30, // u Macron + COLS9+30, // U Ogonek + COLS9+30, // u Ogonek + COLS9+30, // U Ring + COLS9+30, // u Ring + COLS9+30, // U Tilde + COLS9+30, // u Tilde + COLS9+32, // W Circumflex + COLS9+32, // w Circumflex + COLS9+34, // Y Circumflex + COLS9+34, // y Circumflex + COLS9+35, // Z Acute + COLS9+35, // z Acute + COLS9+35, // Z Caron or Hachek + COLS9+35, // z Caron or Hachek + COLS9+35, // Z Dot Above + COLS9+35, // z Dot Above + COLS9+19, // Uppercase Eng + COLS9+19, // Lowercase Eng + + // other + + COLS9+6, // D Macron + COLS9+6, // d Macron + COLS9+16, // L Macron + COLS9+16, // l Macron + COLS9+19, // N Macron + COLS9+19, // n Macron + COLS9+25, // R Grave + COLS9+25, // r Grave + COLS9+27, // S Macron + COLS9+27, // s Macron + COLS9+29, // T Macron + COLS9+29, // t Macron + COLS9+34, // Y Breve + COLS9+34, // y Breve + COLS9+34, // Y Grave + COLS9+34, // y Grave + COLS9+6, // D Apostrophe Beside + COLS9+6, // d Apostrophe Beside + COLS9+21, // O Apostrophe Beside + COLS9+21, // o Apostrophe Beside + COLS9+30, // U Apostrophe Beside + COLS9+30, // u Apostrophe Beside + COLS9+7, // E breve + COLS9+7, // e breve + COLS9+12, // I breve + COLS9+12, // i breve + COLS9+12, // dotless I + COLS9+12, // dotless i + COLS9+21, // O breve + COLS9+21 // o breve +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmSym60Tbl[ SYMTBLLEN + 2] = +{ + 11, // Initial character offset + SYMTBLLEN, // Length of this table + COLS3+2, // pound + COLS3+3, // yen + COLS3+4, // pacetes + COLS3+5, // floren + COLS0, + COLS0, + COLS0, + COLS0, + COLS3+1, // cent +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmGrk60Tbl[ GRKTBLLEN + 2] = +{ + 0, // Starting offset + GRKTBLLEN, // Length + COLS7, // Uppercase Alpha + COLS7, // Lowercase Alpha + COLS7+1, // Uppercase Beta + COLS7+1, // Lowercase Beta + COLS7+1, // Uppercase Beta Medial + COLS7+1, // Lowercase Beta Medial + COLS7+2, // Uppercase Gamma + COLS7+2, // Lowercase Gamma + COLS7+3, // Uppercase Delta + COLS7+3, // Lowercase Delta + COLS7+4, // Uppercase Epsilon + COLS7+4, // Lowercase Epsilon + COLS7+5, // Uppercase Zeta + COLS7+5, // Lowercase Zeta + COLS7+6, // Uppercase Eta + COLS7+6, // Lowercase Eta + COLS7+7, // Uppercase Theta + COLS7+7, // Lowercase Theta + COLS7+8, // Uppercase Iota + COLS7+8, // Lowercase Iota + COLS7+9, // Uppercase Kappa + COLS7+9, // Lowercase Kappa + COLS7+10, // Uppercase Lambda + COLS7+10, // Lowercase Lambda + COLS7+11, // Uppercase Mu + COLS7+11, // Lowercase Mu + COLS7+12, // Uppercase Nu + COLS7+12, // Lowercase Nu + COLS7+13, // Uppercase Xi + COLS7+13, // Lowercase Xi + COLS7+14, // Uppercase Omicron + COLS7+14, // Lowercase Omicron + COLS7+15, // Uppercase Pi + COLS7+15, // Lowercase Pi + COLS7+16, // Uppercase Rho + COLS7+16, // Lowercase Rho + COLS7+17, // Uppercase Sigma + COLS7+17, // Lowercase Sigma + COLS7+17, // Uppercase Sigma Terminal + COLS7+17, // Lowercase Sigma Terminal + COLS7+18, // Uppercase Tau + COLS7+18, // Lowercase Tau + COLS7+19, // Uppercase Upsilon + COLS7+19, // Lowercase Upsilon + COLS7+20, // Uppercase Phi + COLS7+20, // Lowercase Phi + COLS7+21, // Uppercase Chi + COLS7+21, // Lowercase Chi + COLS7+22, // Uppercase Psi + COLS7+22, // Lowercase Psi + COLS7+23, // Uppercase Omega + COLS7+23, // Lowercase Omega + + // Other Modern Greek Characters [8,52] + + COLS7, // Uppercase ALPHA Tonos high prime + COLS7, // Lowercase Alpha Tonos - acute + COLS7+4, // Uppercase EPSILON Tonos - high prime + COLS7+4, // Lowercase Epslion Tonos - acute + COLS7+6, // Uppercase ETA Tonos - high prime + COLS7+6, // Lowercase Eta Tonos - acute + COLS7+8, // Uppercase IOTA Tonos - high prime + COLS7+8, // Lowercase iota Tonos - acute + COLS7+8, // Uppercase IOTA Diaeresis + COLS7+8, // Lowercase iota diaeresis + COLS7+14, // Uppercase OMICRON Tonos - high prime + COLS7+14, // Lowercase Omicron Tonos - acute + COLS7+19, // Uppercase UPSILON Tonos - high prime + COLS7+19, // Lowercase Upsilon Tonos - acute + COLS7+19, // Uppercase UPSILON Diaeresis + COLS7+19, // Lowercase Upsilon diaeresis + COLS7+23, // Uppercase OMEGA Tonos - high prime + COLS7+23, // Lowercase Omega Tonso - acute + + // Variants [8,70] + + COLS7+4, // epsilon (variant) + COLS7+7, // theta (variant) + COLS7+9, // kappa (variant) + COLS7+15, // pi (variant) + COLS7+16, // rho (variant) + COLS7+17, // sigma (variant) + COLS7+19, // upsilon (variant) + COLS7+20, // phi (variant) + COLS7+23, // omega (variant) + + // Greek Diacritic marks [8,79] + + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, + COLS0, // 8,108 end of diacritic marks + + // Ancient Greek [8,109] + + COLS7, // alpha grave + COLS7, // alpha circumflex + COLS7, // alpha w/iota + COLS7, // alpha acute w/iota + COLS7, // alpha grave w/iota + COLS7, // alpha circumflex w/Iota + COLS7, // alpha smooth + COLS7, // alpha smooth acute + COLS7, // alpha smooth grave + COLS7, // alpha smooth circumflex + COLS7, // alpha smooth w/Iota + COLS7, // alpha smooth acute w/Iota + COLS7, // alpha smooth grave w/Iota + COLS7, // alpha smooth circumflex w/Iota + COLS7, // alpha rough + COLS7, // alpha rough acute + COLS7, // alpha rough grave + COLS7, // alpha rough circumflex + COLS7, // alpha rough w/Iota + COLS7, // alpha rough acute w/Iota + COLS7, // alpha rough grave w/Iota + COLS7, // alpha rough circumflex w/Iota + COLS7+4, // epsilon grave + COLS7+4, // epsilon smooth + COLS7+4, // epsilon smooth acute + COLS7+4, // epsilon smooth grave + COLS7+4, // epsilon rough + COLS7+4, // epsilon rough acute + COLS7+4, // epsilon rough grave + COLS7+6, // eta grave + COLS7+6, // eta circumflex + COLS7+6, // eta w/iota + COLS7+6, // eta acute w/iota + COLS7+6, // eta grave w/Iota + COLS7+6, // eta circumflex w/Iota + COLS7+6, // eta smooth + COLS7+6, // eta smooth acute + COLS7+6, // eta smooth grave + COLS7+6, // eta smooth circumflex + COLS7+6, // eta smooth w/Iota + COLS7+6, // eta smooth acute w/Iota + COLS7+6, // eta smooth grave w/Iota + COLS7+6, // eta smooth circumflex w/Iota + COLS7+6, // eta rough + COLS7+6, // eta rough acute + COLS7+6, // eta rough grave + COLS7+6, // eta rough circumflex + COLS7+6, // eta rough w/Iota + COLS7+6, // eta rough acute w/Iota + COLS7+6, // eta rough grave w/Iota + COLS7+6, // eta rough circumflex w/Iota + COLS7+8, // iota grave + COLS7+8, // iota circumflex + COLS7+8, // iota acute diaeresis + COLS7+8, // iota grave diaeresis + COLS7+8, // iota smooth + COLS7+8, // iota smooth acute + COLS7+8, // iota smooth grave + COLS7+8, // iota smooth circumflex + COLS7+8, // iota rough + COLS7+8, // iota rough acute + COLS7+8, // iota rough grave + COLS7+8, // iota rough circumflex + COLS7+14, // omicron grave + COLS7+14, // omicron smooth + COLS7+14, // omicron smooth acute + COLS7+14, // omicron smooth grave + COLS7+14, // omicron rough + COLS7+14, // omicron rough acute + COLS7+14, // omicron rough grave + COLS7+16, // rho smooth + COLS7+16, // rho rough + COLS7+19, // upsilon grave + COLS7+19, // upsilon circumflex + COLS7+19, // upsilon acute diaeresis + COLS7+19, // upsilon grave diaeresis + COLS7+19, // upsilon smooth + COLS7+19, // upsilon smooth acute + COLS7+19, // upsilon smooth grave + COLS7+19, // upsilon smooth circumflex + COLS7+19, // upsilon rough + COLS7+19, // upsilon rough acute + COLS7+19, // upsilon rough grave + COLS7+19, // upsilon rough circumflex + COLS7+23, // omega grave + COLS7+23, // omega circumflex + COLS7+23, // omega w/Iota + COLS7+23, // omega acute w/Iota + COLS7+23, // omega grave w/Iota + COLS7+23, // omega circumflex w/Iota + COLS7+23, // omega smooth + COLS7+23, // omega smooth acute + COLS7+23, // omega smooth grave + COLS7+23, // omega smooth circumflex + COLS7+23, // omega smooth w/Iota + COLS7+23, // omega smooth acute w/Iota + COLS7+23, // omega smooth grave w/Iota + COLS7+23, // omega smooth circumflex w/Iota + COLS7+23, // omega rough + COLS7+23, // omega rough acute + COLS7+23, // omega rough grave + COLS7+23, // omega rough circumflex + COLS7+23, // omega rough w/Iota + COLS7+23, // omega rough acute w/Iota + COLS7+23, // omega rough grave w/Iota + COLS7+23, // omega rough circumflex w/Iota + COLS7+24, // Uppercase Stigma--the number 6 + COLS7+24, // Uppercase Digamma--Obsolete letter used as 6 + COLS7+24, // Uppercase Koppa--Obsolete letter used as 90 + COLS7+24 // Uppercase Sampi--Obsolete letter used as 900 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmCyrl60Tbl[ CYRLTBLLEN + 2] = +{ + 0, // Starting offset + CYRLTBLLEN, // Length of table + COLS10, // Russian uppercase A + COLS10, // Russian lowercase A + COLS10+1, // Russian uppercase BE + COLS10+1, // Russian lowercase BE + COLS10+2, // Russian uppercase VE + COLS10+2, // Russian lowercase VE + COLS10+3, // Russian uppercase GHE + COLS10+3, // Russian lowercase GHE + COLS10+5, // Russian uppercase DE + COLS10+5, // Russian lowercase DE + COLS10+8, // Russian uppercase E + COLS10+8, // Russian lowercase E + COLS10+9, // Russian lowercase YO + COLS10+9, // Russian lowercase YO + COLS10+11, // Russian uppercase ZHE + COLS10+11, // Russian lowercase ZHE + COLS10+12, // Russian uppercase ZE + COLS10+12, // Russian lowercase ZE + COLS10+14, // Russian uppercase I + COLS10+14, // Russian lowercase I + COLS10+17, // Russian uppercase SHORT I + COLS10+17, // Russian lowercase SHORT I + COLS10+19, // Russian uppercase KA + COLS10+19, // Russian lowercase KA + COLS10+20, // Russian uppercase EL + COLS10+20, // Russian lowercase EL + COLS10+22, // Russian uppercase EM + COLS10+22, // Russian lowercase EM + COLS10+23, // Russian uppercase EN + COLS10+23, // Russian lowercase EN + COLS10+25, // Russian uppercase O + COLS10+25, // Russian lowercase O + COLS10+26, // Russian uppercase PE + COLS10+26, // Russian lowercase PE + COLS10+27, // Russian uppercase ER + COLS10+27, // Russian lowercase ER + COLS10+28, // Russian uppercase ES + COLS10+28, // Russian lowercase ES + COLS10+29, // Russian uppercase TE + COLS10+29, // Russian lowercase TE + COLS10+32, // Russian uppercase U + COLS10+32, // Russian lowercase U + COLS10+34, // Russian uppercase EF + COLS10+34, // Russian lowercase EF + COLS10+35, // Russian uppercase HA + COLS10+35, // Russian lowercase HA + COLS10+36, // Russian uppercase TSE + COLS10+36, // Russian lowercase TSE + COLS10+37, // Russian uppercase CHE + COLS10+37, // Russian lowercase CHE + COLS10+39, // Russian uppercase SHA + COLS10+39, // Russian lowercase SHA + COLS10+40, // Russian uppercase SHCHA + COLS10+40, // Russian lowercase SHCHA + COLS10+41, // Russian lowercase ER (also hard sign) + COLS10+41, // Russian lowercase ER (also hard sign) + COLS10+42, // Russian lowercase ERY + COLS10+42, // Russian lowercase ERY + COLS10+43, // Russian lowercase SOFT SIGN + COLS10+43, // Russian lowercase SOFT SIGN + COLS10+45, // Russian uppercase REVERSE E + COLS10+45, // Russian lowercase REVERSE E + COLS10+46, // Russian uppercase YU + COLS10+46, // Russian lowercase yu + COLS10+47, // Russian uppercase YA + COLS10+47, // Russian lowercase ya + COLS0, // Russian uppercase EH + COLS0, // Russian lowercase eh + COLS10+7, // Macedonian uppercase SOFT DJ + COLS10+7, // Macedonian lowercase soft dj + COLS10+4, // Ukrainian uppercase HARD G + COLS10+4, // Ukrainian lowercase hard g + COLS0, // GE bar + COLS0, // ge bar + COLS10+6, // Serbian uppercase SOFT DJ + COLS10+6, // Serbian lowercase SOFT DJ + COLS0, // IE (variant) + COLS0, // ie (variant) + COLS10+10, // Ukrainian uppercase YE + COLS10+10, // Ukrainian lowercase YE + COLS0, // ZHE with right descender + COLS0, // zhe with right descender + COLS10+13, // Macedonian uppercase ZELO + COLS10+13, // Macedonian lowercase ZELO + COLS0, // Old Slovanic uppercase Z + COLS0, // Old Slovanic uppercase z + COLS0, // II with macron + COLS0, // ii with mscron + COLS10+15, // Ukrainian uppercase I + COLS10+15, // Ukrainian lowercase I + COLS10+16, // Ukrainian uppercase I with Two Dots + COLS10+16, // Ukrainian lowercase I with Two Dots + COLS0, // Old Slovanic uppercase I ligature + COLS0, // Old Slovanic lowercase I ligature + COLS10+18, // Serbian--Macedonian uppercase JE + COLS10+18, // Serbian--Macedonian lowercase JE + COLS10+31, // Macedonian uppercase SOFT K + COLS10+31, // Macedonian lowercase SOFT K + COLS0, // KA with right descender + COLS0, // ka with right descender + COLS0, // KA ogonek + COLS0, // ka ogonek + COLS0, // KA vertical bar + COLS0, // ka vertical bar + COLS10+21, // Serbian--Macedonian uppercase SOFT L + COLS10+21, // Serbian--Macedonian lowercase SOFT L + COLS0, // EN with right descender + COLS0, // en with right descender + COLS10+24, // Serbian--Macedonian uppercase SOFT N + COLS10+24, // Serbian--Macedonian lowercase SOFT N + COLS0, // ROUND OMEGA + COLS0, // round omega + COLS0, // OMEGA + COLS0, // omega + COLS10+30, // Serbian uppercase SOFT T + COLS10+30, // Serbian lowercase SOFT T + COLS10+33, // Byelorussian uppercase SHORT U + COLS10+33, // Byelorussian lowercase SHORT U + COLS0, // U with macron + COLS0, // u with macron + COLS0, // STRAIGHT U + COLS0, // straight u + COLS0, // STRAIGHT U bar + COLS0, // straight u bar + COLS0, // OU ligature + COLS0, // ou ligature + COLS0, // KHA with right descender + COLS0, // kha with right descender + COLS0, // KHA ogonek + COLS0, // kha ogonek + COLS0, // H + COLS0, // h + COLS0, // OMEGA titlo + COLS0, // omega titlo + COLS10+38, // Serbian uppercase HARD DJ + COLS10+38, // Serbian lowercase HARD DJ + COLS0, // CHE with right descender + COLS0, // che with right descender + COLS0, // CHE vertical bar + COLS0, // che vertical bar + COLS0, // Old Slavonic SHCHA (variant) + COLS0, // old SLAVONIC shcha (variant) + COLS10+44, // Old Russian uppercase YAT + COLS10+44, // Old Russian lowercase YAT + + // END OF UNIQUE COLLATED BYTES + // CHARACTERS BELOW MUST HAVE HAVE THEIR OWN + // SUB-COLLATION VALUE TO COMPARE CORRECTLY. + + COLS0, // Old Bulgarian uppercase YUS + COLS0, // Old Bulgarian lowercase YUS + COLS0, // Old Slovanic uppercase YUS MALYI + COLS0, // Old Slovanic uppercase YUS MALYI + COLS0, // KSI + COLS0, // ksi + COLS0, // PSI + COLS0, // psi + COLS0, // Old Russian uppercase FITA + COLS0, // Old Russian lowercase FITA + COLS0, // Old Russian uppercase IZHITSA + COLS0, // Old Russian lowercase IZHITSA + COLS0, // Russian uppercase A acute + COLS0, // Russian lowercase A acute + COLS10+8, // Russian uppercase E acute + COLS10+8, // Russian lowercase E acute + COLS0, // E acute + COLS0, // e acute + COLS10+14, // II acute + COLS10+14, // ii acute + COLS0, // I acute + COLS0, // i acute + COLS0, // YI acute + COLS0, // yi acute + COLS10+25, // O acute + COLS10+25, // o acute + COLS10+32, // U acute + COLS10+32, // u acute + COLS10+42, // YERI acute + COLS10+42, // YERI acute + COLS10+45, // REVERSED E acute + COLS10+45, // reversed e acute + COLS10+46, // YU acute + COLS10+46, // yu acute + COLS10+47, // YA acute + COLS10+47, // ya acute + COLS10, // A grave + COLS10, // a grave + COLS10+8, // E grave + COLS10+8, // e grave + COLS10+9, // YO grave + COLS10+9, // yo grave + COLS10+14, // I grave + COLS10+14, // i grave + COLS10+25, // O grave + COLS10+25, // o grave + COLS10+32, // U grave + COLS10+32, // u grave + COLS10+42, // YERI grave + COLS10+42, // yeri grave + COLS10+45, // REVERSED E grave + COLS10+45, // reversed e grave + COLS10+46, // IU (YU) grave + COLS10+46, // iu (yu) grave + COLS10+47, // ia (YA) grave + COLS10+47, // ia (ya) grave ******* [10,199] +}; + +/**************************************************************************** +Desc: The Hebrew characters are collated over the Russian characters. + Therefore sorting both Hebrew and Russian is impossible to do. +****************************************************************************/ +FLMBYTE flmHeb60TblA[ HEBTBL1LEN + 2] = +{ + 0, // Starting offset + HEBTBL1LEN, // Length of table + COLS10h+0, // Alef + COLS10h+1, // Bet + COLS10h+2, // Gimel + COLS10h+3, // Dalet + COLS10h+4, // He + COLS10h+5, // Vav + COLS10h+6, // Zayin + COLS10h+7, // Het + COLS10h+8, // Tet + COLS10h+9, // Yod + COLS10h+10, // Kaf (final) [9,10] + COLS10h+11, // Kaf + COLS10h+12, // Lamed + COLS10h+13, // Mem (final) + COLS10h+14, // Mem + COLS10h+15, // Nun (final) + COLS10h+16, // Nun + COLS10h+17, // Samekh + COLS10h+18, // Ayin + COLS10h+19, // Pe (final) + COLS10h+20, // Pe [9,20] + COLS10h+21, // Tsadi (final) + COLS10h+22, // Tsadi + COLS10h+23, // Qof + COLS10h+24, // Resh + COLS10h+25, // Shin + COLS10h+26 // Tav [9,26] +}; + +/**************************************************************************** +Desc: This is the ANCIENT HEBREW SCRIPT piece. The actual value will be + stored in the subcollation. This way we don't play + diacritic/subcollation games. +****************************************************************************/ +FLMBYTE flmHeb60TblB[ HEBTBL2LEN + 2] = +{ + 84, + HEBTBL2LEN, + COLS10h+0, // Alef Dagesh [9,84] + COLS10h+1, // Bet Dagesh + COLS10h+1, // Vez - looks like a bet + COLS10h+2, // Gimel Dagesh + COLS10h+3, // Dalet Dagesh + COLS10h+4, // He Dagesh + COLS10h+5, // Vav Dagesh [9,90] + COLS10h+5, // Vav Holem + COLS10h+6, // Zayin Dagesh + COLS10h+7, // Het Dagesh + COLS10h+8, // Tet Dagesh + COLS10h+9, // Yod Dagesh + COLS10h+9, // Yod Hiriq [9,96] - not on my list + COLS10h+11, // Kaf Dagesh + COLS10h+10, // Kaf Dagesh (final) + COLS10h+10, // Kaf Sheva (final) + COLS10h+10, // Kaf Tsere (final) [9,100] + COLS10h+10, // Kaf Segol (final) + COLS10h+10, // Kaf Patah (final) + COLS10h+10, // Kaf Qamats (final) + COLS10h+10, // Kaf Dagesh Qamats (final) + COLS10h+12, // Lamed Dagesh + COLS10h+14, // Mem Dagesh + COLS10h+16, // Nun Dagesh + COLS10h+15, // Nun Qamats (final) + COLS10h+17, // Samekh Dagesh + COLS10h+20, // Pe Dagesh [9,110] + COLS10h+20, // Fe - just guessing this is like Pe - was +21 + COLS10h+22, // Tsadi Dagesh + COLS10h+23, // Qof Dagesh + COLS10h+25, // Sin (with sin dot) + COLS10h+25, // Sin Dagesh (with sin dot) + COLS10h+25, // Shin + COLS10h+25, // Shin Dagesh + COLS10h+26 // Tav Dagesh [9,118] +}; + +/**************************************************************************** +Desc: The Arabic characters are collated OVER the Russian characters + Therefore sorting both Arabic and Russian in the same database + is not supported. + + Arabic starts with a bunch of accents/diacritic marks that are + Actually placed OVER a preceeding character. These accents are + ignored while sorting the first pass - when collation == COLS0. + + There are 4 possible states for all/most arabic characters: + ÚÙ - occurs as the only character in a word + ÄÙ - appears at the first of the word + ÄÄ - appears at the middle of a word + ÚÄ - appears at the end of the word + + Usually only the simple version of the letter is stored. + Therefore we should not have to worry about sub-collation + of these characters. + + The arabic characters with diacritics differ however. The alef has + sub-collation values to sort correctly. There is not any more room + to add more collation values. Some chars in CS14 are combined when + urdu, pashto and sindhi characters overlap. +****************************************************************************/ +FLMBYTE flmAr160Tbl[ AR1TBLLEN + 2] = +{ + 38, // Starting offset + AR1TBLLEN, // Length of table + COLLS+2, // , comma + COLLS+3, // : colon + COLLS+7, // ? question mark + COLS4+2, // * asterick + COLS6, // % percent + COLS9+41, // >> alphabetic - end of list) + COLS9+40, // << alphabetic - end of list) + COLS2, // ( + COLS2+1, // ) + COLS8+1, // ÚÙ One + COLS8+2, // ÚÙ Two + COLS8+3, // ÚÙ Three + COLS8+4, // ÚÙ Four + COLS8+5, // ÚÙ Five + COLS8+6, // ÚÙ Six + COLS8+7, // ÚÙ Seven + COLS8+8, // ÚÙ Eight + COLS8+9, // ÚÙ Nine + COLS8+0, // ÚÙ Zero + COLS8+2, // ÚÙ Two (Handwritten) + COLS10a+1, // ÚÙ alif + COLS10a+1, // ÚÄ alif + COLS10a+2, // ÚÙ ba + COLS10a+2, // ÄÙ ba + COLS10a+2, // ÄÄ ba + COLS10a+2, // ÚÄ ba + COLS10a+6, // ÚÙ ta + COLS10a+6, // ÄÙ ta + COLS10a+6, // ÄÄ ta + COLS10a+6, // ÚÄ ta + COLS10a+8, // ÚÙ tha + COLS10a+8, // ÄÙ tha + COLS10a+8, // ÄÄ tha + COLS10a+8, // ÚÄ tha + COLS10a+12, // ÚÙ jiim + COLS10a+12, // ÄÙ jiim + COLS10a+12, // ÄÄ jiim + COLS10a+12, // ÚÄ jiim + COLS10a+16, // ÚÙ Ha + COLS10a+16, // ÄÙ Ha + COLS10a+16, // ÄÄ Ha + COLS10a+16, // ÚÄ Ha + COLS10a+17, // ÚÙ kha + COLS10a+17, // ÄÙ kha + COLS10a+17, // ÄÄ kha + COLS10a+17, // ÚÄ kha + COLS10a+20, // ÚÙ dal + COLS10a+20, // ÚÄ dal + COLS10a+22, // ÚÙ dhal + COLS10a+22, // ÚÄ dhal + COLS10a+27, // ÚÙ ra + COLS10a+27, // ÚÄ ra + COLS10a+29, // ÚÙ ziin + COLS10a+29, // ÚÄ ziin + COLS10a+31, // ÚÙ siin + COLS10a+31, // ÄÙ siin + COLS10a+31, // ÄÄ siin + COLS10a+31, // ÚÄ siin + COLS10a+32, // ÚÙ shiin + COLS10a+32, // ÄÙ shiin + COLS10a+32, // ÄÄ shiin + COLS10a+32, // ÚÄ shiin + COLS10a+34, // ÚÙ Sad + COLS10a+34, // ÄÙ Sad + COLS10a+34, // ÄÄ Sad + COLS10a+34, // ÚÄ Sad + COLS10a+35, // ÚÙ Dad + COLS10a+35, // ÄÙ Dad + COLS10a+35, // ÄÄ Dad + COLS10a+35, // ÚÄ Dad + COLS10a+36, // ÚÙ Ta + COLS10a+36, // ÄÙ Ta + COLS10a+36, // ÄÄ Ta + COLS10a+36, // ÚÄ Ta + COLS10a+37, // ÚÙ Za + COLS10a+37, // ÄÙ Za + COLS10a+37, // ÄÄ Za + COLS10a+37, // ÚÄ Za + COLS10a+38, // ÚÙ 'ain + COLS10a+38, // ÄÙ 'ain + COLS10a+38, // ÄÄ 'ain + COLS10a+38, // ÚÄ 'ain + COLS10a+39, // ÚÙ ghain + COLS10a+39, // ÄÙ ghain + COLS10a+39, // ÄÄ ghain + COLS10a+39, // ÚÄ ghain + COLS10a+40, // ÚÙ fa + COLS10a+40, // ÄÙ fa + COLS10a+40, // ÄÄ fa + COLS10a+40, // ÚÄ fa + COLS10a+42, // ÚÙ Qaf + COLS10a+42, // ÄÙ Qaf + COLS10a+42, // ÄÄ Qaf + COLS10a+42, // ÚÄ Qaf + COLS10a+43, // ÚÙ kaf + COLS10a+43, // ÄÙ kaf + COLS10a+43, // ÄÄ kaf + COLS10a+43, // ÚÄ kaf + COLS10a+46, // ÚÙ lam + COLS10a+46, // ÄÙ lam + COLS10a+46, // ÄÄ lam + COLS10a+46, // ÚÄ lam + COLS10a+47, // ÚÙ miim + COLS10a+47, // ÄÙ miim + COLS10a+47, // ÄÄ miim + COLS10a+47, // ÚÄ miim + COLS10a+48, // ÚÙ nuun + COLS10a+48, // ÄÙ nuun + COLS10a+48, // ÄÄ nuun + COLS10a+48, // ÚÄ nuun + COLS10a+49, // ÚÙ ha + COLS10a+49, // ÄÙ ha + COLS10a+49, // ÄÄ ha + COLS10a+49, // ÚÄ ha + COLS10a+6, // ÚÙ ta marbuuTah + COLS10a+6, // ÚÄ ta marbuuTah + COLS10a+50, // ÚÙ waw + COLS10a+50, // ÚÄ waw + COLS10a+53, // ÚÙ ya + COLS10a+53, // ÄÙ ya + COLS10a+53, // ÄÄ ya + COLS10a+53, // ÚÄ ya + COLS10a+52, // ÚÙ alif maqSuurah + COLS10a+52, // ÄÙ ya maqSuurah? + COLS10a+52, // ÄÄ ya maqSuurah? + COLS10a+52, // ÚÄ alif maqSuurah + COLS10a+0, // ÚÙ hamzah accent - never appears alone + + // Store the sub-collation as the actual + // character value from this point on + + COLS10a+1, // ÚÙ alif hamzah + COLS10a+1, // ÚÄ alif hamzah + COLS10a+1, // ÚÙ hamzah-under-alif + COLS10a+1, // ÚÄ hamzah-under-alif + COLS10a+1, // ÚÙ waw hamzah + COLS10a+1, // ÚÄ waw hamzah + COLS10a+1, // ÚÙ ya hamzah + COLS10a+1, // ÄÙ ya hamzah + COLS10a+1, // ÄÄ ya hamzah + COLS10a+1, // ÚÄ ya hamzah + COLS10a+1, // ÚÙ alif fatHataan + COLS10a+1, // ÚÄ alif fatHataan + COLS10a+1, // ÚÙ alif maddah + COLS10a+1, // ÚÄ alif maddah + COLS10a+1, // ÚÙ alif waSlah + COLS10a+1, // ÚÄ alif waSlah (final) + + // LIGATURES + // Should NEVER be stored so will not worry + // about breaking up into pieces for collation. + // NOTE: + // Let's store the "Lam" collation value (+42) + // below and in the sub-collation store the + // actual character. This will sort real close. + // The best implementation is to + // break up ligatures into its base pieces. + + COLS10a+46, // ÚÙ lamalif + COLS10a+46, // ÚÄ lamalif + COLS10a+46, // ÚÙ lamalif hamzah + COLS10a+46, // ÚÄ lamalif hamzah + COLS10a+46, // ÚÙ hamzah-under-lamalif + COLS10a+46, // ÚÄ hamzah-under-lamalif + COLS10a+46, // ÚÙ lamalif fatHataan + COLS10a+46, // ÚÄ lamalif fatHataan + COLS10a+46, // ÚÙ lamalif maddah + COLS10a+46, // ÚÄ lamalif maddah + COLS10a+46, // ÚÙ lamalif waSlah + COLS10a+46, // ÚÄ lamalif waSlah + COLS10a+46, // ÚÙ Allah - khaDalAlif + COLS0_ARABIC, // ÄÄ taTwiil + COLS0_ARABIC // ÄÄ taTwiil +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmAlefSubColTbl[] = +{ + 1, // ÚÙ alif hamzah + 1, // ÚÄ alif hamzah + 3, // ÚÙ hamzah-under-alif + 3, // ÚÄ hamzah-under-alif + 2, // ÚÙ waw hamzah + 2, // ÚÄ waw hamzah + 4, // ÚÙ ya hamzah + 4, // ÄÙ ya hamzah + 4, // ÄÄ ya hamzah + 4, // ÚÄ ya hamzah + 5, // ÚÙ alif fatHataan + 5, // ÚÄ alif fatHataan + 0, // ÚÙ alif maddah + 0, // ÚÄ alif maddah + 6, // ÚÙ alif waSlah + 6 // ÚÄ alif waSlah (final) +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmAr260Tbl[ AR2TBLLEN + 2] = +{ + 41, // Starting offset + AR2TBLLEN, // Length of table + COLS8+4, // Farsi and Urdu Four + COLS8+4, // Urdu Four + COLS8+5, // Farsi and Urdu Five + COLS8+6, // Farsi Six + COLS8+6, // Farsi and Urdu Six + COLS8+7, // Urdu Seven + COLS8+8, // Urdu Eight + COLS10a+3, // Sindhi bb - baa /w 2 dots below (67b) + COLS10a+3, + COLS10a+3, + COLS10a+3, + COLS10a+4, // Sindhi bh - baa /w 4 dots below (680) + COLS10a+4, + COLS10a+4, + COLS10a+4, + COLS10a+5, // Malay, Kurdish, Pashto, Farsi, Sindhi, and Urdu p + COLS10a+5, // =peh - taa /w 3 dots below (67e) + COLS10a+5, + COLS10a+5, + COLS10a+7, // Urdu T - taa /w small tah + COLS10a+7, + COLS10a+7, + COLS10a+7, + COLS10a+7, // Pashto T - taa /w ring (forced to combine) + COLS10a+7, + COLS10a+7, + COLS10a+7, + COLS10a+9, // Sindhi th - taa /w 4 dots above (67f) + COLS10a+9, + COLS10a+9, + COLS10a+9, + COLS10a+10, // Sindhi Tr - taa /w 3 dots above (67d) + COLS10a+10, + COLS10a+10, + COLS10a+10, + COLS10a+11, // Sindhi Th - taa /w 2 dots above (67a) + COLS10a+11, + COLS10a+11, + COLS10a+11, + COLS10a+13, // Sindhi jj - haa /w 2 middle dots verticle (684) + COLS10a+13, + COLS10a+13, + COLS10a+13, + COLS10a+14, // Sindhi ny - haa /w 2 middle dots (683) + COLS10a+14, + COLS10a+14, + COLS10a+14, + COLS10a+15, // Malay, Kurdish, Pashto, Farsi, Sindhi, and Urdu ch + COLS10a+15, // =tcheh (686) + COLS10a+15, + COLS10a+15, + COLS10a+15, // Sindhi chh - haa /w middle 4 dots (687) + COLS10a+15, // forced to combine + COLS10a+15, + COLS10a+15, + COLS10a+18, // Pashto ts - haa /w 3 dots above (685) + COLS10a+18, + COLS10a+18, + COLS10a+18, + COLS10a+19, // Pashto dz - hamzah on haa (681) + COLS10a+19, + COLS10a+19, + COLS10a+19, + COLS10a+21, // Urdu D - dal /w small tah (688) + COLS10a+21, + COLS10a+21, // Pashto D - dal /w ring (689) forced to combine + COLS10a+21, + COLS10a+23, // Sindhi dh - dal /w 2 dots above (68c) + COLS10a+23, + COLS10a+24, // Sindhi D - dal /w 3 dots above (68e) + COLS10a+24, + COLS10a+25, // Sindhi Dr - dal /w dot below (68a) + COLS10a+25, + COLS10a+26, // Sindhi Dh - dal /w 2 dots below (68d) + COLS10a+26, + COLS10a+28, // Pashto r - ra /w ring (693) + COLS10a+28, + COLS10a+28, // Urdu R - ra /w small tah (691) forced to combine + COLS10a+28, + COLS10a+28, // Sindhi r - ra /w 4 dots above (699) forced to combine + COLS10a+28, + COLS10a+27, // Kurdish rolled r - ra /w 'v' below (695) + COLS10a+27, + COLS10a+27, + COLS10a+27, + COLS10a+30, // Kurdish, Pashto, Farsi, Sindhi, and Urdu Z + COLS10a+30, // = jeh - ra /w 3 dots above (698) + COLS10a+30, // Pashto zz - ra /w dot below & dot above (696) + COLS10a+30, // forced to combine + COLS10a+30, // Pashto g - not in unicode! - forced to combine + COLS10a+30, + COLS10a+33, // Pashto x - seen dot below & above (69a) + COLS10a+33, + COLS10a+33, + COLS10a+33, + COLS10a+39, // Malay ng - old maly ain /w 3 dots above (6a0) + COLS10a+39, // forced to combine + COLS10a+39, + COLS10a+39, + COLS10a+41, // Malay p, Kurdish v - Farsi ? - fa /w 3 dots above + COLS10a+41, // = veh - means foreign words (6a4) + COLS10a+41, + COLS10a+41, + COLS10a+41, // Sindhi ph - fa /w 4 dots above (6a6) forced to combine + COLS10a+41, + COLS10a+41, + COLS10a+41, + COLS10a+43, // Misc k - open caf (6a9) + COLS10a+43, + COLS10a+43, + COLS10a+43, + COLS10a+43, // misc k - no unicode - forced to combine + COLS10a+43, + COLS10a+43, + COLS10a+43, + COLS10a+43, // Sindhi k - swash caf (various) (6aa) -forced to combine + COLS10a+43, + COLS10a+43, + COLS10a+43, + COLS10a+44, // Persian/Urdu g - gaf (6af) + COLS10a+44, + COLS10a+44, + COLS10a+44, + COLS10a+44, // Persian/Urdu g - no unicode + COLS10a+44, + COLS10a+44, + COLS10a+44, + COLS10a+44, // malay g - gaf /w ring (6b0) + COLS10a+44, + COLS10a+44, + COLS10a+44, + COLS10a+44, // Sindhi ng - gaf /w 2 dots above (6ba) + COLS10a+44, // forced to combine ng only + COLS10a+44, + COLS10a+44, + COLS10a+45, // Sindhi gg - gaf /w 2 dots vertical below (6b3) + COLS10a+45, + COLS10a+45, + COLS10a+45, + COLS10a+46, // Kurdish velar l - lam /w small v (6b5) + COLS10a+46, + COLS10a+46, + COLS10a+46, + COLS10a+46, // Kurdish Lamalif with diacritic - no unicode + COLS10a+46, + COLS10a+48, // Urdu n - dotless noon (6ba) + COLS10a+48, + COLS10a+48, + COLS10a+48, + COLS10a+48, // Pashto N - noon /w ring (6bc) - forced to combine + COLS10a+48, + COLS10a+48, + COLS10a+48, + COLS10a+48, // Sindhi N - dotless noon/w small tah (6bb) + COLS10a+48, // forced to combine + COLS10a+48, + COLS10a+48, + COLS10a+50, // Kurdish o - waw /w small v (6c6) + COLS10a+50, + COLS10a+50, // Kurdish o - waw /w bar above (6c5) + COLS10a+50, + COLS10a+50, // Kurdish o - waw /w 2 dots above (6ca) + COLS10a+50, + COLS10a+51, // Urdu h - no unicode + COLS10a+51, + COLS10a+51, + COLS10a+51, + COLS10a+52, // Kurdish ˆ - ya /w small v (6ce) + COLS10a+52, + COLS10a+52, + COLS10a+52, + COLS10a+54, // Urdu y - ya barree (6d2) + COLS10a+54, + COLS10a+54, // Malay ny - ya /w 3 dots below (6d1) forced to combine + COLS10a+54, + COLS10a+54, + COLS10a+54, + COLS10a+51, // Farsi hamzah - hamzah on ha (6c0) forced to combine + COLS10a+51 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE flmAr2BitTbl[] = +{ + 0xF0, // 64..71 + 0x00, // 72..79 + 0x00, // 80..87 + 0x0F, // 88..95 - 92..95 + 0x00, // 96..103 + 0x00, // 104..111 + 0x03, // 112..119 + 0xFC, // 120..127 + 0xFF, // 128..135 + 0xF0, // 136..143 - 136..139 + 0xFF, // 144..151 - 144..147, 148..159 + 0xFF, // 152..159 + 0x0F, // 160..167 - 164..175 + 0xFF, // 168..175 + 0x0F, // 176..183 - 180..185 + 0xFF, // 184..191 - 186..197 + 0xFF, // 192..199 - 198..203 + 0xFF, // 200..207 - 204..207 + 0xF3, // 208..215 - 208..211 , 214..217 + 0xF0 // 216..219 - 218..219 +}; + +/**************************************************************************** +Desc: This table describes and gives addresses for collating + character sets. Each line corresponds to a character set. +****************************************************************************/ +TBL_B_TO_BP flmCol60Tbl[] = +{ + {CHSASCI, flmAsc60Tbl}, // ascii - " " - "~" + {CHSMUL1, flmMn60Tbl}, // multinational + {CHSSYM1, flmSym60Tbl}, // symbols + {CHSGREK, flmGrk60Tbl}, // Greek + {CHSCYR, flmCyrl60Tbl}, // Cyrillic - Russian + {0xFF, 0} // table terminator +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +TBL_B_TO_BP flmHebArabicCol60Tbl[] = +{ + {CHSASCI, flmAsc60Tbl}, // ascii - " " - "~" + {CHSMUL1, flmMn60Tbl}, // multinational + {CHSSYM1, flmSym60Tbl}, // symbols + {CHSGREK, flmGrk60Tbl}, // Greek + {CHSHEB, flmHeb60TblA}, // Hebrew + {CHSHEB, flmHeb60TblB}, // Hebrew + {CHSARB1, flmAr160Tbl}, // Arabic Set 1 + {CHSARB2, flmAr260Tbl}, // Arabic Set 2 + {0xff, 0} // table terminator +}; + +/**************************************************************************** +Desc: The diacritical to collated table translates the first 26 characters + of character set #1 into a 5 bit value for "correct" sorting + sequence for that diacritical (DCV) - diacritic collated value. + + The attempt here is to convert the collated character value + along with the DCV to form the original character. + + The diacriticals are in an order to fit the most languages. + Czech, Swedish, and Finnish will have to manual reposition the + ring above (assign it a value greater then the umlaut) + + This table is index by the diacritical value. +****************************************************************************/ +FLMBYTE flmDia60Tbl[] = +{ + 2, // grave offset = 0 + 16, // centerd offset = 1 + 7, // tilde offset = 2 + 4, // circum offset = 3 + 12, // crossb offset = 4 + 10, // slash offset = 5 + 1, // acute offset = 6 + 6, // umlaut offset = 7 + // In SU, SV and CZ will = 9 + 17, // macron offset = 8 + 18, // aposab offset = 9 + 19, // aposbes offset = 10 + 20, // aposba offset = 11 + 21, // aposbc offset = 12 + 22, // abosbl offset = 13 + 8, // ring offset = 14 + 13, // dota offset = 15 + 23, // dacute offset = 16 + 11, // cedilla offset = 17 + 14, // ogonek offset = 18 + 5, // caron offset = 19 + 15, // stroke offset = 20 + 24, // bara offset = 21 + 3, // breve offset = 22 + 0, // dbls offset = 23 sorts as 'ss' + 25, // dotlesi offset = 24 + 26 // dotlesj offset = 25 +}; + +/**************************************************************************** +Desc: Map special chars in CharSet (x24) to collation values +****************************************************************************/ +BYTE_WORD_TBL flmCh24ColTbl[] = +{ + {1, COLLS + 2}, // comma + {2, COLLS + 1}, // maru + {5, COLS_ASIAN_MARKS + 2}, // chuuten + {10, COLS_ASIAN_MARKS}, // dakuten + {11, COLS_ASIAN_MARKS + 1}, // handakuten + {43, COLS2 + 2}, // angled brackets + {44, COLS2 + 3}, + {49, COLS2 + 2}, // pointy brackets + {50, COLS2 + 3}, + {51, COLS2 + 2}, // double pointy brackets + {52, COLS2 + 3}, + {53, COLS1}, // Japanese quotes + {54, COLS1}, + {55, COLS1}, // hollow Japanese quotes + {56, COLS1}, + {57, COLS2 + 2}, // filled rounded brackets + {58, COLS2 + 3} +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 colToWPChr[ COLS11 - COLLS] = +{ + 0x20, // colls - + 0x2e, // colls+1 - . + 0x2c, // colls+2 - , + 0x3a, // colls+3 - : + 0x3b, // colls+4 - ; + 0x21, // colls+5 - ! + 0, // colls+6 - NO VALUE + 0x3f, // colls+7 - ? + 0, // colls+8 - NO VALUE + 0x22, // cols1 - " + 0x27, // cols1+1 - ' + 0x60, // cols1+2 - ` + 0, // cols1+3 - NO VALUE + 0, // cols1+4 - NO VALUE + 0x28, // cols2 - ( + 0x29, // cols2+1 - ) + 0x5b, // cols2+2 - japanese angle brackets + 0x5d, // cols2+3 - japanese angle brackets + 0x7b, // cols2+4 - { + 0x7d, // cols2+5 - } + 0x24, // cols3 - $ + 0x413, // cols3+1 - cent + 0x40b, // cols3+2 - pound + 0x40c, // cols3+3 - yen + 0x40d, // cols3+4 - pacetes + 0x40e, // cols3+5 - floren + 0x2b, // cols4 - + + 0x2d, // cols4+1 - - + 0x2a, // cols4+2 - * + 0x2f, // cols4+3 - / + 0x5e, // cols4+4 - ^ + 0, // cols4+5 - NO VALUE + 0, // cols4+6 - NO VALUE + 0, // cols4+7 - NO VALUE + 0x3c, // cols5 - < + 0, // cols5+1 - NO VALUE + 0x3d, // cols5+2 - = + 0, // cols5+3 - NO VALUE + 0x3e, // cols5+4 - > + 0, // cols5+5 - NO VALUE + 0, // cols5+6 - NO VALUE + 0, // cols5+7 - NO VALUE + 0, // cols5+8 - NO VALUE + 0, // cols5+9 - NO VALUE + 0, // cols5+10 - NO VALUE + 0, // cols5+11 - NO VALUE + 0, // cols5+12 - NO VALUE + 0, // cols5+13 - NO VALUE + 0x25, // cols6 - % + 0x23, // cols6+1 - # + 0x26, // cols6+2 - & + 0x40, // cols6+3 - @ + 0x5c, // cols6+4 - backslash + 0x5f, // cols6+5 - _ + 0x7c, // cols6+6 - | + 0x7e, // cols6+7 - ~ + 0, // cols6+8 - NO VALUE + 0, // cols6+9 - NO VALUE + 0, // cols6+10 - NO VALUE + 0, // cols6+11 - NO VALUE + 0, // cols6+12 - NO VALUE + 0x800, // cols7 - Uppercase Alpha + 0x802, // cols7+1 - Uppercase Beta + 0x806, // cols7+2 - Uppercase Gamma + 0x808, // cols7+3 - Uppercase Delta + 0x80a, // cols7+4 - Uppercase Epsilon + 0x80c, // cols7+5 - Uppercase Zeta + 0x80e, // cols7+6 - Uppercase Eta + 0x810, // cols7+7 - Uppercase Theta + 0x812, // cols7+8 - Uppercase Iota + 0x814, // cols7+9 - Uppercase Kappa + 0x816, // cols7+10 - Uppercase Lambda + 0x818, // cols7+11 - Uppercase Mu + 0x81a, // cols7+12 - Uppercase Nu + 0x81c, // cols7+13 - Uppercase Xi + 0x81e, // cols7+14 - Uppercase Omicron + 0x820, // cols7+15 - Uppercase Pi + 0x822, // cols7+16 - Uppercase Rho + 0x824, // cols7+17 - Uppercase Sigma + 0x828, // cols7+18 - Uppercase Tau + 0x82a, // cols7+19 - Uppercase Upsilon + 0x82c, // cols7+20 - Uppercase Phi + 0x82e, // cols7+21 - Uppercase Chi + 0x830, // cols7+22 - Uppercase Psi + 0x832, // cols7+23 - Uppercase Omega + 0, // cols7+24 - NO VALUE + 0x30, // cols8 - 0 + 0x31, // cols8+1 - 1 + 0x32, // cols8+2 - 2 + 0x33, // cols8+3 - 3 + 0x34, // cols8+4 - 4 + 0x35, // cols8+5 - 5 + 0x36, // cols8+6 - 6 + 0x37, // cols8+7 - 7 + 0x38, // cols8+8 - 8 + 0x39, // cols8+9 - 9 + 0x41, // cols9 - A + 0x124, // cols9+1 - AE digraph + 0x42, // cols9+2 - B + 0x43, // cols9+3 - C + 0xffff, // cols9+4 - CH in spanish + 0x162, // cols9+5 - Holder for C caron in Czech + 0x44, // cols9+6 - D + 0x45, // cols9+7 - E + 0x46, // cols9+8 - F + 0x47, // cols9+9 - G + 0x48, // cols9+10 - H + 0xffff, // cols9+11 - CH in czech or dotless i in turkish + 0x49, // cols9+12 - I + 0x18a, // cols9+13 - IJ Digraph + 0x4a, // cols9+14 - J + 0x4b, // cols9+15 - K + 0x4c, // cols9+16 - L + 0xffff, // cols9+17 - LL in spanish + 0x4d, // cols9+18 - M + 0x4e, // cols9+19 - N + 0x138, // cols9+20 - N Tilde + 0x4f, // cols9+21 - O + 0x1a6, // cols9+22 - OE digraph + 0x50, // cols9+23 - P + 0x51, // cols9+24 - Q + 0x52, // cols9+25 - R + 0x1aa, // cols9+26 - Holder for R caron in Czech + 0x53, // cols9+27 - S + 0x1b0, // cols9+28 - Holder for S caron in Czech + 0x54, // cols9+29 - T + 0x55, // cols9+30 - U + 0x56, // cols9+31 - V + 0x57, // cols9+32 - W + 0x58, // cols9+33 - X + 0x59, // cols9+34 - Y + 0x5a, // cols9+35 - Z + 0x1ce, // cols9+36 - Holder for Z caron in Czech + 0x158, // cols9+37 - Uppercase Thorn + 0, // cols9+38 - ??? + 0, // cols9+39 - ??? + 0x5b, // cols9+40 - [ (note: alphabetic - end of list) + 0x5d, // cols9+41 - ] (note: alphabetic - end of list) + 0x124, // cols9+42 - AE diagraph - DK + 0x124, // cols9+43 - AE diagraph - NO + 0x122, // cols9+44 - A ring - SW + 0x11E, // cols9+45 - A diaeresis - DK + 0x124, // cols9+46 - AE diagraph - IC + 0x150, // cols9+47 - O slash - NO + 0x11e, // cols9+48 - A diaeresis - SW + 0x150, // cols9+49 - O slash - DK + 0x13E, // cols9+50 - O Diaeresis - IC + 0x122, // cols9+51 - A ring - NO + 0x13E, // cols9+52 - O Diaeresis - SW + 0x13E, // cols9+53 - O Diaeresis - DK + 0x150, // cols9+54 - O slash - IC + 0x122, // cols9+55 - A ring - DK + 0x124, // cols9+56 - AE diagraph future + 0x13E, // cols9+57 - O Diaeresis future + 0x150, // cols9+58 - O slash future + 0, // cols9+59 - NOT USED future + 0xA00, // cols10 - Russian A + 0xA02, // cols10+1 - Russian BE + 0xA04, // cols10+2 - Russian VE + 0xA06, // cols10+3 - Russian GHE + 0xA46, // cols10+4 - Ukrainian HARD G + 0xA08, // cols10+5 - Russian DE + 0xA4a, // cols10+6 - Serbian SOFT DJ + 0xA44, // cols10+7 - Macedonian SOFT DJ + 0xA0a, // cols10+8 - Russian E + 0xA0c, // cols10+9 - Russian YO + 0xA4e, // cols10+10 - Ukrainian YE + 0xA0e, // cols10+11 - Russian ZHE + 0xA10, // cols10+12 - Russian ZE + 0xA52, // cols10+13 - Macedonian ZELO + 0xA12, // cols10+14 - Russian I + 0xA58, // cols10+15 - Ukrainian I + 0xA5a, // cols10+16 - Ukrainian I with Two dots + 0xA14, // cols10+17 - Russian SHORT I + 0xA5e, // cols10+18 - Serbian--Macedonian JE + 0xA16, // cols10+19 - Russian KA + 0xA18, // cols10+20 - Russian EL + 0xA68, // cols10+21 - Serbian--Macedonian SOFT L + 0xA1a, // cols10+22 - Russian EM + 0xA1c, // cols10+23 - Russian EN + 0xA6c, // cols10+24 - Serbian--Macedonian SOFT N + 0xA1e, // cols10+25 - Russian O + 0xA20, // cols10+26 - Russian PE + 0xA22, // cols10+27 - Russian ER + 0xA24, // cols10+28 - Russian ES + 0xA26, // cols10+29 - Russian TE + 0xA72, // cols10+30 - Serbian SOFT T + 0xA60, // cols10+31 - Macedonian SOFT K + 0xA28, // cols10+32 - Russian U + 0xA74, // cols10+33 - Byelorussian SHORT U + 0xA2a, // cols10+34 - Russian EF + 0xA2c, // cols10+35 - Russian HA + 0xA2e, // cols10+36 - Russian TSE + 0xA30, // cols10+37 - Russian CHE + 0xA86, // cols10+38 - Serbian HARD DJ + 0xA32, // cols10+39 - Russian SHA + 0xA34, // cols10+40 - Russian SHCHA + 0xA36, // cols10+41 - Russian ER + 0xA38, // cols10+42 - Russian ERY + 0xA3a, // cols10+43 - Russian SOFT SIGN + 0xA8e, // cols10+44 - Old Russian YAT + 0xA3c, // cols10+45 - Russian uppercase REVERSE E + 0xA3e, // cols10+46 - Russian YU + 0xA40, // cols10+47 - Russian YA + 0xA3a, // cols10+48 - Russian SOFT SIGN - UKRAIN ONLY + 0 // cols10+49 - future +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 HebArabColToWPChr[ ] = +{ + 0x0D00 +164, // hamzah + 0x0D00 + 58, // [13,177] alef maddah + 0x0D00 + 60, // baa + 0x0E00 + 48, // Sindhi bb + 0x0E00 + 52, // Sindhi bh + 0x0E00 + 56, // Misc p = peh + 0x0D00 +152, // taa marbuuTah + 0x0E00 + 60, // Urdu T + 0x0D00 + 68, // thaa + 0x0E00 + 68, // Sindhi th + 0x0E00 + 72, // Sindhi tr + 0x0E00 + 76, // Sindhi Th + 0x0D00 + 72, // jiim - jeem + 0x0E00 + 80, // Sindhi jj + 0x0E00 + 84, // Sindhi ny + 0x0E00 + 88, // Misc ch + 0x0D00 + 76, // Haa + 0x0D00 + 80, // khaa + 0x0E00 + 96, // Pashto ts + 0x0E00 +100, // Pashto dz + 0x0D00 + 84, // dal + 0x0E00 +104, // Urdu D + 0x0D00 + 86, // thal + 0x0E00 +108, // Sindhi dh + 0x0E00 +110, // Sindhi D + 0x0E00 +112, // Sindhi Dr + 0x0E00 +114, // Sindhi Dh + 0x0D00 + 88, // ra + 0x0E00 +116, // Pashto r + 0x0D00 + 90, // zain + 0x0E00 +126, // Mizc Z + 0x0D00 + 92, // seen + 0x0D00 + 96, // sheen + 0x0E00 +132, // Pashto x + 0x0D00 +100, // Sad + 0x0D00 +104, // Dad + 0x0D00 +108, // Tah + 0x0D00 +112, // Za (dhah) + 0x0D00 +116, // 'ain + 0x0D00 +120, // ghain + 0x0D00 +124, // fa + 0x0E00 +140, // Malay p, kurdish v = veh + 0x0D00 +128, // Qaf + 0x0D00 +132, // kaf (caf) + 0x0E00 +160, // Persian/Urdu gaf + 0x0E00 +176, // Singhi gg + 0x0D00 +136, // lam - all ligature variants + 0x0D00 +140, // meem + 0x0D00 +144, // noon + 0x0D00 +148, // ha - arabic language only + 0x0D00 +154, // waw + 0x0D00 +148, // ha - non-arabic language + 0x0D00 +160, // alef maqsurah + 0x0D00 +156, // ya + 0x0E00 +212 // Urdu ya barree +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 ArabSubColToWPChr[] = +{ + 0x0D00 +177, // Alef maddah + 0x0D00 +165, // Alef Hamzah + 0x0D00 +169, // Waw hamzah + 0x0D00 +167, // Hamzah under alef + 0x0D00 +171, // ya hamzah + 0x0D00 +175, // alef fathattan + 0x0D00 +179, // alef waslah + 0x0D00 + 58, // alef + 0x0D00 + 64 // taa - after taa marbuuTah +}; + +/**************************************************************************** +Desc: Turns a collated diacritic value into the original diacritic value +****************************************************************************/ +FLMBYTE ml1_COLtoD[ 27] = +{ + 23, // dbls sort value = 0 sorts as 'ss' + 6, // acute sort value = 1 + 0, // grave sort value = 2 + 22, // breve sort value = 3 + 3, // circum sort value = 4 + 19, // caron sort value = 5 + 7, // umlaut sort value = 6 + 2, // tilde sort value = 7 + 14, // ring sort value = 8 + 7, // umlaut in SU, SV and CZ after ring = 9 + 5, // slash sort value = 10 + 17, // cedilla sort value = 11 + 4, // crossb sort value = 12 + 15, // dota sort value = 13 + 18, // ogonek sort value = 14 + 20, // stroke sort value = 15 + 1, // centerd sort value = 16 + 8, // macron sort value = 17 + 9, // aposab sort value = 18 + 10, // aposbes sort value = 19 + 11, // aposba sort value = 20 + 12, // aposbc sort value = 21 + 13, // abosbl sort value = 22 + 16, // dacute sort value = 23 + 21, // bara sort value = 24 + 24, // dotlesi sort value = 25 + 25 // dotlesj sort value = 26 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 flmIndexi[] = +{ + 0, + 11, + 14, + 15, + 17, + 18, + 19, + 21, + 22, + 23, + 24, + 25, + 26, + 35, + 59 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMUINT16 flmIndexj[] = +{ + CA_LANG, // Catalan + CF_LANG, // Canadian French + CZ_LANG, // Czech + SL_LANG, // Slovak + DE_LANG, // German + SD_LANG, // Swiss German + ES_LANG, // Spanish (Spain) + FR_LANG, // French + _NL_LANG, // Netherlands + 0xFFFF, // DK_LANG, Danish + 0xFFFF, // NO_LANG, Norwegian + 0x0063, // c + 0x006c, // l + 0x0197, // l with center dot + 0x0063, // c + 0x0125, // ae digraph + 0x01a7, // oe digraph + 0x0068, // h + 0x0068, // h + 0x006c, // l + 0x0101, // center dot alone + 0x006c, // l + 0x0117, // á (for German) + 0x018b, // ij digraph + 0x0000, // was 'a' - will no longer map 'aa' to a-ring + 0x0000, // was 'a' + CZ_LANG, + DK_LANG, + NO_LANG, + SL_LANG, + TK_LANG, + SU_LANG, + IS_LANG, + SV_LANG, + YK_LANG, + 0x011e, // A diaeresis + 0x011f, // a diaeresis + 0x0122, // A ring + 0x0123, // a ring + 0x0124, // AE diagraph + 0x0125, // ae diagraph + 0x013e, // O diaeresis + 0x013f, // o diaeresis + 0x0146, // U diaeresis + 0x0147, // u diaeresis + 0x0150, // O slash + 0x0151, // o slash + 0x0A3a, // CYRILLIC SOFT SIGN + 0x0A3b, // CYRILLIC soft sign + 0x01ee, // dotless i - turkish + 0x01ef, // dotless I - turkish + 0x0162, // C Hacek/caron + 0x0163, // c Hacek/caron + 0x01aa, // R Hacek/caron + 0x01ab, // r Hacek/caron + 0x01b0, // S Hacek/caron + 0x01b1, // s Hacek/caron + 0x01ce, // Z Hacek/caron + 0x01cf, // z Hacek/caron +}; + +/**************************************************************************** +Desc: Kana subcollation values + BIT 0: set if large char + BIT 1: set if voiced + BIT 2: set if half voiced +Notes: To save space should be nibbles +IMPORTANT: The '1' entries that do not have a matching '0' entry have been + changed to zero to save space in the subcollation area. +****************************************************************************/ +FLMBYTE flmKanaSubColTbl[] = +{ + 0,1,0,1,0,1,0,1,0,1, // a A i I u U e E o O + 1,3,0,3,0,3,1,3,0,3, // KA GA KI GI KU GU KE GE KO GO + 0,3,0,3,0,3,0,3,0,3, // SA ZA SHI JI SU ZU SE ZE SO ZO + 0,3,0,3,0,1,3,0,3,0,3, // TA DA CHI JI tsu TSU ZU TE DE TO DO + 0,0,0,0,0, // NA NI NU NE NO + 0,3,5,0,3,5,0,3,5, // HA BA PA HI BI PI FU BU PU + 0,3,5,0,3,5, // HE BE PE HO BO PO + 0,0,0,0,0, // MA MI MU ME MO + 0,1,0,1,0,1, // ya YA yu YU yo YO + 0,0,0,0,0, // RA RI RU RE RO + 0,1,0,0,0, // wa WA WI WE WO + 0,3,0,0 // N VU ka ke +}; + +/**************************************************************************** +Desc: Map KataKana (CharSet x26) to collation values. + Kana collating values are two byte values where the high byte is 0x01. +****************************************************************************/ +FLMBYTE KanaColTbl[] = +{ + 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, // a A i I u U e E o O + 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, // KA GA KI GI KU GU KE GE KO GO + 10,10,11,11,12,12,13,13,14,14, // SA ZA SHI JI SU ZU SE ZE SO ZO + 15,15,16,16,17,17,17,18,18,19,19,// TA DA CHI JI tsu TSU ZU TE DE TO DO + 20,21,22,23,24, // NA NI NU NE NO + 25,25,25,26,26,26,27,27,27, // HA BA PA HI BI PI FU BU PU + 28,28,28,29,29,29, // HE BE PE HO BO PO + 30,31,32,33,34, // MA MI MU ME MO + 35,35,36,36,37,37, // ya YA yu YU yo YO + 38,39,40,41,42, // RA RI RU RE RO + 43,43,44,45,46, // wa WA WI WE WO + 47, 2, 5, 8 // N VU ka ke +}; + +/**************************************************************************** +Desc: Map KataKana collated value to vowel value for use for the + previous char. +****************************************************************************/ +FLMBYTE KanaColToVowel[] = +{ + 0,1,2,3,4, // a i u e o + 0,1,2,3,4, // ka ki ku ke ko + 0,1,2,3,4, // sa shi su se so + 0,1,2,3,4, // ta chi tsu te to + 0,1,2,3,4, // na ni nu ne no + 0,1,2,3,4, // ha hi hu he ho + 0,1,2,3,4, // ma mi mu me mo + 0,2,4, // ya yu yo + 0,1,2,3,4, // ra ri ru re ro + 0,1,3,4, // wa wi we wo +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +static FLMBYTE ColToKanaTbl[ 48] = +{ + 0, // a=0, A=1 + 2, // i=2, I=3 + 4, // u=4, U=5, VU=83 + 6, // e=6, E=7 + 8, // o=8, O=9 + 84, // KA=10, GA=11, ka=84 + 12, // KI=12, GI=13 + 14, // KU=14, GU=15 + 85, // KE=16, GE=17, ke=85 + 18, // KO=18, GO=19 + 20, // SA=20, ZA=21 + 22, // SHI=22, JI=23 + 24, // SU=24, ZU=25 + 26, // SE=26, ZE=27 + 28, // SO=28, ZO=29 + 30, // TA=30, DA=31 + 32, // CHI=32, JI=33 + 34, // tsu=34, TSU=35, ZU=36 + 37, // TE=37, DE=38 + 39, // TO=39, DO=40 + 41, // NA + 42, // NI + 43, // NU + 44, // NE + 45, // NO + 46, // HA, BA, PA + 49, // HI, BI, PI + 52, // FU, BU, PU + 55, // HE, BE, PE + 58, // HO, BO, PO + 61, // MA + 62, // MI + 63, // MU + 64, // ME + 65, // MO + 66, // ya, YA + 68, // yu, YU + 70, // yo, YO + 72, // RA + 73, // RI + 74, // RU + 75, // RE + 76, // RO + 77, // wa, WA + 79, // WI + 80, // WE + 81, // WO + 82 // N +}; + +/**************************************************************************** +Desc: Maps from charset 11 to CS24 (punctuation) (starting from 11,0) +****************************************************************************/ +FLMBYTE From0AToZen[] = +{ + 0, 9, 40, 0x53, // sp ! " # + 0x4f, 0x52, 0x54, 38, // $ % & ' + 0x29, 0x2a, 0x55, 0x3b, // ( ) * + + 3, 0x1d, 4, 0x1e // , - . / +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE From0BToZen[] = +{ + 6, 7, 0x42, 0x40, // : ; < = + 0x43, 8, 0x56 // > ? @ +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE From0CToZen[] = +{ + 0x2d, 0x1f, 0x2e, // [ \ ] + 0x0f, 0x11, 0x0d // ^ _ ` +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE From0DToZen[] = +{ + 0x2f, 0x22, 0x30, 0x20 // { | } ~ +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FLMBYTE From8ToZen[] = +{ + 0x5e, 0x7e, 0x5f, 0x7f, 0x5f, 0xFF, 0x60, 0x80, + 0x61, 0x81, 0x62, 0x82, 0x63, 0x83, 0x64, 0x84, + 0x65, 0x85, 0x66, 0x86, 0x67, 0x87, 0x68, 0x88, + 0x69, 0x89, 0x6a, 0x8a, 0x6b, 0x8b, 0x6c, 0x8c, + 0x6d, 0x8d, 0x6e, 0x8e, 0x6f, 0x8f, 0x6f, 0xFF, + 0x70, 0x90, 0x71, 0x91, 0x72, 0x92, 0x73, 0x93, + 0x74, 0x94, 0x75, 0x95 +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +static FLMBYTE From11AToZen[] = +{ + 2, // japanese period + 0x35, // left bracket + 0x36, // right bracket + 0x01, // comma + 0x05 // chuuten +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +static FLMBYTE From11BToZen[] = +{ + 0x51, // wo + 0,2,4,6,8,0x42,0x44,0x46,0x22, // small a i u e o ya yu yo tsu + 0xFF, 1, 3, 5, 7, 9, // dash (x241b) a i u e o + 0x0a, 0x0c, 0x0e, 0x10, 0x12, // ka ki ku ke ko + 0x14, 0x16, 0x18, 0x1a, 0x1c, // sa shi su se so + 0x1e, 0x20, 0x23, 0x25, 0x27, // ta chi tsu te to + 0x29, 0x2a, 0x2b, 0x2c, 0x2d, // na ni nu ne no + 0x2e, 0x31, 0x34, 0x37, 0x3a, // ha hi fu he ho + 0x3d, 0x3e, 0x3f, 0x40, 0x41, // ma mi mu me mo + 0x43, 0x45, 0x47, // ya yu yo + 0x48, 0x49, 0x4a, 0x4b, 0x4c, // ra ri ru re ro + 0x4e, 0x52 // WA N +}; + +/**************************************************************************** +Desc: Convert Zenkaku (double wide) to Hankaku (single wide) + Character set 0x24 maps to single wide chars in other char sets. + This enables collation values to be found on some symbols. + This is also used to convert symbols from hankaku to Zen24. +****************************************************************************/ +BYTE_WORD_TBL Zen24ToHankaku[] = +{ + { 0 ,0x0020 }, // space + { 1 ,0x0b03 }, // japanese comma + { 2 ,0x0b00 }, // circle period + { 3 , 44 }, // comma + { 4 , 46 }, // period + { 5 ,0x0b04 }, // center dot + { 6 , 58 }, // colon + { 7 , 59 }, // semicolon + { 8 , 63 }, // question mark + { 9 , 33 }, // exclamation mark + { 10 ,0x0b3d }, // dakuten + { 11 ,0x0b3e }, // handakuten + { 12 ,0x0106 }, // accent mark + { 13 , 96 }, // accent mark + { 14 ,0x0107 }, // umlat + { 15 , 94 }, // caret + { 16 ,0x0108 }, // macron + { 17 , 95 }, // underscore + { 27 ,0x0b0f }, // extend vowel + { 28 ,0x0422 }, // mdash + { 29 , 45 }, // hyphen + { 30 , 47 }, // slash + { 31 ,0x0607 }, // backslash + { 32 , 126 }, // tilde + { 33 ,0x0611 }, // doubleline + { 34 ,0x0609 }, // line + { 37 ,0x041d }, // left apostrophe + { 38 ,0x041c }, // right apostrophe + { 39 ,0x0420 }, // left quote + { 40 ,0x041f }, // right quote + { 41 , 40 }, // left paren + { 42 , 41 }, // right paren + { 45 , 91 }, // left bracket + { 46 , 93 }, // right bracket + { 47 , 123 }, // left curly bracket + { 48 , 125 }, // right curly bracket + { 53 ,0x0b01 }, // left j quote + { 54 ,0x0b02 }, // right j quote + { 59 , 43 }, // plus + { 60 ,0x0600 }, // minus + { 61 ,0x0601 }, // plus/minus + { 62 ,0x0627 }, // times + { 63 ,0x0608 }, // divide + { 64 , 61 }, // equal + { 65 ,0x0663 }, // unequal + { 66 , 60 }, // less + { 67 , 62 }, // greater + { 68 ,0x0602 }, // less/equal + { 69 ,0x0603 }, // greater/equal + { 70 ,0x0613 }, // infinity + { 71 ,0x0666 }, // traingle dots + { 72 ,0x0504 }, // man + { 73 ,0x0505 }, // woman + { 75 ,0x062d }, // prime + { 76 ,0x062e }, // double prime + { 78 ,0x040c }, // yen + { 79 , 36 }, // dollar + { 80 ,0x0413 }, // cent + { 81 ,0x040b }, // pound + { 82 , 37 }, // percent + { 83 , 35 }, // # + { 84 , 38 }, // & + { 85 , 42 }, // * + { 86 , 64 }, // @ + { 87 ,0x0406 }, // squiggle + { 89 ,0x06b8 }, // filled star + { 90 ,0x0425 }, // hollow circle + { 91 ,0x042c }, // filled circle + { 93 ,0x065f }, // hollow diamond + { 94 ,0x0660 }, // filled diamond + { 95 ,0x0426 }, // hollow box + { 96 ,0x042e }, // filled box + { 97 ,0x0688 }, // hollow triangle + { 99 ,0x0689 }, // hollow upside down triangle + { 103,0x0615 }, // right arrow + { 104,0x0616 }, // left arrow + { 105,0x0617 }, // up arrow + { 106,0x0622 }, // down arrow + { 119,0x060f }, + { 121,0x0645 }, + { 122,0x0646 }, + { 123,0x0643 }, + { 124,0x0644 }, + { 125,0x0642 }, // union + { 126,0x0610 }, // intersection + { 135,0x0655 }, + { 136,0x0656 }, + { 138,0x0638 }, // right arrow + { 139,0x063c }, // left/right arrow + { 140,0x067a }, + { 141,0x0679 }, + { 153,0x064f }, // angle + { 154,0x0659 }, + { 155,0x065a }, + { 156,0x062c }, + { 157,0x062b }, + { 158,0x060e }, + { 159,0x06b0 }, + { 160,0x064d }, + { 161,0x064e }, + { 162,0x050e }, // square root + { 164,0x0604 }, + { 175,0x0623 }, // angstrom + { 176,0x044b }, // percent + { 177,0x051b }, // sharp + { 178,0x051c }, // flat + { 179,0x0509 }, // musical note + { 180,0x0427 }, // dagger + { 181,0x0428 }, // double dagger + { 182,0x0405 }, // paragraph + { 187,0x068f } // big hollow circle +}; + +/**************************************************************************** +Desc: Maps CS26 to CharSet 11 +****************************************************************************/ +FLMBYTE MapCS26ToCharSet11[ 86 ] = +{ + 0x06, // 0 a + 0x10, // 1 A + 0x07, // 2 i + 0x11, // 3 I + 0x08, // 4 u + 0x12, // 5 U + 0x09, // 6 e + 0x13, // 7 E + 0x0a, // 8 o + 0x14, // 9 O + 0x15, // 0x0a KA + 0x95, // GA - 21 followed by 0x3D dakuten + 0x16, // 0x0c KI + 0x96, // GI + 0x17, // 0x0e KU + 0x97, // GU + 0x18, // 0x10 KE + 0x98, // GE + 0x19, // 0x12 KO + 0x99, // GO + 0x1a, // 0x14 SA + 0x9a, // ZA + 0x1b, // 0x16 SHI + 0x9b, // JI + 0x1c, // 0x18 SU + 0x9c, // ZU + 0x1d, // 0x1a SE + 0x9d, // ZE + 0x1e, // 0x1c SO + 0x9e, // ZO + 0x1f, // 0x1e TA + 0x9f, // DA + 0x20, // 0x20 CHI + 0xa0, // JI + 0x0e, // 0x22 small tsu + 0x21, // 0x23 TSU + 0xa1, // ZU + 0x22, // 0x25 TE + 0xa2, // DE + 0x23, // 0x27 TO + 0xa3, // DO + 0x24, // 0x29 NA + 0x25, // 0x2a NI + 0x26, // 0x2b NU + 0x27, // 0x2c NE + 0x28, // 0x2d NO + 0x29, // 0x2e HA + 0xa9, // 0x2f BA + 0xe9, // 0x30 PA + 0x2a, // 0x31 HI + 0xaa, // 0x32 BI + 0xea, // 0x33 PI + 0x2b, // 0x34 FU + 0xab, // 0x35 BU + 0xeb, // 0x36 PU + 0x2c, // 0x37 HE + 0xac, // 0x38 BE + 0xec, // 0x39 PE + 0x2d, // 0x3a HO + 0xad, // 0x3b BO + 0xed, // 0x3c PO + 0x2e, // 0x3d MA + 0x2f, // 0x3e MI + 0x30, // 0x3f MU + 0x31, // 0x40 ME + 0x32, // 0x41 MO + 0x0b, // 0x42 small ya + 0x33, // 0x43 YA + 0x0c, // 0x44 small yu + 0x34, // 0x45 YU + 0x0d, // 0x46 small yo + 0x35, // 0x47 YO + 0x36, // 0x48 RA + 0x37, // 0x49 RI + 0x38, // 0x4a RU + 0x39, // 0x4b RE + 0x3a, // 0x4c RO + 0xff, // 0x4d small wa + 0x3b, // 0x4e WA + 0xff, // 0x4f WI + 0xff, // 0x50 WE + 0x05, // 0x51 WO + 0x3c, // 0x52 N + 0xff, // 0x53 VU + 0xff, // 0x54 ka + 0xff // 0x55 ke +}; + +/**************************************************************************** +Desc: +****************************************************************************/ +FINLINE FLMBOOL charIsUpper( + FLMUINT16 ui16Char) +{ + return( (FLMBOOL)((ui16Char < 0x7F) + ? (FLMBOOL)((ui16Char >= ASCII_LOWER_A && + ui16Char <= ASCII_LOWER_Z) + ? (FLMBOOL)FALSE + : (FLMBOOL)TRUE) + : flmIsUpper( ui16Char))); +} + +/**************************************************************************** +Desc: getNextCharState can be thought of as a 2 dimentional array with + i and j as the row and column indicators respectively. If a value + exists at the intersection of i and j, it is returned. Sparse array + techniques are used to minimize memory usage. +****************************************************************************/ +FINLINE FLMUINT16 getNextCharState( + FLMUINT i, + FLMUINT j) +{ + FLMUINT k; + FLMUINT x; + + for( k = flmIndexi[ x = (i > START_COL) ? (START_ALL) : i ]; + k <= (FLMUINT) (flmIndexi[ x + 1] - 1); + k++ ) + { + if( j == flmIndexj[ k]) + { + return( flmValuea[ (i > START_COL) + ? (k + (FIXUP_AREA_SIZE * (i - START_ALL))) + : k]); + } + } + + return(0); +} + +/************************************************************************** +Desc: Find the collating value of a WP character +Ret: Collating value (COLS0 is high value - undefined WP char) +***************************************************************************/ +FLMUINT16 flmGetCollation( + FLMUINT16 ui16WpChar, + FLMUINT uiLanguage) +{ + FLMUINT16 ui16State; + FLMBYTE ucCharVal; + FLMBYTE ucCharSet; + FLMBOOL bHebrewArabicFlag = FALSE; + TBL_B_TO_BP * pColTbl = flmCol60Tbl; + + // State ONLY for non-US + + if (uiLanguage != US_LANG) + { + if (uiLanguage == AR_LANG || // Arabic + uiLanguage == FA_LANG || // Farsi - persian + uiLanguage == HE_LANG || // Hebrew + uiLanguage == UR_LANG) // Urdu + { + pColTbl = flmHebArabicCol60Tbl; + bHebrewArabicFlag = TRUE; + } + else + { + + // Check if uiLanguage candidate for alternate double collating + + ui16State = getNextCharState( START_COL, uiLanguage); + if (0 != (ui16State = getNextCharState( (ui16State + ? ui16State // look at special case languages + : START_ALL), // look at US and European + (FLMUINT) ui16WpChar))) + { + return( ui16State); + } + } + } + + ucCharVal = (FLMBYTE)ui16WpChar; + ucCharSet = (FLMBYTE)(ui16WpChar >> 8); + + // This is an optimized version of f_b_bp_citrp() inline for performance + + do + { + if (pColTbl->key == ucCharSet) + { + FLMBYTE * pucColVals; + + pucColVals = pColTbl->charPtr; + + // Above lower range of table? + + if (ucCharVal >= *pucColVals) + { + + // Make value zero based to index + + ucCharVal -= *pucColVals++; + + // Below maximum number of table entries? + + if (ucCharVal < *pucColVals++) + { + + // Return collated value. + + return( pucColVals[ ucCharVal]); + } + } + } + + // Go to next table entry + + pColTbl++; + } while (pColTbl->key != 0xFF); + + if (bHebrewArabicFlag) + { + if (ucCharSet == CHSHEB || + ucCharSet == CHSARB1 || + ucCharSet == CHSARB2) + { + + // Same as COLS0_HEBREW + + return( COLS0_ARABIC); + } + } + + // Defaults for characters that don't have a collation value. + + return( COLS0); +} + +/**************************************************************************** +Desc: Add an field into the CDL (Compound Data List) for this ISK. +****************************************************************************/ +RCODE KYCmpKeyAdd2Lst( + FDB * pDb, + IXD * pIxd, // Index definition + IFD * pIfd, // Index field definition + void * pvField, // Field whose value is part of the key + void * pRootContext) // Points to root context of field path +{ + RCODE rc = FERR_OK; + CDL * pCdl; + KREF_CNTRL * pKrefCntrl; + CDL ** ppCdlTbl; + FLMUINT uiCdlEntry; + FLMUINT uiIxEntry; + + pKrefCntrl = &pDb->KrefCntrl; + ppCdlTbl = pKrefCntrl->ppCdlTbl; + + flmAssert( ppCdlTbl != NULL); + + // Figure out which CDL and index entry to use + + uiIxEntry = (FLMUINT) (pIxd - pDb->pDict->pIxdTbl); + uiCdlEntry = (FLMUINT) (pIfd - pDb->pDict->pIfdTbl); + + if( (pCdl = (CDL *)GedPoolAlloc( &pDb->TempPool, sizeof( CDL))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + flmAssert( pKrefCntrl->pIxHasCmpKeys != NULL); + + pKrefCntrl->pIxHasCmpKeys [uiIxEntry] = TRUE; + pCdl->pField = pvField; + pCdl->pRootContext = pRootContext; + + // Insert at first of CDL list + + pCdl->pNext = ppCdlTbl [uiCdlEntry]; + ppCdlTbl [uiCdlEntry] = pCdl; + pKrefCntrl->bHaveCompoundKey = TRUE; + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Called when an entire record has been processed by the key + building functions. Builds and add all compound keys to the table. +****************************************************************************/ +RCODE KYBuildCmpKeys( + FDB * pDb, + FLMUINT uiAction, + FLMUINT uiContainerNum, + FLMUINT uiDrn, + FLMBOOL * pbHadUniqueKeys, + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + KREF_CNTRL * pKrefCntrl = &pDb->KrefCntrl; + CDL ** ppCdlTbl = pKrefCntrl->ppCdlTbl; + FLMBYTE * pKeyBuf = pKrefCntrl->pKrefKeyBuf; + FLMBYTE * pIxHasCmpKeys = pKrefCntrl->pIxHasCmpKeys; + IXD * pIxd; + IFD * pIfd; + IFD * pFirstIfd; + FLMUINT uiFirstCdlEntry; + FLMUINT uiCdlEntry; + FLMBOOL bBuildCmpKeys; + FLMUINT uiIxEntry; + FLMUINT uiTotalIndexes; + FLMUINT uiIfdCnt; + FLMUINT uiKeyLen; + FLMBYTE LowUpBuf [MAX_LOWUP_BUF]; + FLD_CONTEXT fldContext; + FDICT * pDict = pDb->pDict; + + LowUpBuf[0] = '\0'; + + if( pKrefCntrl->bHaveCompoundKey == FALSE) + { + goto Exit; + } + + flmAssert( pKeyBuf != NULL && pIxHasCmpKeys != NULL); + pKrefCntrl->bHaveCompoundKey = FALSE; + + // Loop through all of the indexes looking for a CDL entry. + // VISIT: We need to find the indexes faster than looping! + + uiTotalIndexes = pDict->uiIxdCnt; + for (uiIxEntry = 0; uiIxEntry < uiTotalIndexes; uiIxEntry++) + { + // See if the index has compound keys to build. + + if( !pIxHasCmpKeys [uiIxEntry]) + { + continue; + } + pIxd = pDict->pIxdTbl + uiIxEntry; + pIxHasCmpKeys [uiIxEntry] = FALSE; + bBuildCmpKeys = TRUE; + + // Make sure that all required fields are present. + + pFirstIfd = pIfd = pIxd->pFirstIfd; + uiCdlEntry = uiFirstCdlEntry = (FLMUINT) (pFirstIfd - pDict->pIfdTbl); + + for (uiIfdCnt = 0; + uiIfdCnt < pIxd->uiNumFlds; + pIfd++, uiCdlEntry++, uiIfdCnt++) + { + FLMUINT uiCompoundPos; + FLMBOOL bHitFound; + + // Loop on each compound field piece looking for REQUIRED field + // without any data - then we don't have to build a key. + + bHitFound = (pIfd->uiFlags & IFD_REQUIRED_PIECE) ? FALSE : TRUE; + uiCompoundPos = pIfd->uiCompoundPos; + + for(;;) + { + if( !bHitFound) + { + if( ppCdlTbl [uiCdlEntry]) + { + bHitFound = TRUE; + } + } + + if( (pIfd->uiFlags & IFD_LAST) || + ((pIfd+1)->uiCompoundPos != uiCompoundPos)) + { + break; + } + + pIfd++; + uiCdlEntry++; + uiIfdCnt++; + } + + if( !bHitFound) + { + bBuildCmpKeys = FALSE; + break; + } + } + + // Build the individual compound keys. + + if( bBuildCmpKeys) + { + uiKeyLen = 0; + f_memset( &fldContext, 0, sizeof(FLD_CONTEXT)); + + if( RC_BAD(rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, + pFirstIfd, + uiAction, uiDrn, pbHadUniqueKeys, + uiFirstCdlEntry, 0, pKeyBuf, + uiKeyLen, LowUpBuf, 0, + pRecord, &fldContext))) + { + goto Exit; + } + } + + // Reset the CDL pointers to NULL + + f_memset( (void *) (&ppCdlTbl [ uiFirstCdlEntry ]), + 0, sizeof(CDL *) * pIxd->uiNumFlds); + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: Build all compound keys for a record. +****************************************************************************/ +RCODE KYCmpKeyElmBld( + FDB * pDb, + IXD * pIxd, // Index definition. + FLMUINT uiContainerNum, + IFD * pIfd, // Index field definition. + FLMUINT uiAction, + FLMUINT uiDrn, + FLMBOOL * pbHadUniqueKeys, + FLMUINT uiCdlEntry, // CDL entry for the IFD. + FLMUINT uiCompoundPos, // Compound Piece number - zero based + FLMBYTE * pKeyBuf, // Key buffer to build the key in + FLMUINT uiKeyLen, // Total length left in the key buffer + FLMBYTE * pLowUpBuf, // For POST compound keys place bits here. + FLMUINT uiLuLen, // Length used in pLowUpBuf. + FlmRecord * pRecord, // Record being indexed. + FLD_CONTEXT * pFldContext) // State to verify all fields are siblings. +{ + RCODE rc = FERR_OK; + CDL ** pCdlTbl = pDb->KrefCntrl.ppCdlTbl; + CDL * pCdl = pCdlTbl [uiCdlEntry]; + FLMBYTE * pTmpBuf = NULL; + void * pvMark = NULL; + IFD * pNextIfdPiece; + void * pvField; + void * pSaveParentAnchor; + FLMUINT uiNextCdlEntry; + FLMBOOL bBuiltKeyPiece; + FLMUINT uiElmLen; + FLMUINT uiPostFlag; + FLMUINT uiPostLen; + FLMUINT uiTempLuLen; + FLMUINT uiPieceLuLen; + FLMUINT uiNextPiecePos; + FLMUINT uiLanguage; + FLMUINT uiMaxKeySize = (pIxd->uiContainerNum) + ? MAX_KEY_SIZ + : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); + FLMBOOL bFldIsEncrypted = FALSE; + + if ((uiLanguage = pIxd->uiLanguage) == 0xFFFF) + { + uiLanguage = pDb->pFile->FileHdr.uiDefaultLanguage; + } + + // Test for compound key being tons of levels + + flmAssert( uiCompoundPos < MAX_COMPOUND_PIECES); + + // Set if this piece is part of post + + uiPostFlag = IFD_IS_POST_TEXT( pIfd); + + // Add the DELIMITER, except on the first key element + + if( uiCompoundPos != 0) + { + IFD * pPrevIfd = pIfd - 1; + + if( (uiLanguage >= FIRST_DBCS_LANG) && + (uiLanguage <= LAST_DBCS_LANG) && + (IFD_GET_FIELD_TYPE( pPrevIfd) == FLM_TEXT_TYPE) && + (!(pPrevIfd->uiFlags & IFD_CONTEXT))) + { + pKeyBuf [uiKeyLen++] = 0; + } + pKeyBuf [uiKeyLen++] = COMPOUND_MARKER; + } + + // Determine the next IFD compound piece. + + for( pNextIfdPiece = (IFD *)NULL, + uiNextCdlEntry = uiCdlEntry + 1, + uiNextPiecePos = 0; + ((pIfd+uiNextPiecePos)->uiFlags & IFD_LAST) == 0; ) + { + if( (pIfd+uiNextPiecePos)->uiCompoundPos != + (pIfd+uiNextPiecePos+1)->uiCompoundPos) + { + pNextIfdPiece = pIfd + uiNextPiecePos + 1; + uiNextCdlEntry = uiCdlEntry + uiNextPiecePos + 1; + break; + } + + if( !pCdl) + { + pIfd++; + pCdl = pCdlTbl [ ++uiCdlEntry]; + uiNextCdlEntry = uiCdlEntry + 1; + } + else + { + uiNextPiecePos++; + } + } + + pSaveParentAnchor = pFldContext->pParentAnchor; + bBuiltKeyPiece = FALSE; + + // Loop on each CDL, but do at least once + + while( pCdl || !bBuiltKeyPiece) + { + // Restore context values for each iteration + + pFldContext->pParentAnchor = pSaveParentAnchor; + + // If there is a field to process, verify that its path is + // relative to the previous non-null compound pieces + + if( pCdl) + { + pvField = pCdl->pField; + + // Validate the current and previous root contexts + + if( KYValidatePathRelation( pRecord, pCdl->pRootContext, pvField, + pFldContext, uiCompoundPos) == FERR_FAILURE) + { + // This field didn't pass the test, get the next field. + + goto Next_CDL_Field; + } + } + else + { + pvField = NULL; + } + + bBuiltKeyPiece = TRUE; + uiPostLen = uiElmLen = 0; + uiTempLuLen = uiLuLen; + + if( pCdl && (pIfd->uiFlags & (IFD_EACHWORD | IFD_SUBSTRING)) && + (pRecord->getDataType( pvField) == FLM_TEXT_TYPE) && + pRecord->getDataLength( pvField) && + ((!pRecord->isEncryptedField( pvField) || + (pRecord->isEncryptedField( pvField) && + pDb->pFile->bInLimitedMode)))) + { + const FLMBYTE * pText = pRecord->getDataPtr( pvField); + FLMUINT uiTextLen = pRecord->getDataLength( pvField); + FLMUINT uiWordLen; + FLMBOOL bReturn; + FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) + ? TRUE + : FALSE; + + if( !pTmpBuf) + { + pvMark = GedPoolMark( &pDb->TempPool); + + if( (pTmpBuf = (FLMBYTE *)GedPoolAlloc( &pDb->TempPool, + (FLMUINT)MAX_KEY_SIZ + 8)) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Cleanup1; + } + } + + // Loop on each WORD in the value + + for(;;) + { + bReturn = (pIfd->uiFlags & IFD_EACHWORD) + ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, + pIfd->uiLimit, + pTmpBuf, &uiWordLen) + : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, + pIfd->uiFlags, pIfd->uiLimit, + pTmpBuf, &uiWordLen); + if( !bReturn) + { + break; + } + + uiTempLuLen = uiLuLen; + + // Compute number of bytes left + + uiElmLen = uiMaxKeySize - uiKeyLen - uiTempLuLen; + + if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, + pTmpBuf, uiWordLen, pIfd->uiFlags, pIfd->uiLimit, + NULL, &uiPieceLuLen, uiLanguage, TRUE, + bFirstSubstring, FALSE, NULL))) + { + goto Exit; + } + + bFirstSubstring = FALSE; + + if( uiPostFlag) + { + uiElmLen -= uiPieceLuLen; + f_memcpy( &pLowUpBuf [uiTempLuLen], + &pKeyBuf[ uiKeyLen + uiElmLen ], uiPieceLuLen); + uiTempLuLen += uiPieceLuLen; + } + + if( !pNextIfdPiece) + { + + // All ISKs have been added so now output the key + + if( uiTempLuLen ) + { + uiPostLen = KYCombPostParts( pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen), + pLowUpBuf, uiTempLuLen, + uiLanguage, + (FLMUINT)(pIfd->uiFlags) ); + } + + if( RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, + pIfd, uiAction, uiDrn, pbHadUniqueKeys, + pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen + uiPostLen), + TRUE, FALSE, FALSE))) + { + goto Cleanup1; + } + } + else if( RC_BAD( rc)) + { + goto Cleanup1; + } + else + { + + // RECURSIVE CALL to the Next ISK provided no overflow + + if( RC_BAD( rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, + pNextIfdPiece, + uiAction, uiDrn, pbHadUniqueKeys, + uiNextCdlEntry, + uiCompoundPos + 1, pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen), pLowUpBuf, + uiTempLuLen, pRecord, pFldContext))) + { + goto Cleanup1; + } + } + + if( (pIfd->uiFlags & IFD_SUBSTRING) && + (uiTextLen == 1 && + !(uiLanguage >= FIRST_DBCS_LANG && + uiLanguage <= LAST_DBCS_LANG))) + { + break; + } + } + +Cleanup1: + + if (RC_BAD( rc)) + { + goto Exit; + } + } + else + { + if( pvField) + { + if( pIfd->uiFlags & IFD_CONTEXT) + { + pKeyBuf [uiKeyLen] = KY_CONTEXT_PREFIX; + flmUINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pvField), + &pKeyBuf [uiKeyLen + 1]); + uiKeyLen += KY_CONTEXT_LEN; + } + else if( pRecord->getDataLength( pvField)) + { + const FLMBYTE * pExportValue = pRecord->getDataPtr( pvField); + FLMUINT uiDataLength = pRecord->getDataLength( pvField); + + if (pRecord->isEncryptedField( pvField) && + pDb->pFile->bInLimitedMode) + { + pExportValue = pRecord->getEncryptionDataPtr( pvField); + uiDataLength = pRecord->getEncryptedDataLength( pvField); + bFldIsEncrypted = TRUE; + } + + // Compute number of bytes left + + uiElmLen = uiMaxKeySize - uiKeyLen - uiLuLen; + + if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, + pExportValue, + uiDataLength, pIfd->uiFlags, + pIfd->uiLimit, NULL, &uiPieceLuLen, + uiLanguage, TRUE, FALSE, FALSE, NULL, NULL, + bFldIsEncrypted))) + { + goto Exit; + } + + if( uiPostFlag ) + { + uiElmLen -= uiPieceLuLen; + f_memcpy( &pLowUpBuf [uiTempLuLen], + &pKeyBuf [uiKeyLen + uiElmLen], uiPieceLuLen); + uiTempLuLen += uiPieceLuLen; + } + } + } + + if( !pNextIfdPiece) + { + + // All IFDs have been added so now output the key + + if( uiTempLuLen) + { + uiPostLen = KYCombPostParts( pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen), + pLowUpBuf, uiTempLuLen, + uiLanguage, (FLMUINT)(pIfd->uiFlags)); + } + + if( RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, + pIfd, uiAction, uiDrn, pbHadUniqueKeys, + pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen + uiPostLen), + TRUE, FALSE, bFldIsEncrypted))) + { + goto Exit; + } + } + else if( RC_BAD( rc)) + { + goto Exit; + } + else + { + if( RC_BAD( rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, + pNextIfdPiece, + uiAction, uiDrn, pbHadUniqueKeys, + uiNextCdlEntry, + uiCompoundPos + 1, pKeyBuf, + (FLMUINT)(uiKeyLen + uiElmLen), pLowUpBuf, + uiTempLuLen, pRecord, pFldContext))) + { + goto Exit; + } + } + } + +Next_CDL_Field: + + if( pCdl) + { + pCdl = pCdl->pNext; + } + + // If the CDL list is empty, goto the next IFD if same uiCompoundPos. + + while ((!pCdl) && ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + { + pIfd++; + pCdl = pCdlTbl [++uiCdlEntry]; + } + + // If all fields failed the validate field path test and this piece of + // the compound key is required, then goto exit NOW which will not + // build any key with the previous built key pieces. + + if( !pCdl && !bBuiltKeyPiece && ((pIfd->uiFlags & IFD_OPTIONAL) == 0)) + { + goto Exit; + } + } + +Exit: + + if( pvMark) + { + GedPoolReset( &pDb->TempPool, pvMark); + } + + return( rc); +} + + +/**************************************************************************** +Desc: Validate that the current field is related to the other fields + in the compound key index. The context (left-most) fields of the + field paths must all be siblings of each other in order to + be related. +****************************************************************************/ +RCODE KYValidatePathRelation( + FlmRecord * pRecord, + void * pCurContext, + void * pCurFld, + FLD_CONTEXT * pFldContext, + FLMUINT uiCompoundPos) +{ + RCODE rc = FERR_OK; + void * pCurParent; + FLMUINT uiPrevCompoundPos; + FLMBOOL bMatchedContext; + + // If too many compound levels, just exit and don't check. + + if( uiCompoundPos >= MAX_COMPOUND_PIECES) + { + goto Exit; + } + + pCurParent = pRecord->parent( pCurContext); + + // First time in is the easy case - just set the parent anchor. + // A value of NULL is OK. + + if( uiCompoundPos == 0) + { + pFldContext->pParentAnchor = pCurParent; + goto Exit; + } + + bMatchedContext = FALSE; + uiPrevCompoundPos = uiCompoundPos; + + while( uiPrevCompoundPos--) + { + if( pFldContext->rootContexts[ uiPrevCompoundPos] == pCurContext) + { + // Check this field against the current field values. + + rc = KYVerifyMatchingPaths( pRecord, pCurContext, pCurFld, + pFldContext->leafFlds[ uiPrevCompoundPos]); + + // Return failure on any failure. Otherwise continue. + + if( rc == FERR_FAILURE) + { + goto Exit; + } + + bMatchedContext = TRUE; + } + } + + if( bMatchedContext) + { + // If we had some base relation match, there is no need to + // verify that the parents are the same. + + goto Exit; + } + + // Verify that the parent anchor equals the parent of pCurContext. + + if( pFldContext->pParentAnchor != pCurParent) + { + rc = RC_SET( FERR_FAILURE); + goto Exit; + } + +Exit: + + // Set the state variables for this compound position. + + if( RC_OK(rc)) + { + pFldContext->rootContexts[ uiCompoundPos ] = pCurContext; + pFldContext->leafFlds[ uiCompoundPos] = pCurFld; + } + + return( rc); +} + +/**************************************************************************** +Desc: Verify that two paths with a common context match paths. + If the tag of pCurContext has a previous match in the compound + key, the field should also match (more of a relational validation). + + This means that for keys (A.B.C.D AND A.B.C.E) the 'A.B.C' fields + should be the same field. ALL previous field pieces must be + checked for this. This could be (but isn't being) done by + finding the best match" and only comparing the current with the + best match. + + Hard Example: + Do these fields match - A.B.D.E.F and A.C.D.E.G? + We don't want to keep the field path of the two fields around + because this is more state than we need right now. These match + only if the 'A's are the same field. + + A A + B C + D D + E E + F G +****************************************************************************/ +RCODE KYVerifyMatchingPaths( + FlmRecord * pRecord, + void * pCurContext, // Same value as pMatchFld's context. + void * pCurFld, // Current field + void * pMatchFld) // Some field from a previous piece. +{ + RCODE rc = FERR_OK; + FLMUINT uiCurLevel; + FLMUINT uiMatchLevel; + FLMBOOL bMismatchFound = FALSE; + + // If a field equals a context then don't bother to check. + + if( (pCurContext == pCurFld) || (pCurContext == pMatchFld)) + { + goto Exit; + } + + // Go up the parent line until levels match. + + uiCurLevel = pRecord->getLevel( pCurFld); + uiMatchLevel = pRecord->getLevel( pMatchFld); + flmAssert( pRecord->getLevel( pCurContext) < uiCurLevel); + + while( uiCurLevel != uiMatchLevel) + { + if( uiCurLevel > uiMatchLevel) + { + pCurFld = pRecord->parent( pCurFld); + uiCurLevel--; + } + else + { + pMatchFld = pRecord->parent( pMatchFld); + uiMatchLevel--; + } + } + + // Go up until you hit the matching context. + + while( pCurFld != pCurContext) + { + if( pRecord->getFieldID( pCurFld) == pRecord->getFieldID( pMatchFld)) + { + // If the fields are NOT the same we MAY have a mismatch. + + if( pCurFld != pMatchFld) + { + bMismatchFound = TRUE; + } + } + else + { + // Tags are different - start over checking + + bMismatchFound = FALSE; + } + + // Go to the next parent. + + pCurFld = pRecord->parent( pCurFld); + pMatchFld = pRecord->parent( pMatchFld); + } + + if( bMismatchFound) + { + rc = RC_SET( FERR_FAILURE); + goto Exit; + } + +Exit: + + return( rc); +} + + +/**************************************************************************** +Desc: Combine the bits from all POST text keys. +****************************************************************************/ +FLMUINT KYCombPostParts( + FLMBYTE * pKeyBuf, + FLMUINT uiKeyLen, + FLMBYTE * pLowUpBuf, + FLMUINT uiLuLen, + FLMUINT uiLanguage, + FLMUINT uiIfdAttr) +{ + FLMUINT wReturnLen; + + if( !uiLuLen) + { + return( 0); + } + + wReturnLen = (FLMUINT)(uiLuLen + 2); + if( (uiLanguage >= FIRST_DBCS_LANG) && + (uiLanguage <= LAST_DBCS_LANG) && + ((uiIfdAttr & 0x0F) == FLM_TEXT_TYPE) && + (!(uiIfdAttr & IFD_CONTEXT ))) + { + pKeyBuf [uiKeyLen++] = 0; + wReturnLen++; + } + + pKeyBuf [uiKeyLen++] = END_COMPOUND_MARKER; + f_memcpy( &pKeyBuf [uiKeyLen], pLowUpBuf, uiLuLen); + pKeyBuf [uiKeyLen + uiLuLen] = (FLMBYTE) uiLuLen; + + return( wReturnLen ); +} + /**************************************************************************** Desc: Create an index key given a keyTree and index definition. This routine works on a normal data tree - used in FlmKeyBuild. where a data record is traversed with field paths being checked. - -Ret: FERR_OK, FERR_MEM, FERR_DATA_CONVERSION ****************************************************************************/ RCODE KYTreeToKey( - FDB_p pDb, - IXD_p pIxd, + FDB * pDb, + IXD * pIxd, FlmRecord * pRecord, FLMUINT uiContainerNum, FLMBYTE * pKeyBuf, @@ -53,7 +3636,7 @@ RCODE KYTreeToKey( FLMUINT uiFlags) { RCODE rc = FERR_OK; - IFD_p pIfd; + IFD * pIfd; void * pvMatchField; FLMBYTE * pToKey = pKeyBuf; const FLMBYTE * pExportPtr; @@ -84,11 +3667,9 @@ RCODE KYTreeToKey( pIfd = pIxd->pFirstIfd; bIsCompound = (pIfd->uiFlags & IFD_COMPOUND) ? TRUE : FALSE; + for (;;pIfd++) { - - /* Set if IFD is post. */ - uiIsPost |= (FLMUINT) (uiIskPostFlag = (FLMUINT)IFD_IS_POST_TEXT( pIfd)); bIsAsianCompound =((uiLanguage >= FIRST_DBCS_LANG) && @@ -98,13 +3679,15 @@ RCODE KYTreeToKey( nth = 1; uiToKeyLen = 0; - // Find matching node in the tree - if not found skip and continue. + // Find matching node in the tree - if not found skip and continue FIND_NXT: - if( (pvMatchField = pRecord->find( pRecord->root(), pIfd->uiFldNum, nth)) != NULL) + + if( (pvMatchField = pRecord->find( pRecord->root(), + pIfd->uiFldNum, nth)) != NULL) { - /* Match was found, now if flagged, validate its parent path. */ + // Match was found, now if flagged, validate its parent path if( uiFlags & KY_PATH_CHK_FLAG) { @@ -113,6 +3696,7 @@ FIND_NXT: FLMUINT uiCurrentFld; puiFieldPath = pIfd->pFieldPathCToP; + for( uiCurrentFld = 1; puiFieldPath [uiCurrentFld]; uiCurrentFld++) { if( ((pTempField = pRecord->parent( pTempField)) == NULL) || @@ -124,21 +3708,21 @@ FIND_NXT: } } - /* Convert the node's key value to the index type. */ - - /* Compute maximum. bytes remaining. */ + // Convert the node's key value to the index type. + // Compute maximum bytes remaining. uiToKeyLen = uiMaxKeySize - uiTotalLen; - /* Take the tag and make it the key. */ + // Take the tag and make it the key if( pIfd->uiFlags & IFD_CONTEXT) { - /* Output the tag number. */ + // Output the tag number. *pToKey = KY_CONTEXT_PREFIX; - flmUINT16ToBigEndian( (FLMUINT16) pRecord->getFieldID( pvMatchField), &pToKey [1]); + flmUINT16ToBigEndian( (FLMUINT16) pRecord->getFieldID( + pvMatchField), &pToKey [1]); uiToKeyLen = KY_CONTEXT_LEN; } else @@ -160,20 +3744,17 @@ FIND_NXT: if( pRecord->isRightTruncated( pvMatchField)) { - /* - VISIT: This is a bug in f_tocoll.cpp that if we - fix all text indexes could be corrupt. If the string - is EXACTLY the length of the truncation length then - it should, but doesn't, set the truncation flag. - The code didn't match the design intent. - */ + // If the string is EXACTLY the length of the truncation + // length then it should, but doesn't, set the truncation flag. + // The code didn't match the design intent. + f_memmove( &pToKey[ uiToKeyLen - uiPieceLuLen + 1], &pToKey[ uiToKeyLen - uiPieceLuLen], uiPieceLuLen); pToKey[ uiToKeyLen - uiPieceLuLen] = COLL_TRUNCATED; uiToKeyLen++; } - if( uiIskPostFlag) /* uiPieceLuLen cannot be 0 */ + if( uiIskPostFlag) { uiToKeyLen -= uiPieceLuLen; f_memcpy( &LowUpBuf [uiLuLen], @@ -181,7 +3762,7 @@ FIND_NXT: uiLuLen += uiPieceLuLen; } } - } /* ifend gedFind==NULL */ + } // Check here if key found else the fields are missing. @@ -193,70 +3774,73 @@ FIND_NXT: // Go to the last IFD with the same compound position. - while( ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + while( ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) { pIfd++; } } - else /* no matching field found */ + else { // Continue if there are still fields with same compound position. - if( ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + if( ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) { continue; } iMissingFlds++; + if( bIsAsianCompound) + { iMissingFlds++; + } } // Check if done. - if( pIfd->uiFlags & IFD_LAST) + { break; + } if( bIsCompound) { - if( bIsAsianCompound) /* Output 2 bytes for marker */ + if( bIsAsianCompound) { *pToKey++ = 0; uiTotalLen++; } + *pToKey++ = COMPOUND_MARKER; uiTotalLen++; } - else if( uiToKeyLen ) /* multi-field index key */ + else if( uiToKeyLen) + { break; - } /* FOR LOOP END */ + } + } - /* - Back up iMissingFlds-1 because last - field does not have compound marker. - Add 4 bytes of foxes for high values. - */ + // Back up iMissingFlds-1 because last + // field does not have compound marker. + // Add 4 bytes of foxes for high values. - if( iMissingFlds && (uiFlags & KY_HIGH_FLAG) && (bIsCompound)) + if( iMissingFlds && (uiFlags & KY_HIGH_FLAG) && bIsCompound) { - - /* - Ignore the last one or two iMissingFlds values because a compound - marker was not added to the end of the key. - */ + // Ignore the last one or two iMissingFlds values because a compound + // marker was not added to the end of the key. if( bIsAsianCompound) + { iMissingFlds--; + } + uiTotalLen -= --iMissingFlds; - pToKey -= iMissingFlds; + pToKey -= iMissingFlds; - /* - Fill with high values to the end of the buffer. - It is easy for double byte ASIAN collation values to all be 0xFF. - */ + // Fill with high values to the end of the buffer. + // It is easy for double byte ASIAN collation values to all be 0xFF. if( uiTotalLen < uiMaxKeySize) { @@ -265,7 +3849,7 @@ FIND_NXT: uiTotalLen += (uiMaxKeySize - uiTotalLen); } } - else if( uiIsPost) /* else take care of post index */ + else if( uiIsPost) { uiTotalLen += KYCombPostParts( pKeyBuf, uiTotalLen, LowUpBuf, uiLuLen, uiLanguage, (FLMUINT)(pIfd->uiFlags)); @@ -277,8 +3861,11 @@ FIND_NXT: { appendContainerToKey( pIxd, uiContainerNum, pKeyBuf, &uiTotalLen); } + *puiKeyLenRV = uiTotalLen; + Exit: + return( rc); } @@ -307,6 +3894,7 @@ RCODE KYCollateValue( FLMUINT uiDataType = uiFlags & 0x0F; // Treat an encrypted field as binary for collation purposes. + if (bFldIsEncrypted) { uiDataType = FLM_BINARY_TYPE; @@ -325,9 +3913,9 @@ RCODE KYCollateValue( if( uiDataType == FLM_TEXT_TYPE) { FLMUINT uiCharLimit; - FLMBYTE byTmpBuf[ MAX_KEY_SIZ + 8]; // OK on the stack. + FLMBYTE byTmpBuf[ MAX_KEY_SIZ + 8]; - if(uiFlags & (IFD_MIN_SPACES | IFD_NO_UNDERSCORE | + if( uiFlags & (IFD_MIN_SPACES | IFD_NO_UNDERSCORE | IFD_NO_SPACE | IFD_NO_DASH | IFD_ESC_CHAR)) { if( RC_BAD( rc = KYFormatText( @@ -341,10 +3929,12 @@ RCODE KYCollateValue( { goto Exit; } + pSrc = (FLMBYTE *) byTmpBuf; } uiCharLimit = uiLimit ? uiLimit : IFD_DEFAULT_LIMIT; + if( (uiLanguage >= FIRST_DBCS_LANG ) && (uiLanguage <= LAST_DBCS_LANG)) { rc = AsiaFlmTextToColStr( pSrc, uiSrcLen, pDest, &uiDestLen, @@ -360,13 +3950,14 @@ RCODE KYCollateValue( } } - // TRICKY: uiDestLen could be set to zero if text and no value. + // uiDestLen could be set to zero if text and no value. if( !uiSrcLen || !uiDestLen) { if( !bCompoundPiece) { // Zero length key. Any value under 0x1F would work. + if( (uiLanguage >= FIRST_DBCS_LANG ) && (uiLanguage <= LAST_DBCS_LANG)) { @@ -384,55 +3975,73 @@ RCODE KYCollateValue( { uiDestLen = 0; } + goto Exit; } switch (uiDataType) { case FLM_TEXT_TYPE: - break; - - case FLM_NUMBER_TYPE: /* parse internal number; generate key */ { - FLMBYTE * pOutput = pDest + 1; /* First byte holds sign/magnitude */ + break; + } + + case FLM_NUMBER_TYPE: + { + FLMBYTE * pOutput = pDest + 1; const FLMBYTE * pTempSrc = pSrc; - FLMUINT uiBytesOutput = 1; /* Allow for sign/magnitude byte */ + FLMUINT uiBytesOutput = 1; FLMUINT uiMaxOutLen = uiDestLen; FLMINT iHiInNibble = 1; FLMINT iHiOutNibble = 1; - FLMUINT uiSigSign = SIG_POS; /* hi bit causes + to collate before */ + FLMUINT uiSigSign = SIG_POS; FLMUINT uiMagnitude = COLLATED_NUM_EXP_BIAS - 1; FLMBYTE byValue; for (rc = FERR_OK;;) { - switch( /* Determine what we're pointing at */ - byValue = (iHiInNibble++ & 1) /* test if high/low nibble */ - ? (FLMBYTE)(*pTempSrc >> 4) /* high: shift for math below */ - : (FLMBYTE)(*pTempSrc++ & 0x0F) /* low: mask off high & point next */ - ){ - case 0x0B: /* Negative Sign code */ + switch( byValue = (iHiInNibble++ & 1) + ? (FLMBYTE)(*pTempSrc >> 4) + : (FLMBYTE)(*pTempSrc++ & 0x0F)) + { + case 0x0B: // Negative Sign code + { uiSigSign = 0; continue; - case 0x0A: /* Ignore for now - not implemented */ + } + + case 0x0A: // Ignore for now - not implemented case 0x0C: case 0x0D: case 0x0E: + { continue; - case 0x0F: /* Terminator */ + } + + case 0x0F: // Terminator + { *pDest = (FLMBYTE)(uiSigSign | ((uiSigSign ? uiMagnitude : ~uiMagnitude) & 0x7F)); goto NumDone; - default: /* Numeric digits */ - uiMagnitude++; /* Determine the magnitude as we go */ - if( uiSigSign) /* positive number */ - byValue += COLLATED_DIGIT_OFFSET; - else /* invert for key collation */ - byValue = (FLMBYTE)((COLLATED_DIGIT_OFFSET + 9) - byValue); - if( iHiOutNibble++ & 1) /* test high/low output nibble */ + } + + default: + { + uiMagnitude++; + + if( uiSigSign) + { + byValue += COLLATED_DIGIT_OFFSET; + } + else + { + // Invert for key collation + + byValue = (FLMBYTE)((COLLATED_DIGIT_OFFSET + 9) - byValue); + } + + if( iHiOutNibble++ & 1) { - /* need another byte; check length */ - if( uiBytesOutput++ == uiMaxOutLen) { uiBytesOutput = 0; @@ -440,20 +4049,23 @@ RCODE KYCollateValue( goto NumDone; } - *pOutput = (FLMBYTE)((byValue << 4) /* store high nibble */ - | 0x0F); /* pre-set terminator (may be last)*/ + *pOutput = (FLMBYTE)((byValue << 4) | 0x0F); } else { - *pOutput++ &= (FLMBYTE)(byValue | 0xF0);/* reset low nib-high wasn't last */ + *pOutput++ &= (FLMBYTE)(byValue | 0xF0); } + continue; + } } } + NumDone: + uiDestLen = uiBytesOutput; - } break; + } case FLM_BINARY_TYPE: { @@ -491,6 +4103,7 @@ NumDone: { *tmpDest++ = COLL_TRUNCATED; } + break; } @@ -508,12 +4121,15 @@ NumDone: uiDestLen = 5; rc = FERR_OK; } + break; } default: + { rc = RC_SET( FERR_CONV_BAD_DEST_TYPE); break; + } } Exit: @@ -532,7 +4148,7 @@ Visit: Pass in uiLimit and pass back a truncated flag when the to get the exact truncated count that is done in f_tocoll.cpp and that could introduce some bugs. ****************************************************************************/ -FSTATIC RCODE KYFormatText( +RCODE KYFormatText( const FLMBYTE * psVal, // Points to value source FLMUINT uiSrcLen, // Length of the key-NOT NULL TERMINATED // Booleans below are zero or NON-zero @@ -555,28 +4171,31 @@ FSTATIC RCODE KYFormatText( FLMUINT objLength; FLMBOOL bLastCharWasSpace = bMinSpaces; - for( ; uiCurPos < uiSrcLen && uiDestPos < MAX_KEY_SIZ - 1; uiCurPos += objLength ) + for( ; uiCurPos < uiSrcLen && uiDestPos < MAX_KEY_SIZ - 1; + uiCurPos += objLength) { ucValue = psVal [uiCurPos]; objLength = 1; uiOldDestPos = uiDestPos; - objType = (FLMBYTE)(GedTextObjType( ucValue)); + objType = (FLMBYTE)(flmTextObjType( ucValue)); switch( objType) { - case ASCII_CHAR_CODE: /* 0nnnnnnn */ - - if( (ucValue == ASCII_SPACE) || ((ucValue == ASCII_UNDERSCORE) && bNoUnderscore)) + case ASCII_CHAR_CODE: // 0nnnnnnn + { + if( (ucValue == ASCII_SPACE) || + ((ucValue == ASCII_UNDERSCORE) && bNoUnderscore)) { if( bLastCharWasSpace || bNoSpace) { break; } + // Sets to true if we want to minimize spaces. + bLastCharWasSpace = bMinSpaces; ucValue = ASCII_SPACE; } - // FYI: There are about 13 different UNICODE hyphen characters. else if( (ucValue == ASCII_DASH) && bNoDash) { break; @@ -584,71 +4203,4806 @@ FSTATIC RCODE KYFormatText( else { if( (ucValue == ASCII_BACKSLASH) && bEscChar && - (psVal [uiCurPos+1] == ASCII_WILDCARD || psVal [uiCurPos+1] == ASCII_BACKSLASH)) + (psVal [uiCurPos+1] == ASCII_WILDCARD || + psVal [uiCurPos+1] == ASCII_BACKSLASH)) { ucValue = psVal [uiCurPos+1]; objLength++; } + bLastCharWasSpace = FALSE; } + psDestPtr[ uiDestPos++] = ucValue; break; - case WHITE_SPACE_CODE: /* 110nnnnn */ + } + + case WHITE_SPACE_CODE: // 110nnnnn + { if( bLastCharWasSpace || bNoSpace) { break; } + // Sets to true if we want to minimize spaces. + bLastCharWasSpace = bMinSpaces; psDestPtr[ uiDestPos++] = ASCII_SPACE; break; - case CHAR_SET_CODE: /* 10nnnnnn */ + } + + case CHAR_SET_CODE: // 10nnnnnn case UNK_EQ_1_CODE: case OEM_CODE: + { bLastCharWasSpace = FALSE; psDestPtr[ uiDestPos++] = psVal [uiCurPos]; psDestPtr[ uiDestPos++] = psVal [uiCurPos+1]; objLength = 2; break; - case UNICODE_CODE: /* Unconvertable UNICODE code */ - case EXT_CHAR_CODE: /* Full extended character */ + } + + case UNICODE_CODE: // Unconvertable UNICODE code + case EXT_CHAR_CODE: // Full extended character + { bLastCharWasSpace = FALSE; psDestPtr[ uiDestPos++] = psVal [uiCurPos]; psDestPtr[ uiDestPos++] = psVal [uiCurPos+1]; psDestPtr[ uiDestPos++] = psVal [uiCurPos+2]; objLength = 3; break; + } + case UNK_GT_255_CODE: + { bLastCharWasSpace = FALSE; objLength = 1 + sizeof( FLMUINT) + FB2UW( &psVal [uiCurPos + 1]); break; + } + case UNK_LE_255_CODE: + { bLastCharWasSpace = FALSE; objLength = 2 + (FLMUINT) (psVal [uiCurPos+1]); break; - default: /* should NEVER happen: same as other code like this. */ + } + + default: + { psDestPtr[ uiDestPos++] = psVal [uiCurPos]; bLastCharWasSpace = FALSE; break; + } } } // On overflow - back out of the last character. + if( uiDestPos >= MAX_KEY_SIZ - 1) { uiDestPos = uiOldDestPos; bLastCharWasSpace = FALSE; } + // Handle the trailing space if present. // bLastCharWasSpace cannot be set to true if bNoSpace is true. + if( bLastCharWasSpace && uiDestPos && !bInputTruncated) { uiDestPos--; } + psDestPtr[ uiDestPos] = '\0'; *puuiDestLen = (FLMUINT) uiDestPos; -//Exit: return( rc); } +/**************************************************************************** +Desc: Convert a text string to a collated string. +****************************************************************************/ +RCODE AsiaFlmTextToColStr( + const FLMBYTE * Str, // Points to the internal TEXT string + FLMUINT StrLen, // Length of the internal TEXT string + FLMBYTE * ColStr, // Output collated string + FLMUINT * ColStrLenRV, // Collated string length return value + // Input value is MAX num of bytes in buffer + FLMUINT UppercaseFlag, // Set if to convert to uppercase + FLMUINT * puiCollationLen, // Returns the collation bytes length + FLMUINT * puiCaseLen, // Returns length of case bytes + FLMUINT uiCharLimit, // Max number of characters in this key piece + FLMBOOL bFirstSubstring, // TRUE is this is the first substring key + FLMBOOL * pbDataTruncated) +{ + RCODE rc = FERR_OK; + const FLMBYTE * pszStrEnd; + FLMUINT Length; + FLMUINT uiTargetColLen = *ColStrLenRV - 12; + FLMBYTE SubColBuf[MAX_SUBCOL_BUF + 1]; + FLMBYTE LowUpBuf[MAX_LOWUP_BUF + MAX_LOWUP_BUF + 2]; + FLMUINT ColLen; + FLMUINT SubColBitPos; + FLMUINT LowUpBitPos; + FLMUINT Flags; + FLMUINT16 NextWpChar; + FLMUINT16 UnicodeChar; + FLMUINT16 ColValue; + FLMBOOL bDataTruncated = FALSE; + + ColLen = 0; + SubColBitPos = 0; + LowUpBitPos = 0; + Flags = 0; + UnicodeChar = 0; + ColValue = 0; + + // Don't allow any key component to exceed 256 bytes regardless of the + // user-specified character or byte limit. The goal is to prevent any + // single key piece from consuming too much of the key (which is + // limited to 640 bytes) and thus "starving" other pieces, resulting in + // a key overflow error. + + if (uiTargetColLen > 256) + { + uiTargetColLen = 256; + } + + // Make sure SubColBuf and LowUpBuf are set to 0's + + f_memset( SubColBuf, 0, sizeof( SubColBuf)); + f_memset( LowUpBuf, 0, sizeof( LowUpBuf)); + + pszStrEnd = &Str[StrLen]; + NextWpChar = 0; + + while ((Str < pszStrEnd) || NextWpChar || UnicodeChar) + { + FLMUINT16 WpChar; // Current WP character + FLMUINT ObjLength; + FLMUINT16 SubColVal; // Sub-collated value (diacritic) + FLMBYTE CaseFlags; + + // Get the next character from the TEXT String. NOTE: OEM + // characters will be returned as character set ZERO, the character + // will be greater than 127. + + WpChar = NextWpChar; + + for (NextWpChar = 0; + (!WpChar || !NextWpChar) && !UnicodeChar && (Str < pszStrEnd); + Str += ObjLength) + { + FLMBYTE ObjType; + FLMBYTE CurByte; + FLMUINT16 CurWpChar = 0; + + CurByte = *Str; + ObjType = (FLMBYTE) (flmTextObjType( CurByte)); + ObjLength = 1; + + switch (ObjType) + { + case ASCII_CHAR_CODE: + { + CurWpChar = (FLMUINT16) CurByte; + break; + } + + case CHAR_SET_CODE: + { + ObjLength = 2; + CurWpChar = (FLMUINT16) (((FLMUINT16) (CurByte & + (~CHAR_SET_MASK)) << 8) + + (FLMUINT16) *(Str + 1)); + break; + } + + case WHITE_SPACE_CODE: + { + CurByte &= (~WHITE_SPACE_MASK); + CurWpChar = ((CurByte == HARD_HYPHEN) || + (CurByte == HARD_HYPHEN_EOL) || + (CurByte == HARD_HYPHEN_EOP)) + ? 0x2D // Minus sign - character set zero + : 0x20; // Space -- character set zero + break; + } + + case UNK_GT_255_CODE: + { + ObjLength = 1 + sizeof(FLMUINT16) + FB2UW( Str + 1); + break; + } + + case UNK_LE_255_CODE: + { + ObjLength = 2 + (FLMUINT16) * (Str + 1); + break; + } + + case UNK_EQ_1_CODE: + { + ObjLength = 2; + break; + } + + case EXT_CHAR_CODE: + { + ObjLength = 3; + CurWpChar = (FLMUINT16) (((FLMUINT16) *(Str + 1) << 8) + + (FLMUINT16) *(Str + 2)); + break; + } + + case OEM_CODE: + { + ObjLength = 2; + + // OEM characters are always >= 128. + // We use character set zero to process them. + + CurWpChar = (FLMUINT16) * (Str + 1); + break; + } + + case UNICODE_CODE: + { + ObjLength = 3; + UnicodeChar = (FLMUINT16) (((FLMUINT16) *(Str + 1) << 8) + + (FLMUINT16) *(Str + 2)); + CurWpChar = 0; + break; + } + + default: + { + // Shouldn't ever get to this point + + continue; + } + } + + if (!WpChar) + { + WpChar = CurWpChar; + } + else + { + NextWpChar = CurWpChar; + } + } + + // If we didn't get a character, break out of the outer processing + // loop. + + if (!WpChar && !UnicodeChar) + { + break; + } + + if (WpChar) + { + if (flmAsiaGetCollation( WpChar, NextWpChar, ColValue, &ColValue, + &SubColVal, &CaseFlags, + (FLMUINT16) UppercaseFlag) == 2) + { + + // Took the NextWpChar value + + NextWpChar = 0; + } + } + else + { + + // This handles all of the UNICODE characters that could not be + // converted to WP characters - which will include most of the + // Asian characters. + + CaseFlags = 0; + if (UnicodeChar < 0x20) + { + ColValue = 0xFFFF; + + // Setting SubColVal to a high code will ensure that the code + // that the UnicodeChar will be stored in its full 16 bits in + // the sub-collation area. + + SubColVal = 0xFFFF; + + // NOTE: UnicodeChar SHOULD NOT be set to zero here. It will + // be set to zero below. + + } + else + { + ColValue = UnicodeChar; + SubColVal = 0; + UnicodeChar = 0; + } + } + + // Store the values in 2 bytes + + ColStr[ColLen++] = (FLMBYTE) (ColValue >> 8); + ColStr[ColLen++] = (FLMBYTE) (ColValue & 0xFF); + + if (SubColVal) + { + Flags |= HAD_SUB_COLLATION; + if (SubColVal <= 31) // 5 bit - store bits 10 + { + SET_BIT( SubColBuf, SubColBitPos); + SubColBitPos += 1 + 1; // Stores a zero + SETnBITS( 5, SubColBuf, SubColBitPos, SubColVal); + + SubColBitPos += 5; + } + else // 2 bytes - store bits 110 or 11110 + { + FLMUINT Temp; + + SET_BIT( SubColBuf, SubColBitPos); + SubColBitPos++; + SET_BIT( SubColBuf, SubColBitPos); + SubColBitPos++; + + if (!WpChar && UnicodeChar) // Store as "11110" + { + SubColVal = UnicodeChar; + UnicodeChar = 0; + SET_BIT( SubColBuf, SubColBitPos); + SubColBitPos++; + SET_BIT( SubColBuf, SubColBitPos); + SubColBitPos++; + } + + SubColBitPos++; // Skip past the zero + + // Go to the next byte boundary to write the WP char + + SubColBitPos = (SubColBitPos + 7) & (~7); + Temp = BYTES_IN_BITS( SubColBitPos); + + // Need to store HIGH-Low - PC format is Low-high! + + SubColBuf[Temp] = (FLMBYTE) (SubColVal >> 8); + SubColBuf[Temp + 1] = (FLMBYTE) (SubColVal); + + SubColBitPos += 16; + } + } + else + { + SubColBitPos++; + } + + // Save case information - always 2 bits worth for asian + + if (CaseFlags & 0x02) + { + SET_BIT( LowUpBuf, LowUpBitPos); + } + + LowUpBitPos++; + + if (CaseFlags & 0x01) + { + SET_BIT( LowUpBuf, LowUpBitPos); + } + + LowUpBitPos++; + + // Check to see if ColLen is within 1 byte of max + + if ((ColLen >= uiCharLimit) || + (ColLen + BYTES_IN_BITS( SubColBitPos) + + BYTES_IN_BITS( LowUpBitPos) >= uiTargetColLen)) + { + + // Still something left? + + if ((Str < pszStrEnd) || NextWpChar || UnicodeChar) + { + bDataTruncated = TRUE; + } + + // Hit the max. number of characters + + break; + } + } + + if (puiCollationLen) + { + *puiCollationLen = ColLen; + } + + // Add the first substring marker - also serves as making the string + // non-null. + + if (bFirstSubstring) + { + ColStr[ColLen++] = 0; + ColStr[ColLen++] = COLL_FIRST_SUBSTRING; + } + + if (bDataTruncated) + { + ColStr[ColLen++] = 0; + ColStr[ColLen++] = COLL_TRUNCATED; + } + + if (!ColLen && !SubColBitPos) + { + if (puiCaseLen) + { + *puiCaseLen = 0; + } + + goto Exit; + } + + // Done putting the String into 3 sections - build the COLLATED KEY + + if (Flags & HAD_SUB_COLLATION) + { + ColStr[ColLen++] = 0; + ColStr[ColLen++] = COLL_MARKER | SC_SUB_COL; + + // Move the Sub-collation (diacritics) into the collating String + + Length = (FLMUINT) (BYTES_IN_BITS( SubColBitPos)); + f_memcpy( &ColStr[ColLen], SubColBuf, Length); + ColLen += Length; + } + + // Always represent the marker as 2 bytes and case bits in asia + + ColStr[ColLen++] = 0; + ColStr[ColLen++] = COLL_MARKER | SC_MIXED; + Length = (FLMUINT) (BYTES_IN_BITS( LowUpBitPos)); + + f_memcpy( &ColStr[ColLen], LowUpBuf, Length); + + if (puiCaseLen) + { + *puiCaseLen = (FLMUINT) (Length + 2); + } + + ColLen += Length; + +Exit: + + if (pbDataTruncated) + { + *pbDataTruncated = bDataTruncated; + } + + *ColStrLenRV = (FLMUINT) ColLen; + return (rc); +} + +/**************************************************************************** +Desc: Convert a text string to a collated string. + If FERR_CONV_DEST_OVERFLOW is returned the string is truncated as + best as it can be. The caller must decide to return the error up + or deal with the truncation. +Return: RCODE = SUCCESS or FERR_CONV_DEST_OVERFLOW +VISIT: If the string is EXACTLY the length of the truncation + length then it should, but doesn't, set the truncation flag. + The code didn't match the design intent. Fix next major + version. +****************************************************************************/ +RCODE FTextToColStr( + const FLMBYTE * pucStr, // Points to the internal TEXT string + FLMUINT uiStrLen, // Length of the internal TEXT string + FLMBYTE * pucCollatedStr, // Returns collated string + FLMUINT * puiCollatedStrLen, // Returns total collated string length + // Input is maximum bytes in buffer + FLMUINT uiUppercaseFlag, // Set if to convert to uppercase + FLMUINT * puiCollationLen, // Returns the collation bytes length + FLMUINT * puiCaseLen, // Returns length of case bytes + FLMUINT uiLanguage, // Language + FLMUINT uiCharLimit, // Max number of characters in this key piece + FLMBOOL bFirstSubstring, // TRUE is this is the first substring key + FLMBOOL * pbOriginalCharsLost, + FLMBOOL * pbDataTruncated) +{ + RCODE rc = FERR_OK; + const FLMBYTE * pucStrEnd; // Points to the end of the string + FLMUINT16 ui16Base; // Value of the base character + FLMUINT16 ui16SubColVal; // Sub-collated value (diacritic) + FLMUINT uiObjLength = 0; + FLMUINT uiLength; // Temporary variable for length + FLMUINT uiTargetColLen = *puiCollatedStrLen - 8; // 4=ovhd,4=worse char + FLMUINT uiObjType; + FLMBOOL bDataTruncated = FALSE; + + // Need to increase the buffer sizes to not overflow. + // Characaters without COLL values will take up 3 bytes in + // the ucSubColBuf[] and easily overflow the buffer. + // Hard coded the values so as to minimize changes. + + FLMBYTE ucSubColBuf[ MAX_SUBCOL_BUF + 301]; // Holds sub-collated values(diac) + FLMBYTE ucCaseBits[ MAX_LOWUP_BUF + 81]; // Holds case bits + FLMUINT16 ui16WpChr; // Current WP character + FLMUNICODE unichr = 0; // Current unconverted Unicode character + FLMUINT16 ui16WpChr2; // 2nd character if any; default 0 for US lang + FLMUINT uiColLen; // Return value of collated length + FLMUINT uiSubColBitPos; // Sub-collation bit position + FLMUINT uiCaseBitPos; // Case bit position + FLMUINT uiFlags; // Clear all bit flags + FLMBOOL bHebrewArabic = FALSE; // Set if language is hebrew, arabic, farsi + FLMBOOL bTwoIntoOne; + + uiColLen = 0; + uiSubColBitPos = 0; + uiCaseBitPos = 0; + uiFlags = 0; + ui16WpChr2 = 0; + + // Don't allow any key component to exceed 256 bytes regardless of the + // user-specified character or byte limit. The goal is to prevent + // any single key piece from consuming too much of the key (which is + // limited to 640 bytes) and thus "starving" other pieces, resulting + // in a key overflow error. + + if( uiTargetColLen > 256) + { + uiTargetColLen = 256; + } + + // Code below sets ucSubColBuf[] and ucCaseBits[] values to zero. + + if (uiLanguage != US_LANG) + { + if (uiLanguage == AR_LANG || // Arabic + uiLanguage == FA_LANG || // Farsi - persian + uiLanguage == HE_LANG || // Hebrew + uiLanguage == UR_LANG) // Urdu + { + bHebrewArabic = TRUE; + } + } + pucStrEnd = &pucStr [uiStrLen]; + + while (pucStr < pucStrEnd) + { + + // Set the case bits and sub-collation bits to zero when + // on the first bit of the byte. + + if (!(uiCaseBitPos & 0x07)) + { + ucCaseBits [uiCaseBitPos >> 3] = 0; + } + if (!(uiSubColBitPos & 0x07)) + { + ucSubColBuf [uiSubColBitPos >> 3] = 0; + } + + // Get the next character from the TEXT string. + + for (ui16WpChr = ui16SubColVal = 0; // Default sub-collation value + !ui16WpChr && pucStr < pucStrEnd; + pucStr += uiObjLength) + { + FLMBYTE ucChar = *pucStr; + + uiObjType = flmTextObjType( ucChar); + switch (uiObjType) + { + case ASCII_CHAR_CODE: // 0nnnnnnn + { + uiObjLength = 1; + + // Character set zero is assumed. + + ui16WpChr = (FLMUINT16)ucChar; + continue; + } + + case CHAR_SET_CODE: // 10nnnnnn + { + uiObjLength = 2; + + // Character set followed by character + + ui16WpChr = (((FLMUINT16)(ucChar & (~CHAR_SET_MASK)) << 8) + + (FLMUINT16)*(pucStr + 1)); + continue; + } + + case WHITE_SPACE_CODE: // 110nnnnn + { + uiObjLength = 1; + ucChar &= (~WHITE_SPACE_MASK); + ui16WpChr = (ucChar == HARD_HYPHEN || + ucChar == HARD_HYPHEN_EOL || + ucChar == HARD_HYPHEN_EOP) + ? (FLMUINT16)0x2D // Minus sign -- character set 0 + : (FLMUINT16)0x20;// Space -- character set zero + continue; + } + + case UNK_GT_255_CODE: + { + uiObjLength = 3 + FB2UW( pucStr + 1); + continue; + } + + case UNK_LE_255_CODE: + { + uiObjLength = 2 + (FLMUINT16)*(pucStr + 1); + continue; + } + + case UNK_EQ_1_CODE: + { + uiObjLength = 2; + continue; + } + + case EXT_CHAR_CODE: + { + uiObjLength = 3; + + // Character set followed by character + + ui16WpChr = (((FLMUINT16)*(pucStr + 1) << 8) + + (FLMUINT16)*(pucStr + 2)); + continue; + } + + case OEM_CODE: + { + + // OEM characters are always >= 128 + // Use character set zero to process them. + + uiObjLength = 2; + ui16WpChr = (FLMUINT16)*(pucStr + 1); + continue; + } + + case UNICODE_CODE: // Unconvertable UNICODE code + { + uiObjLength = 3; + + // Unicode character followed by unicode character set + + unichr = (FLMUINT16)(((FLMUINT16)*(pucStr + 1) << 8) + + (FLMUINT16)*(pucStr + 2)); + ui16WpChr = UNK_UNICODE_CODE; + continue; + } + + default: + { + + // Should not happen, but don't return an error + + flmAssert( 0); + continue; + } + } + } + + // If we didn't get a character, break out of while loop. + + if (!ui16WpChr) + { + break; + } + + // flmCheckDoubleCollation modifies ui16WpChr if a digraph or a double + // character sequence is found. If a double character is found, pucStr + // is incremented and ui16WpChr2 is set to 1. If a digraph is found, + // pucStr is not changed, but ui16WpChr contains the first character and + // ui16WpChr2 contains the second character of the digraph. + + if (uiLanguage != US_LANG) + { + ui16WpChr2 = flmCheckDoubleCollation( &ui16WpChr, &bTwoIntoOne, + &pucStr, uiLanguage); + } + + // Save the case bit + + if (!uiUppercaseFlag) + { + + // charIsUpper returns TRUE if upper case, 0 if lower case. + + if (!charIsUpper( ui16WpChr)) + { + uiFlags |= HAD_LOWER_CASE; + } + else + { + + // Set if upper case. + + SET_BIT( ucCaseBits, uiCaseBitPos); + } + + uiCaseBitPos++; + } + + // Handle OEM characters, non-collating characters, + // characters with subcollating values, double collating + // values. + + // Get the collated value from the WP character-if not collating value + + if ((pucCollatedStr[ uiColLen++] = + (FLMBYTE)(flmGetCollation( ui16WpChr, uiLanguage))) >= COLS11) + { + FLMUINT uiTemp; + + // Save OEM characters just like non-collating characters + + // If lower case, convert to upper case. + + if (!charIsUpper( ui16WpChr)) + { + ui16WpChr &= ~1; + } + + // No collating value given for this WP char. + // Save original WP char (2 bytes) in subcollating + // buffer. + + // 1110 is a new code that will store an insert over + // the character OR a non-convertable unicode character. + // Store with the same alignment as "store_extended_char" + // below. + + // 11110 is code for unmappable UNICODE value. + // A value 0xFE will be the collation value. The sub-collation + // value will be 0xFFFF followed by the UNICODE value. + // Be sure to eat an extra case bit. + + // See specific Hebrew and Arabic comments in the + // switch statement below. + + // Set the next byte that follows in the sub collation buffer. + + ucSubColBuf [(uiSubColBitPos + 8) >> 3] = 0; + + if (bHebrewArabic && (pucCollatedStr [uiColLen-1] == COLS0_ARABIC)) + { + + // Store first bit of 1110, fall through & store remaining 3 bits + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos++; + + // Don't store collation value + + uiColLen--; + } + else if (unichr) + { + ui16WpChr = unichr; + unichr = 0; + + // Store 11 out of 11110 + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos++; + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos++; + + if (!uiUppercaseFlag) + { + ucCaseBits [(uiCaseBitPos + 7) >> 3] = 0; + + // Set upper case bit. + + SET_BIT( ucCaseBits, uiCaseBitPos); + uiCaseBitPos++; + } + } + +store_extended_char: + + // Set the next byte that follows in the sub collation buffer. + + ucSubColBuf [(uiSubColBitPos + 8) >> 3] = 0; + ucSubColBuf [(uiSubColBitPos + 16) >> 3] = 0; + uiFlags |= HAD_SUB_COLLATION; + + // Set 110 bits in sub-collation - continued from above. + // No need to explicitly set the zero, but must increment + // for it. + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos++; + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos += 2; + + // store_aligned_word: This label is not referenced. + // Go to the next byte boundary to write the character. + + uiSubColBitPos = (uiSubColBitPos + 7) & (~7); + uiTemp = BYTES_IN_BITS( uiSubColBitPos); + + // Need to big-endian - so it will sort correctly. + + ucSubColBuf [uiTemp] = (FLMBYTE)(ui16WpChr >> 8); + ucSubColBuf [uiTemp + 1] = (FLMBYTE)(ui16WpChr); + uiSubColBitPos += 16; + ucSubColBuf [uiSubColBitPos >> 3] = 0; + } + else + { + // Had a collation value + // Add the lower/uppercase bit if a mixed case output. + // If not lower ASCII set - check diacritic value for sub-collation + + if (!(ui16WpChr & 0xFF00)) + { + + // ASCII character set - set a single 0 bit - just need to + // increment to do this. + + uiSubColBitPos++; + } + else + { + FLMBYTE ucTmpChar = (FLMBYTE)ui16WpChr; + FLMBYTE ucCharSet = (FLMBYTE)(ui16WpChr >> 8); + + // Convert char to uppercase because case information + // is stored above. This will help + // ensure that the "ETA" doesn't sort before "eta" + + if (!charIsUpper(ui16WpChr)) + { + ui16WpChr &= ~1; + } + + switch (ucCharSet) + { + case CHSMUL1: // Multinational 1 + { + + // If we cannot break down a char into base and + // diacritic we cannot combine the charaacter + // later when converting back the key. In that case, + // write the entire WP char in the sub-collation area. + + if (flmCh6Brkcar( ui16WpChr, &ui16Base, &ui16SubColVal)) + { + goto store_extended_char; + } + + // Write the FLAIM diacritic sub-collation value. + // Prefix is 2 bits "10". Remember to leave + // "111" alone for the future. + // NOTE: The "unlaut" character must sort after the "ring" + // character. + + ui16SubColVal = ((ui16SubColVal & 0xFF) == umlaut && + (uiLanguage == SU_LANG || + uiLanguage == SV_LANG || + uiLanguage == CZ_LANG || + uiLanguage == SL_LANG)) + ? (FLMUINT16)(flmDia60Tbl[ ring] + 1) + : (FLMUINT16)(flmDia60Tbl[ ui16SubColVal & 0xFF]); + +store_sub_col: + // Set the next byte that follows in the sub collation buffer. + + ucSubColBuf[ (uiSubColBitPos + 8) >> 3] = 0; + uiFlags |= HAD_SUB_COLLATION; + + // Set the 10 bits - no need to explicitly set the zero, but + // must increment for it. + + SET_BIT( ucSubColBuf, uiSubColBitPos); + uiSubColBitPos += 2; + + // Set sub-collation bits. + + SETnBITS( 5, ucSubColBuf, uiSubColBitPos, ui16SubColVal); + uiSubColBitPos += 5; + break; + } + + case CHSGREK: // Greek + { + if (ucTmpChar >= 52 || // Keep case bit for 52-69 else ignore + ui16WpChr == 0x804 || // [ 8,4] BETA Medial | Terminal + ui16WpChr == 0x826) // [ 8,38] SIGMA terminal + { + goto store_extended_char; + } + + // No subcollation to worry about - set a zero bit by + // incrementing the bit position. + + uiSubColBitPos++; + break; + } + + case CHSCYR: + { + if (ucTmpChar >= 144) + { + goto store_extended_char; + } + + // No subcollation to worry about - set a zero bit by + // incrementing the bit position. + + uiSubColBitPos++; + + // VISIT: Georgian covers 208-249 - no collation defined yet + + break; + } + + case CHSHEB: // Hebrew + { + // Three sections in Hebrew: + // 0..26 - main characters + // 27..83 - accents that apear over previous character + // 84..118- dagesh (ancient) hebrew with accents + + // Because the ancient is only used for sayings & scriptures + // we will support a collation value and in the sub-collation + // store the actual character because sub-collation is in + // character order. + + if (ucTmpChar >= 84) // Save ancient - value 84 and above + { + goto store_extended_char; + } + + // No subcollation to worry about - set a zero bit by + // incrementing the bit position. + + uiSubColBitPos++; + break; + } + + case CHSARB1: // Arabic 1 + { + // Three sections in Arabic: + // 00..37 - accents that display OVER a previous character + // 38..46 - symbols + // 47..57 - numbers + // 58..163 - characters + // 164 - hamzah accent + // 165..180- common characters with accents + // 181..193- ligatures - common character combinations + // 194..195- extensions - throw away when sorting + + if (ucTmpChar <= 46) + { + goto store_extended_char; // save original character + } + + if (pucCollatedStr[ uiColLen-1] == COLS10a+1) // Alef? + { + ui16SubColVal = (ucTmpChar >= 165) + ? (FLMUINT16)(flmAlefSubColTbl[ ucTmpChar - 165 ]) + : (FLMUINT16)7; // Alef subcol value + goto store_sub_col; + } + + if (ucTmpChar >= 181) // Ligatures - char combination + { + goto store_extended_char; // save original character + } + + if (ucTmpChar == 64) // taa exception + { + ui16SubColVal = 8; + goto store_sub_col; + } + + // No subcollation to worry about - set a zero bit by + // incrementing the bit position. + + uiSubColBitPos++; + break; + } + + case CHSARB2: // Arabic 2 + { + + // There are some characters that share the same slot + // Check the bit table if above character 64 + + if (ucTmpChar >= 64 && + flmAr2BitTbl[(ucTmpChar - 64) >> 3] & + (0x80 >> (ucTmpChar & 0x07))) + { + goto store_extended_char; // Will save original + } + + // No subcollation to worry about - set a zero bit by + // incrementing the bit position. + + uiSubColBitPos++; + break; + } + + default: + { + // Increment bit position to set a zero bit. + + uiSubColBitPos++; + break; + } + } + } + + // Now let's worry about double character sorting + + if (ui16WpChr2) + { + if (pbOriginalCharsLost) + { + *pbOriginalCharsLost = TRUE; + } + + // Set the next byte that follows in the sub collation buffer. + + ucSubColBuf [(uiSubColBitPos + 7) >> 3] = 0; + + if (bTwoIntoOne) + { + // Sorts after character in ui16WpChr after call to + // flmCheckDoubleCollation + // Write the char 2 times so lower/upper bits are correct. + // Could write infinite times because of collation rules. + + pucCollatedStr[ uiColLen] = ++pucCollatedStr[ uiColLen-1]; + uiColLen++; + + // If original was upper case, set one more upper case bit + + if (!uiUppercaseFlag) + { + ucCaseBits[ (uiCaseBitPos + 7) >> 3] = 0; + if (!charIsUpper( (FLMUINT16) *(pucStr - 1))) + { + uiFlags |= HAD_LOWER_CASE; + } + else + { + SET_BIT( ucCaseBits, uiCaseBitPos); + } + + uiCaseBitPos++; + } + + // Take into account the diacritical space + + uiSubColBitPos++; + } + else + { + // We have a digraph, get second collation value + + pucCollatedStr[ uiColLen++] = + (FLMBYTE)(flmGetCollation( ui16WpChr2, uiLanguage)); + + // Normal case, assume no diacritics set + + uiSubColBitPos++; + + // If first was upper, set one more upper bit. + + if (!uiUppercaseFlag) + { + ucCaseBits [(uiCaseBitPos + 7) >> 3] = 0; + if (charIsUpper( ui16WpChr)) + { + SET_BIT( ucCaseBits, uiCaseBitPos); + } + uiCaseBitPos++; + + // no need to reset the uiFlags + } + } + } + } + + // Check to see if uiColLen is at some overflow limit. + + if (uiColLen >= uiCharLimit || + uiColLen + BYTES_IN_BITS( uiSubColBitPos) + + BYTES_IN_BITS( uiCaseBitPos) >= uiTargetColLen) + { + + // We hit the maximum number of characters. + + if (pucStr < pucStrEnd) + { + bDataTruncated = TRUE; + } + + break; + } + } + + if (puiCollationLen) + { + *puiCollationLen = uiColLen; + } + + // Add the first substring marker - also serves as making the string non-null. + + if (bFirstSubstring) + { + pucCollatedStr [uiColLen++] = COLL_FIRST_SUBSTRING; + } + + if (bDataTruncated) + { + pucCollatedStr[ uiColLen++ ] = COLL_TRUNCATED; + } + + if (!uiColLen && !uiSubColBitPos) + { + if (puiCaseLen) + { + *puiCaseLen = 0; + } + goto Exit; + } + + // Store extra zero bit in the sub-collation area for Hebrew/Arabic + + if (bHebrewArabic) + { + uiSubColBitPos++; + } + + // Done putting the string into 4 sections - build the COLLATED KEY + // Don't set uiUppercaseFlag earlier than here because SC_LOWER may be zero + + uiUppercaseFlag = (uiLanguage == GR_LANG) ? SC_LOWER : SC_UPPER; + + // The default terminating characters is (COLL_MARKER|SC_UPPER) + // Did we write anything to the subcollation area? + + if (uiFlags & HAD_SUB_COLLATION) + { + // Writes out a 0x7 + + pucCollatedStr [uiColLen++] = COLL_MARKER | SC_SUB_COL; + + // Move the sub-collation into the collating string + + uiLength = BYTES_IN_BITS( uiSubColBitPos); + f_memcpy( &pucCollatedStr[uiColLen], ucSubColBuf, uiLength); + uiColLen += uiLength; + } + + // Move the upper/lower case stuff - force bits for Greek ONLY + // This is such a small size that a memcpy is not worth it + + if (uiFlags & HAD_LOWER_CASE) + { + FLMUINT uiNumBytes = BYTES_IN_BITS( uiCaseBitPos); + FLMBYTE * pucCasePtr = ucCaseBits; + + // Output the 0x5 + + pucCollatedStr [uiColLen++] = (FLMBYTE)(COLL_MARKER | SC_MIXED); + if (puiCaseLen) + { + *puiCaseLen = uiNumBytes + 1; + } + + if (uiUppercaseFlag == SC_LOWER) + { + + // Negate case bits for languages (like GREEK) that sort + // upper case before lower case. + + while (uiNumBytes--) + { + pucCollatedStr [uiColLen++] = ~(*pucCasePtr++); + } + } + else + { + while (uiNumBytes--) + { + pucCollatedStr [uiColLen++] = *pucCasePtr++; + } + } + } + else + { + + // All characters are either upper or lower case, as determined + // by uiUppercaseFlag. + + pucCollatedStr [uiColLen++] = (FLMBYTE)(COLL_MARKER | uiUppercaseFlag); + if( puiCaseLen) + { + *puiCaseLen = 1; + } + } + +Exit: + + if( pbDataTruncated) + { + *pbDataTruncated = bDataTruncated; + } + + *puiCollatedStrLen = uiColLen; + return( rc); +} + +/**************************************************************************** +Desc: Return the sub-collation value of a WPText character. + Unconvered Unicode values always have a sub-collation + value of 11110 + Unicode Value. +****************************************************************************/ +FLMUINT16 flmTextGetSubCol( + FLMUINT16 ui16WPValue, // WP Character value. + FLMUINT16 ui16ColValue, // Collation Value (for arabic) + FLMUINT uiLangId) // WP Language ID. +{ + FLMUINT16 ui16SubColVal; + FLMBYTE byCharVal; + FLMBYTE byCharSet; + FLMUINT16 ui16Base; + + // Easy case first. + + ui16SubColVal = 0; + if( (ui16WPValue & 0xFF00 ) == 0) + { + goto Exit; + } + + // From here down default ui16SubColVal is WP value. + + ui16SubColVal = ui16WPValue; + + byCharVal = (FLMBYTE) ui16WPValue; + byCharSet = (FLMBYTE) (ui16WPValue >> 8); + + // Convert char to uppercase because case information + // is stored above. This will help + // insure that the "ETA" doesn't sort before "eta" + // could use is lower code here for added performance. + + // This just happens to work with all WP character values + + if (!flmIsUpper( ui16WPValue)) + { + ui16WPValue &= ~1; + } + + switch( byCharSet) + { + case CHSMUL1: + { + // If you cannot break down a char into base and + // diacritic then you cannot combine the charaacter + // later when converting back the key. So, write + // the entire WP char in the sub-collation area. + // We can ONLY SUPPORT MULTINATIONAL 1 for brkcar() + + if( flmCh6Brkcar( ui16WPValue, &ui16Base, &ui16SubColVal)) + { + + // WordPerfect character cannot be broken down. + // If we had a collation value other than 0xFF (COLS0), don't + // return a sub-collation value. This will allow things like + // upper and lower AE digraphs to compare properly. + + if (ui16ColValue != COLS0) + { + ui16SubColVal = 0; + } + goto Exit; + } + + // Write the FLAIM diacritic sub-collation value. + // Prefix is 2 bits "10". Remember to leave + // "111" alone for the future. + + ui16SubColVal = ((ui16SubColVal & 0xFF) == umlaut && + ((uiLangId == SU_LANG) || + (uiLangId == SV_LANG) || + (uiLangId == CZ_LANG) || + (uiLangId == SL_LANG))) + ? (FLMUINT16)(flmDia60Tbl[ ring] + 1) + : (FLMUINT16)(flmDia60Tbl[ ui16SubColVal & 0xFF]); + + break; + } + + case CHSGREK: + { + if( (byCharVal >= 52) || (ui16WPValue == 0x804) || + (ui16WPValue == 0x826)) + { + ui16SubColVal = ui16WPValue; + } + break; + } + + case CHSCYR: + { + if( byCharVal >= 144) + { + ui16SubColVal = ui16WPValue; + } + break; + } + + case CHSHEB: + { + + // Three sections in Hebrew: + // 0..26 - main characters + // 27..83 - accents that apear over previous character + // 84..118- dagesh (ancient) hebrew with accents + // + // Because the ancient is only used for sayings & scriptures + // we will support a collation value and in the sub-collation + // store the actual character because sub-collation is in + // character order. + + if( byCharVal >= 84) + { + ui16SubColVal = ui16WPValue; + } + + break; + } + + case CHSARB1: + { + + // Three sections in Arabic: + // 00..37 - accents that display OVER a previous character + // 38..46 - symbols + // 47..57 - numbers + // 58..163 - characters + // 164 - hamzah accent + // 165..180- common characters with accents + // 181..193- ligatures - common character combinations + // 194..195- extensions - throw away when sorting + + if( byCharVal <= 46 ) + { + ui16SubColVal = ui16WPValue; + } + else + { + if( ui16ColValue == COLS10a + 1) + { + ui16SubColVal = (byCharVal >= 165) + ? (FLMUINT16)(flmAlefSubColTbl[ byCharVal - 165 ]) + : (FLMUINT16)7; // Alef subcol value + } + else + { + if( byCharVal >= 181) // Ligatures - char combination + { + ui16SubColVal = ui16WPValue; + } + else if( byCharVal == 64) // taa exception + { + ui16SubColVal = 8; + } + } + } + break; + } + + case CHSARB2: + { + // There are some characters that share the same slot + // Check the bit table if above character 64 + + if ((byCharVal >= 64) && + (flmAr2BitTbl[(byCharVal-64)>> 3] & (0x80 >> (byCharVal&0x07)))) + { + ui16SubColVal = ui16WPValue; + } + + break; + } + } + +Exit: + + return( ui16SubColVal); +} + +/**************************************************************************** +Desc: Get the original string from an asian collation string Ret: Length + of the word string in bytes +****************************************************************************/ +FLMUINT AsiaConvertColStr( + FLMBYTE* CollatedStr, // Points to the Flaim collated string + FLMUINT* CollatedStrLenRV, // Length of the Flaim collated string + FLMBYTE* WordStr, // Output string to build - WP word string + FLMBOOL* pbDataTruncated, // Set to TRUE if data was truncated + FLMBOOL* pbFirstSubstring) // Set to TRUE if marker exists +{ + FLMBYTE* pWordStr = WordStr; + FLMUINT Length = *CollatedStrLenRV; // May optimize as a register + FLMUINT CollStrPos = 0; // Position in CollatedStr[] + FLMBOOL bHadExtended = FALSE; + FLMUINT WordStrLen; + FLMUINT16 ColChar; // 2 byte value for asian + + while (Length) + { + FLMBYTE CharVal; + FLMBYTE CharSet; + + CharSet = CollatedStr[CollStrPos]; + CharVal = CollatedStr[CollStrPos + 1]; + ColChar = (FLMUINT16) ((CharSet << 8) + CharVal); + + if (ColChar <= MAX_COL_OPCODE) + { + break; + } + + CollStrPos += 2; + Length -= 2; + + if (CharSet == 0) // Normal Latin/Greek/Cyrillic value + { + ColChar = colToWPChr[CharVal - COLLS]; + } + else if (CharSet == 1) // katakana or hiragana character + { + if (CharVal > sizeof(ColToKanaTbl)) // Special cases below + { + if (CharVal == COLS_ASIAN_MARK_VAL) + { // dakuten + ColChar = 0x240a; + } + else if (CharVal == COLS_ASIAN_MARK_VAL + 1) + { // handakuten + ColChar = 0x240b; + } + else if (CharVal == COLS_ASIAN_MARK_VAL + 2) + { // chuuten + ColChar = 0x2405; + } + else + { + ColChar = 0xFFFF; // error + } + } + else + { + ColChar = (FLMUINT16) (0x2600 + ColToKanaTbl[CharVal]); + } + } + else if (CharSet != 0xFF || CharVal != 0xFF) // Asian characters + { + + // Insert zeroes that will be treated as a signal for + // uncoverted unicode characters later on. NOTE: Cannot use + // 0xFFFF, because we need to be able to detect this case in + // the sub-collation stuff, and we don't want to confuse it + // with the 0xFFFF that may have been inserted in another + // case. THIS IS A REALLY BAD HACK, BUT IT IS THE BEST WE CAN + // DO FOR NOW! + + *pWordStr++ = 0; + *pWordStr++ = 0; + bHadExtended = TRUE; + } + + // else does not have a collation value - found in sub-collation + // part + + UW2FBA( ColChar, pWordStr); // Put the uncollation value back + pWordStr += 2; + } + + UW2FBA( 0, pWordStr); // NULL Terminate the string + WordStrLen = (FLMUINT) (pWordStr - WordStr); + + // Parse through the sub-collation and case information. + // Watch out for COMP CollStrPosT indexes-doesn't have case info after + // Here are values for some of the codes: + // [ 0x01] - end for fields case info follows - for COMP POST indexes + // [ 0x02] - compound marker + // [ 0x05] - case bits follow + // [ 0x06] - case information is all uppercase + // [ 0x07] - beginning of sub-collation information + // [ 0x08] - first substring field that is made + // [ 0x09] - truncation marker for text and binary + // + // Asian chars the case information should always be there and not + // compressed out. This is because the case information could change + // the actual width of the character from 0x26xx to charset 11. + + if (Length) + { + ColChar = (FLMUINT16) ((CollatedStr[CollStrPos] << 8) + + CollatedStr[CollStrPos + 1]); + + // First substring is before truncated. + + if (ColChar == COLL_FIRST_SUBSTRING) + { + if (pbFirstSubstring) + { + *pbFirstSubstring = TRUE; // Don't need to initialize to FALSE. + } + + Length -= 2; + CollStrPos += 2; + ColChar = (FLMUINT16) ((CollatedStr[CollStrPos] << 8) + + CollatedStr[CollStrPos + 1]); + } + + if (ColChar == COLL_TRUNCATED) + { + if (pbDataTruncated) + { + *pbDataTruncated = TRUE; // Don't need to initialize to FALSE. + } + + Length -= 2; + CollStrPos += 2; + ColChar = (FLMUINT16) ((CollatedStr[CollStrPos] << 8) + + CollatedStr[CollStrPos + 1]); + } + + if (ColChar == (COLL_MARKER | SC_SUB_COL)) + { + FLMUINT TempLen; + + // Do another pass on the word string adding diacritics/voicings + + CollStrPos += 2; + Length -= 2; + TempLen = AsiaParseSubCol( WordStr, &WordStrLen, + &CollatedStr[CollStrPos]); + CollStrPos += TempLen; + Length -= TempLen; + } + else + { + goto check_case; + } + } + + // Does the case info follow? - It may not because of post indexes + + if (Length) + { + ColChar = (FLMUINT16) ((CollatedStr[CollStrPos] << 8) + + CollatedStr[CollStrPos + 1]); +check_case: + + if (ColChar == (COLL_MARKER | SC_MIXED)) + { + CollStrPos += 2; + CollStrPos += AsiaParseCase( WordStr, &WordStrLen, + &CollatedStr[CollStrPos]); + + // Set bHadExtended to FALSE, because they will have been taken + // care of in this pass. + + bHadExtended = FALSE; + } + } + + // Change embedded zeroes to 0xFFFFs + + if (bHadExtended) + { + FLMUINT uiCnt; + FLMBYTE* pucTmp; + + for (uiCnt = 0, pucTmp = WordStr; + uiCnt < WordStrLen; + uiCnt += 2, pucTmp += 2) + { + if (FB2UW( pucTmp) == 0) + { + UW2FBA( 0xFFFF, pucTmp); + } + } + } + + // Following marker is 2 bytes if post otherwise will be 1 byte ; + // Should make a pass and count the extended characters + + *CollatedStrLenRV = CollStrPos; // value should be on 0x01 or 0x02 flag + return (WordStrLen); // Return the length of the word string +} + +/**************************************************************************** +Desc: Combine the diacritic 5 and 16 bit values to an existing word + string. + +Ret: Number of bytes parsed + +Notes: For each bit in the sub-collation section: + 0 - no subcollation information + 10 - take next 5 bits - will tell about diacritics + or japanese vowel + 110 - align to next byte and take word value as extended + character +****************************************************************************/ +FLMUINT AsiaParseSubCol( + FLMBYTE * WordStr, // Existing word string to modify + FLMUINT * puiWordStrLen, // Wordstring length in bytes + FLMBYTE * SubColBuf) // Diacritic values in 5 bit sets +{ + FLMUINT SubColBitPos = 0; + FLMUINT NumWords = *puiWordStrLen >> 1; + FLMUINT16 Diac; + FLMUINT16 WpChar; + + // For each word in the word string ... + + while (NumWords--) + { + + // Have to skip 0, because it is not accounted for in the + // sub-collation bits. It was inserted when we encountered + // unconverted unicode characters (Asian). Will be converted to + // something else later on. SEE NOTE ABOVE. + + if (FB2UW( WordStr) == 0) + { + WordStr += 2; + continue; + } + + // This macro DOESN'T increment bitPos + + if (TEST1BIT( SubColBuf, SubColBitPos)) + { + + // Bits 10 - take next 5 bits Bits 110 align and take next word + // Bits 11110 align and take unicode value + // + + SubColBitPos++; + + if (!TEST1BIT( SubColBuf, SubColBitPos)) + { + SubColBitPos++; + Diac = (FLMUINT16) (GETnBITS( 5, SubColBuf, SubColBitPos)); + SubColBitPos += 5; + + if ((WpChar = FB2UW( WordStr)) < 0x100) + { + if ((WpChar >= 'A') && (WpChar <= 'Z')) + { + + // Convert to WP diacritic and combine characters + + flmCh6Cmbcar( &WpChar, WpChar, (FLMUINT16) ml1_COLtoD[Diac]); + + // Even if cmbcar fails, WpChar is still set to a valid + // value + } + else // Symbols from charset 0x24 + { + WpChar = (FLMUINT16) (0x2400 + + flmCh24ColTbl[Diac - 1].ByteValue); + } + } + else if (WpChar >= 0x2600) // Katakana + { + + // Voicings - will allow to select original char + // 000 - some 001 are changed to 000 to save space + // 001 - set if large char (uppercase) + // 010 - set if voiced + // 100 - set if half voiced + // + // Should NOT match voicing or wouldn't be here! + + FLMBYTE CharVal = (FLMBYTE) (WpChar & 0xFF); + + // Try exceptions first so don't access out of bounds + + if (CharVal == 84) + { + WpChar = (FLMUINT16) (0x2600 + ((Diac == 1) + ? (FLMUINT16) 10 + : (FLMUINT16) 11)); + } + else if (CharVal == 85) + { + WpChar = (FLMUINT16) (0x2600 + ((Diac == 1) + ? (FLMUINT16) 16 + : (FLMUINT16) 17)); + } + + // Try the next 2 slots, if not then value is 83,84 or 85 + + else if (flmKanaSubColTbl[CharVal + 1] == Diac) + { + WpChar++; + } + else if ((flmKanaSubColTbl[CharVal + 2] == Diac)) + { + WpChar += 2; + } + + // last exception below + + else if (CharVal == 4) + { + WpChar = 0x2600 + 83; + } + + // else leave alone! - invalid storage + + } + + UW2FBA( WpChar, WordStr); // Set if changed or not + } + else // "110" + { + FLMUINT Temp; + + SubColBitPos++; // Skip second '1' + + if (TEST1BIT( SubColBuf, SubColBitPos)) + { + + // Unconvertable UNICODE character ; + // The format will be 4 bytes, 0xFF, 0xFF, 2 byte Unicode + + shiftN( WordStr, (FLMUINT16) (NumWords + NumWords + 4), 2); + + WordStr += 2; // Skip the 0xFFFF for now + SubColBitPos += 2; // Skip next "11" + (*puiWordStrLen) += 2; + } + + SubColBitPos++; // Skip the zero + + // Round up to next byte + + SubColBitPos = (SubColBitPos + 7) & (~7); + Temp = BYTES_IN_BITS( SubColBitPos); + WordStr[1] = SubColBuf[Temp]; // Character set + WordStr[0] = SubColBuf[Temp + 1]; // Character + SubColBitPos += 16; + } + } + else + { + SubColBitPos++; // Be sure to increment this! + } + + WordStr += 2; // Next WP character + } + + return (BYTES_IN_BITS( SubColBitPos)); +} + +/**************************************************************************** +Desc: The case bits for asia are: + Latin/Greek/Cyrillic + 01 - case bit set if character is uppercase + 10 - double wide character in CS 0x25xx, 0x26xx and 0x27xx + Japanese + 00 - double wide hiragana 0x255e..25b0 + 01 - double wide katakana 0x2600..2655 + 10 - single wide symbols from charset 11 that map to CS24?? + 11 - single wide katakana from charset 11 +****************************************************************************/ +FLMUINT AsiaParseCase( + FLMBYTE * WordStr, // Existing word string to modify + FLMUINT * WordStrLenRV, // Length of the WordString in bytes + FLMBYTE * pCaseBits) // Lower/upper case bit string +{ + FLMUINT WordStrLen = *WordStrLenRV; + FLMUINT uiWordCnt; + FLMUINT uiExtraBytes = 0; + FLMUINT16 WpChar; + FLMBYTE TempByte = 0; + FLMBYTE MaskByte; + + // For each character in the word string ... + + for (uiWordCnt = WordStrLen >> 1, + MaskByte = 0; + uiWordCnt--;) + { + FLMBYTE CharSet; + FLMBYTE CharVal; + + WpChar = FB2UW( WordStr); // Get the next character + + // Must skip any 0xFFFFs or zeroes that were inserted. + + if (WpChar == 0xFFFF || WpChar == 0) + { + + // Put back 0xFFFF in case it was a zero. + + UW2FBA( 0xFFFF, WordStr); + WordStr += 2; + uiExtraBytes += 2; + continue; + } + + if (MaskByte == 0) // Time to get another byte + { + TempByte = *pCaseBits++; + MaskByte = 0x80; + } + + CharSet = (FLMBYTE) (WpChar >> 8); + CharVal = (FLMBYTE) (WpChar & 0xFF); + + if (WpChar < 0x2400) // SINGLE WIDE - NORMAL CHARACTERS + { + if (TempByte & MaskByte) // convert to double wide? + { + + // Latin/greek/cyrillic Convert to uppercase double wide char + + if (CharSet == 0) // Latin - uppercase + { + + // May convert to 0x250F (Latin) or CS24 + + if (WpChar >= 'A' && WpChar <= 'Z') + { + // Convert to double wide + + WpChar = (FLMUINT16) (WpChar - 0x30 + 0x250F); + } + else + { + HanToZenkaku( WpChar, 0, &WpChar); + } + } + else if (CharSet == 8) // Greek + { + if (CharVal > 38) + { // Adjust for spaces in greek + CharVal -= 2; + } + + if (CharVal > 4) + { + CharVal -= 2; + } + + WpChar = (FLMUINT16) ((CharVal >> 1) + 0x265E); + } + else if (CharSet == 10) // Cyrillic + { + WpChar = (FLMUINT16) ((CharVal >> 1) + 0x2700); + } + else + { + HanToZenkaku( WpChar, 0, &WpChar); + } + + CharSet = (FLMBYTE) (WpChar >> 8); // Less code this way + CharVal = (FLMBYTE) (WpChar & 0xFF); + } + + MaskByte >>= 1; // Next bit + + if ((TempByte & MaskByte) == 0) // Change to lower case? + { + switch (CharSet) // Convert WpChar to lower case + { + case 0: + { + WpChar |= 0x20; // Bit zero only if lower case + break; + } + + case 1: + { + if (CharVal >= 26) + { + WpChar++; + } + + break; + } + + case 8: + { + if (CharVal <= 69) + { // All lowercase after 69 + WpChar++; + } + + break; + } + + case 10: + { + if (CharVal <= 199) + { // No cases after 199 + WpChar++; + } + + break; + } + + case 0x25: + case 0x26: + { + // should be double wide latin or greek + + WpChar += 0x20; // Add offset to convert to lowercase + break; + } + + case 0x27: // double wide cyrillic only + { + WpChar += 0x30; // Add offset to convert to lowercase + break; + } + } + } + } + else // JAPANESE CHARACTERS + { + if (TempByte & MaskByte) // Original chars from + // CharSet 11 + { + if (CharSet == 0x26) // Convert to ZenToHankaku + { + FLMUINT16 NextChar = 0; + + WpChar = ZenToHankaku( WpChar, &NextChar); + + if (NextChar) // Move everyone down + { + uiWordCnt++; + shiftN( WordStr, uiWordCnt + uiWordCnt + 2, 2); + UW2FBA( WpChar, WordStr); + WordStr += 2; + WpChar = NextChar; // Store this below + + *WordStrLenRV = *WordStrLenRV + 2; // Adjust length + + // Don't change WordStrLen - returns number of bits used + } + } + else if (CharSet == 0x24) + { + WpChar = ZenToHankaku( WpChar, (FLMUINT16*) 0); + } + + MaskByte >>= 1; // Eat next bit + } + else + { + MaskByte >>= 1; // Next bit + if ((TempByte & MaskByte) == 0) // Convert to hiragana? + { + // kanji will also fall through here + + if (CharSet == 0x26) + { + WpChar = (FLMUINT16) (0x255E + CharVal); // Convert to + // hiragana + } + } + } + } + + UW2FBA( WpChar, WordStr); + WordStr += 2; + MaskByte >>= 1; + } + + // Should be 2 bits for each character + + uiWordCnt = WordStrLen - uiExtraBytes; + return (BYTES_IN_BITS( uiWordCnt)); +} + +/**************************************************************************** +Desc: Returns the collation value of the input WP character. + If in charset 11 will convert the character to Zenkaku (double wide). +In: ui16WpChar - Char to collate off of - could be in CS0..14 or x24..up + ui16NextWpChar - next WP char for CS11 voicing marks + ui16PrevColValue - previous collating value - for repeat/vowel repeat + pui16ColValue - returns 2 byte collation value + pui16SubColVal - 0, 6 or 16 bit value for the latin sub collation + or the kana size & vowel voicing + 001 - set if large (upper) character + 010 - set if voiced + 100 - set if half voiced + + pucCaseBits - returns 2 bits + Latin/Greek/Cyrillic + 01 - case bit set if character is uppercase + 10 - double wide character in CS 0x25xx, 0x26xx and 0x27xx + Japanese + 00 - double wide hiragana 0x255e..25b0 + 01 - double wide katakana 0x2600..2655 + 10 - double wide symbols that map to charset 11 + 11 - single wide katakana from charset 11 +Ret: 0 - no valid collation value + high values set for pui16ColValue + Sub-collation gets original WP character value + 1 - valid collation value + 2 - valid collation value and used the ui16NextWpChar + +Terms: HANKAKU - single wide characters in charsets 0..14 + ZENKAKU - double wide characters in charsets 0x24..end of kanji + KANJI - collation values are 0x2900 less than WPChar value +****************************************************************************/ +FLMUINT16 flmAsiaGetCollation( + FLMUINT16 ui16WpChar, // WP char to get collation values + FLMUINT16 ui16NextWpChar, // Next WP char - for CS11 voicing marks + FLMUINT16 ui16PrevColValue, // Previous collating value + FLMUINT16 * pui16ColValue, // Returns collation value + FLMUINT16 * pui16SubColVal, // Returns sub-collation value + FLMBYTE * pucCaseBits, // Returns case bits value + FLMUINT16 uiUppercaseFlag) // Set if to convert to uppercase +{ + FLMUINT16 ui16ColValue; + FLMUINT16 ui16SubColVal; + FLMBYTE ucCaseBits = 0; + FLMBYTE ucCharSet = ui16WpChar >> 8; + FLMBYTE ucCharVal = ui16WpChar & 0xFF; + FLMUINT16 ui16Hankaku; + FLMUINT uiLoop; + FLMUINT16 ui16ReturnValue = 1; + + ui16ColValue = ui16SubColVal = 0; + + // Kanji or above + + if (ucCharSet >= 0x2B) + { + + // Puts 2 or above into high byte. + + ui16ColValue = ui16WpChar - 0x2900; + + // No subcollation or case bits need to be set + + goto Exit; + } + + // Single wide character? (HANKAKU) + + if (ucCharSet < 11) + { + + // Get the values from a non-asian character LATIN, GREEK or + // CYRILLIC. The width bit may have been set on a jump to label from + // below. + +Latin_Greek_Cyrillic: + + // YES: Pass US_LANG because this is what we want - Prevents double + // character sorting. + + ui16ColValue = flmGetCollation( ui16WpChar, US_LANG); + + if (uiUppercaseFlag || flmIsUpper( ui16WpChar)) + { + + // Uppercase - set case bit + + ucCaseBits |= SET_CASE_BIT; + } + + // Character for which there is no collation value? + + if (ui16ColValue == COLS0) + { + ui16ReturnValue = 0; + + if (!flmIsUpper( ui16WpChar)) + { + // Convert to uppercase + + ui16WpChar--; + } + + ui16ColValue = 0xFFFF; + ui16SubColVal = ui16WpChar; + } + else if (ucCharSet) // Don't bother with ascii + { + if (!flmIsUpper( ui16WpChar)) + { + // Convert to uppercase + + ui16WpChar--; + } + + if (ucCharSet == CHSMUL1) + { + FLMUINT16 ui16Base; + FLMUINT16 ui16Diacritic; + + ui16SubColVal = !flmCh6Brkcar( ui16WpChar, &ui16Base, &ui16Diacritic) + ? flmDia60Tbl[ui16Diacritic & 0xFF] + : ui16WpChar; + } + else if (ucCharSet == CHSGREK) // GREEK + { + if (ui16WpChar >= 0x834 || // [8,52] or above + ui16WpChar == 0x804 || // [8,4] BETA Medial | Terminal + ui16WpChar == 0x826) + { + // [8,38] SIGMA terminal + + ui16SubColVal = ui16WpChar; + } + } + else if (ucCharSet == CHSCYR) // CYRILLIC + { + if (ui16WpChar >= 0xA90) // [10, 144] or above + { + ui16SubColVal = ui16WpChar; // Dup collation values + } + } + + // else don't need a sub collation value + + } + + goto Exit; + } + + // Single wide Japanese character? + + if (ucCharSet == 11) + { + FLMUINT16 ui16KanaChar; + + // Convert charset 11 to Zenkaku (double wide) CS24 or CS26 hex. + // All characters in charset 11 will convert to CS24 or CS26. When + // combining the collation and the sub-collation values. + + if (HanToZenkaku( ui16WpChar, ui16NextWpChar, &ui16KanaChar) == 2) + { + // Return 2 + + ui16ReturnValue++; + } + + ucCaseBits |= SET_WIDTH_BIT; // Set so will allow to go back + ui16WpChar = ui16KanaChar; // If in CS24 will fall through + // to ZenKaku + ucCharSet = ui16KanaChar >> 8; + ucCharVal = ui16KanaChar & 0xFF; + } + + if (ui16WpChar < 0x2400) + { + // In some other character set + + goto Latin_Greek_Cyrillic; + } + else if (ui16WpChar >= 0x255e && ui16WpChar <= 0x2655) + { + if (ui16WpChar >= 0x2600) + { + ucCaseBits |= SET_KATAKANA_BIT; + } + + // HIRAGANA and KATAKANA Kana contains both hiragana and katakana. + // The tables contain the same characters in same order + + if (ucCharSet == 0x25) + { + // Change value to be in character set 26 + + ucCharVal -= 0x5E; + } + + ui16ColValue = 0x0100 + KanaColTbl[ucCharVal]; + ui16SubColVal = flmKanaSubColTbl[ucCharVal]; + goto Exit; + } + + if ((ui16Hankaku = ZenToHankaku( ui16WpChar, (FLMUINT16*) 0)) != 0) + { + if ((ui16Hankaku >> 8) != 11) + { + ui16WpChar = ui16Hankaku; + ucCharSet = ui16WpChar >> 8; + ucCharVal = ui16WpChar & 0xFF; + ucCaseBits |= SET_WIDTH_BIT; + goto Latin_Greek_Cyrillic; + } + } + + // 0x2400..0x24bc Japanese symbols that cannot be converted to + // Hankaku. All 6 original symbol chars from 11 will also be here. + // First try to find a collation value of the symbol. The sub-collation + // value will be the position in the CS24 table + 1. + + for (uiLoop = 0; + uiLoop < (sizeof(flmCh24ColTbl) / sizeof(BYTE_WORD_TBL)); + uiLoop++) + { + if (ucCharVal == flmCh24ColTbl[uiLoop].ByteValue) + { + if ((ui16ColValue = flmCh24ColTbl[uiLoop].WordValue) < 0x100) + { + // Don't save for chuuten, dakuten, handakuten + + ui16SubColVal = (FLMUINT16) (uiLoop + 1); + } + + break; + } + } + + if (!ui16ColValue) + { + // Now see if it's a repeat or repeat-vowel character + + if ((((ucCharVal >= 0x12) && (ucCharVal <= 0x15)) || + (ucCharVal == 0x17) || (ucCharVal == 0x18)) && + ((ui16PrevColValue >> 8) == 1)) + { + ui16ColValue = ui16PrevColValue; + + // Store original WP character + + ui16SubColVal = ui16WpChar; + } + else if ((ucCharVal == 0x1B) && // repeat vowel? + (ui16PrevColValue >= 0x100) && + (ui16PrevColValue < COLS_ASIAN_MARKS)) // Previous kana char? + { + ui16ColValue = 0x0100 + KanaColToVowel[ui16PrevColValue & 0xFF]; + + // Store original WP character + + ui16SubColVal = ui16WpChar; + } + else + { + ui16ReturnValue = 0; + ui16ColValue = 0xFFFF; // No collation value + ui16SubColVal = ui16WpChar; // Never have changed if gets here + } + } + +Exit: + + *pui16ColValue = ui16ColValue; + *pui16SubColVal = ui16SubColVal; + *pucCaseBits = ucCaseBits; + + return (ui16ReturnValue); +} + +/***************************************************************************** +Desc: Get the Flaim collating string and convert back to a WP word string +Ret: Length of new WP word string +*****************************************************************************/ +FLMUINT FWWSGetColStr( + FLMBYTE * fColStr, // Points to the Flaim collated string + FLMUINT * fcStrLenRV, // Length of the Flaim collated string + FLMBYTE * wordStr, // Output string to build - WP word string + FLMUINT fWPLang, // FLAIM WP language number + FLMBOOL * pbDataTruncated, // Set to TRUE if truncated + FLMBOOL * pbFirstSubstring) // Sets to TRUE if first substring +{ + FLMBYTE * wsPtr = wordStr; // Points to the word string data area + FLMUINT length = *fcStrLenRV; // May optimize as a register + FLMUINT pos = 0; // Position in fColStr[] + FLMUINT bitPos; // Computed bit position + FLMUINT colChar; // Not portable if a FLMBYTE value + FLMUINT wdStrLen; + FLMBOOL hebrewArabicFlag = 0; // Set if hebrew/arabic language + + // WARNING: The code is duplicated for performance reasons. The US code + // below is much more optimized so any changes must be done twice. + + if (fWPLang != US_LANG) // Code for NON-US languages + { + if ((fWPLang == AR_LANG) || // Arabic + (fWPLang == FA_LANG) || // Farsi - persian + (fWPLang == HE_LANG) || // Hebrew + (fWPLang == UR_LANG)) // Urdu + { + hebrewArabicFlag++; + } + + while (length && (fColStr[pos] > MAX_COL_OPCODE)) + { + length--; + colChar = (FLMUINT) fColStr[pos++]; + + switch (colChar) + { + case COLS9 + 4: // ch in spanish + case COLS9 + 11: // ch in czech + { + // Put the WP char in the word string + + UW2FBA( (FLMUINT16) 'C', wsPtr); + wsPtr += 2; + colChar = (FLMUINT) 'H'; + pos++; // move past second duplicate char + break; + } + + case COLS9 + 17: // ll in spanish + { + // Put the WP char in the word string + + UW2FBA( (FLMUINT16) 'L', wsPtr); + wsPtr += 2; + colChar = (FLMUINT) 'L'; + pos++; // move past duplicate character + break; + } + + case COLS0: // Non collating character + { + // Actual character is in sub-collation area + + colChar = (FLMUINT) 0xFFFF; + break; + } + + default: + { + + if (hebrewArabicFlag && (colChar >= COLS10h)) + { + colChar = (colChar < COLS10a) + ? (FLMUINT) (0x900 + (colChar - (COLS10h))) // Hebrew + : (FLMUINT) (HebArabColToWPChr[colChar - (COLS10a)]); // Arabic + } + else + { + colChar = (FLMUINT) colToWPChr[colChar - COLLS]; + } + + break; + } + } + + UW2FBA( (FLMUINT16) colChar, wsPtr); + wsPtr += 2; + } + } + else + { + while (length && (fColStr[pos] > MAX_COL_OPCODE)) + { + length--; + + // Move in the WP value given uppercase collated value + + colChar = (FLMUINT) fColStr[pos++]; + + if (colChar == COLS0) + { + colChar = (FLMUINT) 0xFFFF; + } + else + { + colChar = (FLMUINT) colToWPChr[colChar - COLLS]; + } + + UW2FBA( (FLMUINT16) colChar, wsPtr); + wsPtr += 2; + } + } + + // NULL Terminate the string + + UW2FBA( (FLMUINT16) 0, wsPtr); + wdStrLen = pos + pos; + + // Parse through the sub-collation and case information. + // Watch out for COMP CollStrPosT indexes-doesn't have case info after + // Here are values for some of the codes: + // [ 0x01] - end for fields case info follows - for COMP POST indexes + // [ 0x02] - compound marker + // [ 0x05] - case bits follow + // [ 0x06] - case information is all uppercase + // [ 0x07] - beginning of sub-collation information + // [ 0x08] - first substring field that is made + // [ 0x09] - truncation marker for text and binary + // + // Asian chars the case information should always be there and not + // compressed out. This is because the case information could change + // the actual width of the character from 0x26xx to charset 11. + + if (length && fColStr[pos] == COLL_FIRST_SUBSTRING) + { + if (pbFirstSubstring) + { + *pbFirstSubstring = TRUE; // Don't need to initialize to FALSE. + } + + length--; + pos++; + } + + if (length && fColStr[pos] == COLL_TRUNCATED) + { + if (pbDataTruncated) + { + *pbDataTruncated = TRUE; // Don't need to initialize to FALSE. + } + + length--; + pos++; + } + + if (length && (fColStr[pos] == (COLL_MARKER | SC_SUB_COL))) + { + FLMUINT tempLen; + + // Do another pass on the word string adding the diacritics + + bitPos = FWWSCmbSubColBuf( wordStr, &wdStrLen, &fColStr[++pos], + hebrewArabicFlag); + + // Move pos to next byte value + + tempLen = BYTES_IN_BITS( bitPos); + pos += tempLen; + length -= tempLen + 1; // The 1 includes the 0x07 byte + } + + // Does the case info follow? + + if (length && (fColStr[pos] > COMPOUND_MARKER)) + { + + // Take care of the lower and upper case conversion If mixed case + // then convert using case bits + + if (fColStr[pos++] & SC_MIXED) // Increment pos here! + { + + // Don't pre-increment pos on line below! + + pos += FWWSToMixed( wordStr, wdStrLen, &fColStr[pos], fWPLang); + } + + // else 0x04 or 0x06 - all characters already in uppercase + + } + + *fcStrLenRV = pos; // pos should be on the 0x01 or 0x02 flag + return (wdStrLen); // Return the length of the word string +} + +/************************************************************************** +Desc: Combine the diacritic 5 bit values to an existing word string +Todo: May want to check flmCh6Cmbcar() for CY return value +***************************************************************************/ +FLMUINT FWWSCmbSubColBuf( + FLMBYTE* wordStr, // Existing word string to modify + FLMUINT* wdStrLenRV, // Wordstring length in bytes + FLMBYTE* subColBuf, // Diacritic values in 5 bit sets + FLMBOOL hebrewArabicFlag) // Set if language is Hebrew or Arabic +{ + FLMUINT subColBitPos = 0; + FLMUINT numWords = *wdStrLenRV >> 1; + FLMUINT16 diac; + FLMUINT16 wpchar; + FLMUINT temp; + + // For each word in the word string ... + + while (numWords--) + { + + // Label used for hebrew/arabic - additional subcollation can follow ; + // This macro DOESN'T increment bitPos + + if (TEST1BIT( subColBuf, subColBitPos)) + { + + // If "11110" - unmappable unicode char - 0xFFFF is before it + // If "1110" then INDEX extended char is inserted + // If "110" then extended char follows that replaces collation + // If "10" then take next 5 bits which contain the diacritic + // subcollation value. + +after_last_character: + + subColBitPos++; // Eat the first 1 bit + + if (!TEST1BIT( subColBuf, subColBitPos)) + { + subColBitPos++; // Eat the 0 bit + diac = (FLMUINT16) (GETnBITS( 5, subColBuf, subColBitPos)); + subColBitPos += 5; + + if ((wpchar = FB2UW( wordStr)) < 0x100) // If not extended base.. + { + + // Convert to WP diacritic and combine characters + + flmCh6Cmbcar( &wpchar, wpchar, (FLMUINT16) ml1_COLtoD[diac]); + + // Even if cmbcar fails, wpchar is still set to a valid + // value + + UW2FBA( wpchar, wordStr); + } + else if ((wpchar & 0xFF00) == 0x0D00) // arabic? + { + wpchar = ArabSubColToWPChr[diac]; + UW2FBA( wpchar, wordStr); + } + + // else diacritic is extra info ; + // cmbcar should not handle extended chars for this design + } + else // "110" or "1110" or "11110" + { + subColBitPos++; // Eat the 2nd '1' bit + if (TEST1BIT( subColBuf, subColBitPos)) // Test the 3rd bit + { + + // 1110 - shift wpchars down 1 word and insert value below + + subColBitPos++; // Eat the 3rd '1' bit + *wdStrLenRV += 2; // Return 2 more bytes + + if (TEST1BIT( subColBuf, subColBitPos)) // Test 4th bit + { + + // Unconvertable UNICODE character. + // + // The format will be 4 bytes, 0xFF, 0xFF, 2 byte Unicode + + shiftN( wordStr, numWords + numWords + 4, 2); + subColBitPos++; // Eat the 4th '1' bit + wordStr += 2; // Skip the 0xFFFF for now + } + else + { + // Move down 2 byte NULL and rest of the 2 byte characters. + // The extended character does not have a 0xFF col value + + shiftN( wordStr, numWords + numWords + 2, 2); + numWords++; + } + } + + subColBitPos++; // Skip past the zero bit + subColBitPos = (subColBitPos + 7) & (~7); // roundup to next byte + temp = BYTES_IN_BITS( subColBitPos); // compute position + wordStr[1] = subColBuf[temp]; // Character set + wordStr[0] = subColBuf[temp + 1]; // Character + + subColBitPos += 16; + } + } + else + { + subColBitPos++; + } + + wordStr += 2; // Next WP character + } + + if (hebrewArabicFlag) + { + if (TEST1BIT( subColBuf, subColBitPos)) + { + + // Hebrew/Arabic can have trailing accents that don't have a + // matching collation value. Keep looping in this case. Note that + // subColBitPos isn't incremented above. + + numWords = 0; // set so won't loop forever! + goto after_last_character; // process trailing bit + } + + subColBitPos++; // Eat the last '0' bit + } + + return (subColBitPos); +} + +/************************************************************************** +Desc: Convert the word string to lower case chars given low/upp bit string +Out: WP characters have modified to their original case +Ret: Number of bytes used in the lower/upper buffer +Notes: Only WP to lower case conversion is done here for each bit NOT set. +***************************************************************************/ +FLMUINT FWWSToMixed( + FLMBYTE * wordStr, // Existing word string to modify + FLMUINT wdStrLen, // Length of the wordstring in bytes + FLMBYTE* lowUpBitStr, // Lower/upper case bit string + FLMUINT fWPLang) +{ + FLMUINT numWords; + FLMUINT tempWord; + FLMBYTE tempByte = 0; + FLMBYTE maskByte; + FLMBYTE xorByte; + + xorByte = (fWPLang == US_LANG) + ? (FLMBYTE) 0 + : (fWPLang == GR_LANG) + ? (FLMBYTE) 0xFF + : (FLMBYTE) 0; + + // For each word in the word string ... + + for (numWords = wdStrLen >> 1, maskByte = 0; + numWords--; + wordStr += 2, maskByte >>= 1) + { + if (maskByte == 0) // Time to get another byte + { + tempByte = xorByte ^ *lowUpBitStr++; + maskByte = 0x80; + } + + if ((tempByte & maskByte) == 0) // If lowercase conver - else is upper + { + + // Convert to lower case - COLL -> WP is already in upper case + + tempWord = (FLMUINT) FB2UW( wordStr); + + if ((tempWord >= ASCII_UPPER_A) && (tempWord <= ASCII_UPPER_Z)) + { + tempWord |= 0x20; + } + else + { + FLMBYTE charVal = (FLMBYTE) (tempWord & 0xFF); + FLMBYTE charSet = (FLMBYTE) (tempWord >> 8); + + // check if charact within region of character set + + if (((charSet == CHSMUL1) && + ((charVal >= 26) && (charVal <= 241))) || + ((charSet == CHSGREK) && (charVal <= 69)) || + ((charSet == CHSCYR) && (charVal <= 199))) + { + tempWord |= 0x01; + } + } + + UW2FBA( (FLMUINT16) tempWord, wordStr); + } + } + + numWords = wdStrLen >> 1; + return (BYTES_IN_BITS( numWords)); +} + +/******************************************************************** +Desc: Build a responce tree of NODEs for the key output. +*********************************************************************/ +RCODE flmIxKeyOutput( + IXD * pIxd, + FLMBYTE * pucFromKey, + FLMUINT uiKeyLen, + FlmRecord ** ppKeyRV, // Returns key + FLMBOOL bFullFldPaths) // If true add full field paths +{ + RCODE rc = FERR_OK; + FlmRecord * pKey = NULL; + void * pvField; + FLMBYTE ucKeyBuf[ MAX_KEY_SIZ + 12]; + FLMBYTE * pucToKey = &ucKeyBuf[ 0]; + FLMBYTE * pucPostBuf = NULL; + IFD * pIfd; + FLMUINT uiLongValue; + FLMUINT uiToKeyLen; + FLMUINT uiLanguage = pIxd->uiLanguage; + FLMUINT uiFromKeyLen; + FLMUINT uiFromRemaining; + FLMUINT uiPostLen; + FLMUINT uiPostPos; + FLMUINT uiTempFromKeyLen; + FLMUINT uiFldType; + FLMUINT uiDataType; + FLMBOOL bDataRightTruncated; + FLMBOOL bFirstSubstring; + FLMBOOL bSigSign; + FLMBYTE ucTemp; + FLMUINT uiContainer; + FLMUINT uiMaxKeySize; + + // If the index is on all containers, see if this key has + // a container component. If so, strip it off. + + if( (uiContainer = pIxd->uiContainerNum) == 0) + { + FLMUINT uiContainerPartLen = getIxContainerPartLen( pIxd); + + if (uiKeyLen <= uiContainerPartLen) + { + flmAssert( 0); + rc = RC_SET( FERR_BTREE_ERROR); + goto Exit; + } + + uiContainer = getContainerFromKey( pucFromKey, uiKeyLen); + + // Subtract off the bytes for the container part. + + uiKeyLen -= uiContainerPartLen; + uiMaxKeySize = MAX_KEY_SIZ - uiContainerPartLen; + } + else + { + uiMaxKeySize = MAX_KEY_SIZ; + } + + flmAssert( uiLanguage != 0xFFFF); + + if (*ppKeyRV) + { + if( (*ppKeyRV)->isReadOnly() || (*ppKeyRV)->isCached()) + { + (*ppKeyRV)->Release(); + *ppKeyRV = NULL; + } + else + { + (*ppKeyRV)->clear(); + } + } + + if( (pKey = *ppKeyRV) == NULL) + { + if( (pKey = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + *ppKeyRV = pKey; + } + + pKey->setContainerID( uiContainer); + + uiFromKeyLen = uiFromRemaining = uiKeyLen; + pIfd = pIxd->pFirstIfd; + + // If post index, get post low/up section. + + if( pIfd->uiFlags & IFD_POST ) + { + + // Last byte has low/upper length + + uiPostLen = pucFromKey[ uiFromKeyLen - 1 ]; + pucPostBuf = &pucFromKey[ uiFromKeyLen - uiPostLen - 1 ]; + uiPostPos = 0; + } + + if (RC_BAD( rc = pKey->insertLast( 0, FLM_KEY_TAG, FLM_CONTEXT_TYPE, NULL))) + { + goto Exit; + } + + // Loop for each compound piece of key + + for( ;;) + { + FLMBOOL bIsAsianCompound; + FLMUINT uiMarker; + + bDataRightTruncated = bFirstSubstring = FALSE; + + bIsAsianCompound = (FLMBOOL)(((uiLanguage >= FIRST_DBCS_LANG) && + (uiLanguage <= LAST_DBCS_LANG) && + (IFD_GET_FIELD_TYPE( pIfd) == FLM_TEXT_TYPE) && + (!(pIfd->uiFlags & IFD_CONTEXT))) + ? (FLMBOOL)TRUE + : (FLMBOOL)FALSE); + + uiMarker = (FLMUINT)((bIsAsianCompound) + ? (FLMUINT)((FLMUINT)(*pucFromKey << 8) + + *(pucFromKey+1)) + : (FLMUINT) *pucFromKey); + uiFldType = (FLMUINT) IFD_GET_FIELD_TYPE( pIfd); + uiDataType = IFD_GET_FIELD_TYPE( pIfd); + + // Hit a compound marker or end of key marker + // Check includes COMPOUND_MARKER & END_COMPOUND_MARKER + + if( uiMarker <= NULL_KEY_MARKER) + { + + // If the field is required or single field then generate an empty node. + + if( ((pIfd->uiFlags & IFD_OPTIONAL) == 0) || + (uiFldType == FLM_TEXT_TYPE) || + (uiFldType == FLM_BINARY_TYPE) || + ((pIfd->uiFlags & IFD_LAST) && !pIfd->uiCompoundPos )) + { + if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, + uiDataType, bFullFldPaths, pKey, &pvField))) + goto Exit; + } + if( uiMarker == END_COMPOUND_MARKER) // Used for post keys + break; + + uiFromKeyLen = 0; // This piece is zero - skip it - may be others + } + else + { + + // If compound key or if only field used in index + // output the key elements field number or else 'NA' + + if( pIfd->uiFlags & IFD_CONTEXT) + { + if( RC_BAD( rc = flmBuildKeyPaths( pIfd, + flmBigEndianToUINT16( &pucFromKey [1]), + uiDataType, bFullFldPaths, pKey, &pvField))) + { + goto Exit; + } + uiFromKeyLen = KY_CONTEXT_LEN; + } + + else + { + if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, + uiDataType, bFullFldPaths, pKey, &pvField))) + { + goto Exit; + } + + // Grab only the Nth section of key if compound key + // Null out key if uiToKeyLen gets 0 + + UD2FBA( 0, pucToKey); + + switch( uiDataType) + { + case FLM_TEXT_TYPE: + + uiTempFromKeyLen = uiFromKeyLen; + uiToKeyLen = FColStrToText( pucFromKey, &uiTempFromKeyLen, pucToKey, + uiLanguage, pucPostBuf, &uiPostPos, + &bDataRightTruncated, &bFirstSubstring); + uiFromKeyLen = uiTempFromKeyLen; + break; + + case FLM_NUMBER_TYPE: + { + FLMUINT uiFirstColNibble; // Current collated nibble + FLMUINT uiFirstNumNibble; // Current output nibble + FLMBYTE * pucOutPtr; // Output pointer + FLMBYTE * pucColPtr; + FLMUINT uiBytesProcessed; + + // Start at byte after sign/magnitude byte + + pucColPtr = pucFromKey + 1; + uiBytesProcessed = 1; + uiFirstColNibble = 1; + + // Determine the sign of the number + + pucOutPtr = pucToKey; + if( (bSigSign = (*pucFromKey & SIG_POS)) == 0) + { + *pucOutPtr = 0xB0; + uiFirstNumNibble = 0; + } + else + { + uiFirstNumNibble = 1; + } + + // Parse through the collated number outputting data + // to the buffer as we go. + + for( ;;) + { + // Determine what we are pointing at + + if( (ucTemp = *pucColPtr) <= COMPOUND_MARKER) + { + break; + } + + if( uiFirstColNibble++ & 1) + { + ucTemp >>= 4; + } + else + { + ucTemp &= 0x0F; + pucColPtr++; + uiBytesProcessed++; + } + + // A hex F signifies the end of a collated number with an + // odd number of nibbles + + if( ucTemp == 0x0F) + { + break; + } + + // Convert collated number nibble to BCD nibble + // and lay it in buffer + + ucTemp -= COLLATED_DIGIT_OFFSET; + + // Is number negative? + + if( !bSigSign) + { + // Negative values are ~ed + + ucTemp = (FLMBYTE)(10 -(ucTemp + 1)); + } + + if( uiFirstNumNibble++ & 1) + { + *pucOutPtr = (FLMBYTE)(ucTemp << 4); + } + else + { + *pucOutPtr++ += ucTemp; + } + + if( uiBytesProcessed == uiFromKeyLen) + { + break; + } + } + + // Append Terminator code to internal number + + *pucOutPtr++ |= (uiFirstNumNibble & 1) ? 0xFF : 0x0F; + uiToKeyLen = (FLMUINT) (pucOutPtr - pucToKey); + uiFromKeyLen = uiBytesProcessed; + rc = FERR_OK; + break; + } + + case FLM_BINARY_TYPE: + { + FLMUINT uiMaxLength; + FLMBYTE * pucSrc = pucFromKey; + + uiMaxLength = ((uiFromKeyLen >> 1) < uiMaxKeySize) + ? (FLMUINT)(uiFromKeyLen >> 1) + : (FLMUINT)uiMaxKeySize; + uiToKeyLen = 0; + while( (uiToKeyLen < uiMaxLength) && ((ucTemp = *pucSrc) >= COLLS)) + { + + // Take two bytes from source to make one byte in dest + + pucToKey[ uiToKeyLen++] = + (FLMBYTE)(((ucTemp - COLLS) << 4) + (*(pucSrc + 1) - COLLS)); + pucSrc += 2; + } + + if( (uiToKeyLen < (uiFromKeyLen >> 1)) && (*pucSrc >= COLLS)) + { + rc = RC_SET( FERR_CONV_DEST_OVERFLOW); + } + else + { + rc = FERR_OK; + uiFromKeyLen = uiToKeyLen << 1; + + // FLAIM has a bug where the binary fields don't have + // the COLL_TRUNCATED value on truncated values. + // The good news is that we know the true length of + // binary fields. + if( *pucSrc == COLL_TRUNCATED) + { + uiFromKeyLen++; + bDataRightTruncated = TRUE; + } + else if( uiToKeyLen >= pIfd->uiLimit) + { + bDataRightTruncated = TRUE; + } + } + break; + } + + case FLM_CONTEXT_TYPE: + default: + uiFromKeyLen = 5; + + uiLongValue = flmBigEndianToUINT32( pucFromKey + 1); + UD2FBA( (FLMUINT32)uiLongValue, pucToKey); + uiToKeyLen = 4; + break; + } + + if( RC_BAD( rc)) + { + goto Exit; + } + + // Allocate and Copy Value into the node + + if( uiToKeyLen) + { + FLMBYTE * pucValue; + + if( RC_BAD(rc = pKey->allocStorageSpace( pvField, + uiDataType, uiToKeyLen, 0, 0, 0, &pucValue, NULL))) + { + goto Exit; + } + + f_memcpy( pucValue, pucToKey, uiToKeyLen); + } + + // Set first sub-string and truncated flags. + + if( (pIfd->uiFlags & IFD_SUBSTRING) && !bFirstSubstring) + { + pKey->setLeftTruncated( pvField, TRUE); + } + if( bDataRightTruncated) + { + pKey->setRightTruncated( pvField, TRUE); + } + } + } + + // Compute variables for next section of compound key + // Add 1 for compound marker if still is stuff in key + + if( uiFromRemaining != uiFromKeyLen) + { + uiFromKeyLen += (FLMUINT)(bIsAsianCompound ? (FLMUINT)2 : (FLMUINT)1); + } + + pucFromKey += uiFromKeyLen; + + if( (uiFromKeyLen = (uiFromRemaining -= uiFromKeyLen)) == 0) + { + break; + } + + while( ((pIfd->uiFlags & IFD_LAST) == 0) + && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) + { + pIfd++; + } + + if( pIfd->uiFlags & IFD_LAST) + { + break; + } + + pIfd++; + } + + // Check if we have one field left. + + if( (pIfd->uiFlags & IFD_LAST) == 0) + { + while( (pIfd->uiFlags & IFD_LAST) == 0) + { + pIfd++; + } + if( (pIfd->uiFlags & IFD_OPTIONAL) == 0) + { + if( RC_BAD( rc = flmBuildKeyPaths( pIfd, pIfd->uiFldNum, + uiDataType, bFullFldPaths, pKey, &pvField))) + { + goto Exit; + } + } + } + +Exit: + + return( rc); +} + +/**************************************************************************** +Desc: This module will read all references of an index key. + The references will be output number defined as REFS_PER_NODE +****************************************************************************/ +RCODE flmBuildKeyPaths( + IFD * pIfd, + FLMUINT uiFldNum, + FLMUINT uiDataType, + FLMBOOL bFullFldPaths, + FlmRecord * pKey, + void ** ppvField) +{ + RCODE rc = FERR_OK; + void * pvField; + void * pvParentField; + void * pvChildField; + FLMUINT * pFieldPath; + FLMUINT uiTempDataType; + FLMUINT uiFieldPos; + FLMUINT uiTargetFieldID; + + if( !bFullFldPaths) + { + rc = pKey->insertLast( 1, uiFldNum, uiDataType, &pvField); + goto Exit; + } + + pFieldPath = pIfd->pFieldPathPToC; + pvParentField = pKey->root(); + uiFieldPos = 0; + + // Loop finding field matches. + + pvField = pKey->find( pvParentField, pFieldPath[ uiFieldPos]); + if( pvField) + { + pvParentField = pvField; + uiFieldPos++; + uiTargetFieldID = pFieldPath[ uiFieldPos]; + + // Loop finding matching children from this point on. + + for( pvChildField = pKey->firstChild( pvParentField); pvChildField; ) + { + if( pKey->getFieldID( pvChildField) == uiTargetFieldID) + { + // On the child field? + + if( pFieldPath[ uiFieldPos + 1] == 0) + { + pvField = pvChildField; + + // Set the data type in case the data length is zero. + + pKey->allocStorageSpace( pvField, uiDataType, 0, 0, 0, 0, NULL, NULL); + break; + } + + pvParentField = pvChildField; + uiFieldPos++; + uiTargetFieldID = pFieldPath[ uiFieldPos]; + pvChildField = pKey->firstChild( pvParentField); + } + else + { + pvChildField = pKey->nextSibling( pvChildField); + } + } + } + + // Insert the rest of the field path down to the value field (uiFieldPos==0). + + uiTempDataType = FLM_CONTEXT_TYPE; + for( ; pFieldPath[ uiFieldPos]; uiFieldPos++) + { + // Add the real data type for the last field, otherwise set as context. + + if( pFieldPath[ uiFieldPos + 1] == 0) + { + uiTempDataType = uiDataType; + } + + if( RC_BAD( rc = pKey->insert( pvParentField, INSERT_LAST_CHILD, + pFieldPath[ uiFieldPos], uiTempDataType, &pvField))) + { + goto Exit; + } + pvParentField = pvField; + } + +Exit: + + *ppvField = pvField; + return( rc); +} + +/**************************************************************************** +Desc: Compare only the leading left and right characters according + to the many flags that are passed in. This routine operates + to save and set state for the calling routine. +TODO: + This routine does NOT support Asian, Hebrew, or Arabic language + collations. In addition, flmCheckDoubleCollation() is not called + for other non-US lanagues. There is still a lot of work to do! + This is our default US compare and it is not very good for JP. + +Return: Signed value of compare. + <0 if less than, 0 if equal, >0 if greater than. + +Asian Notes: + The asian compare takes two characters and may use one or both. + This makes the algorithm complex so we may have to build full + tests to see what we broke. + +NDS Notes: + The right side (search string) is already formatted according + to the space/dash rules of the syntax. +****************************************************************************/ +FLMINT flmTextCompareSingleChar( + FLMBYTE ** ppLeftText, // [in] Points to current value. + // [out] Points to next character if equals. + FLMUINT * puiLeftLen, // [in] Bytes remaining in text string. + // [out] Bytes remaining in text string. + FLMUINT * puiLeftWpChar2,// Second left character - for double characters + FLMBYTE ** ppRightText, // [in] Points to current value. + // [out] Points to next character if equals. + FLMUINT * puiRightLen, // [in] Bytes remaining in text string. + // [out] Bytes remaining in text string. + FLMUINT * puiRightWpChar2,// Second right character - for double characters. + FLMINT * piSubColCompare,//[in] If NULL disregard the subcollation + // values if collation values are equal. + // [out] If equals is returned, value is + // set ONLY if the signed value of comparing + // the sub-collation values is not equal. + // See lengthy unicode compare below. + FLMINT * piCaseCompare, // [in] If NULL disregard the case bits + // if collation values are equal. Japanese + // values are an exception to this rule. + // [out] If equals is returned, value is + // set ONLY if the signed value of comparing + // the case values is not equal. + FLMBOOL * pbHitWildCard, // [in] If NULL then do not look for wild + // cards in the right text string. + // [out] If non-null, a wild card (*,?) will + // be looked for on the RIGHT SIDE ONLY. + // If '?' is found 0 will be returned and + // pointers are advanced. If '*' is found, + // this value will be set to TRUE and the + // right side is advanced. If no wild + // card is found the value will not be set. + FLMINT iCompareType, // COMPARE_COLLATION, COMPARE_COL_AND_SUBCOL, COMPARE_VALUE + FLMUINT16 * pui16ColVal, // Needed for asian collation compare. + FLMUINT uiFlags, // FLM_* flags + FLMUINT uiLangId) // FLAIM/WordPerfect Lanaguge id. +{ + FLMBYTE * pLeftText = *ppLeftText; + FLMBYTE * pRightText = *ppRightText; + FLMINT iCompare = 0; + FLMUINT uiRightFlags = uiFlags; + FLMUINT16 ui16LeftWPChar; + FLMUINT16 ui16LeftUniChar; + FLMUINT16 ui16RightWPChar; + FLMUINT16 ui16RightUniChar; + FLMUINT uiLeftValueLen; + FLMUINT uiRightValueLen; + FLMUINT16 ui16LeftCol; + FLMUINT16 ui16RightCol; + FLMUINT uiLeftWpChar2 = *puiLeftWpChar2; + FLMUINT uiRightWpChar2 = *puiRightWpChar2; + FLMBOOL bLeftTwoIntoOne; + FLMBOOL bRightTwoIntoOne; + + // Get the next character from the TEXT string. NOTE: OEM characters + // will be returned as a UNICODE character. A unicode character here + // is a value that cannot be converted to the WP set (no good collation value).. + + uiLeftValueLen = flmTextGetValue( pLeftText, *puiLeftLen, &uiLeftWpChar2, + uiFlags, &ui16LeftWPChar, &ui16LeftUniChar); + + uiRightValueLen = flmTextGetValue( pRightText, *puiRightLen, &uiRightWpChar2, + uiRightFlags, &ui16RightWPChar, &ui16RightUniChar); + + // At this point, the double character, if any, should have been consumed. + + flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); + + // Check for the following escape characters: "\\" "*" and "\\" "\\" + + if( ui16RightWPChar == ASCII_BACKSLASH) + { + if( pRightText[ uiRightValueLen ] == ASCII_BACKSLASH) + { + uiRightValueLen++; + } + else if( pRightText[ uiRightValueLen ] == ASCII_WILDCARD) + { + ui16RightWPChar = ASCII_WILDCARD; + uiRightValueLen++; + } + } + // Checking for wild cards in the right string? (Always a WP character) + else if( pbHitWildCard) + { + + // The '*' wildcard means to match zero or many characters. + // The sick case of "A*B" compared to "A**B" should be considered. + + if( ui16RightWPChar == ASCII_WILDCARD) + { + // Eat all duplicate wild cards. + + while( pRightText[ uiRightValueLen] == ASCII_WILDCARD) + { + uiRightValueLen++; + } + + // Advance the right value. Keep left value alone. + // Return equals (default). + + *pbHitWildCard = TRUE; + + // Don't advance the left value. + + uiLeftValueLen = 0; + uiLeftWpChar2 = *puiLeftWpChar2; + goto Exit; + } + } + + // First section is to compare just WP values. + + if( ui16LeftWPChar && ui16RightWPChar) + { + FLMUINT16 ui16LeftSubCol; + FLMUINT16 ui16RightSubCol; + + if (iCompareType == COMPARE_VALUE) + { + + // Check the obvious case of equal WP values. + + if( ui16LeftWPChar != ui16RightWPChar) + { + iCompare = -1; + } + goto Exit; + } + + // JP compare code. + + if (uiLangId >= FIRST_DBCS_LANG && uiLangId <= LAST_DBCS_LANG) + { + FLMUINT uiNextLeftLen; + FLMUINT uiNextRightLen; + FLMUINT16 ui16NextLeftWPChar; + FLMUINT16 ui16NextRightWPChar; + FLMUINT16 ui16ColVal = pui16ColVal ? *pui16ColVal : 0; + FLMBYTE ucLeftCaseValue; + FLMBYTE ucRightCaseValue; + + // Should have already consumed double character, if any + + flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); + uiNextLeftLen = flmTextGetValue( pLeftText+uiLeftValueLen, + *puiLeftLen, &uiLeftWpChar2, uiFlags, + &ui16NextLeftWPChar, &ui16LeftUniChar); + uiNextRightLen = flmTextGetValue( pRightText+uiRightValueLen, + *puiRightLen, &uiRightWpChar2, uiFlags, + &ui16NextRightWPChar, &ui16RightUniChar); + + // nextL/R WPChar may be zero. + + if (flmAsiaGetCollation( ui16LeftWPChar, ui16NextLeftWPChar, + ui16ColVal, &ui16LeftCol, &ui16LeftSubCol, + &ucLeftCaseValue, FALSE) == 2) + { + uiLeftValueLen += uiNextLeftLen; + } + + if (flmAsiaGetCollation( ui16RightWPChar, ui16NextRightWPChar, + ui16ColVal, &ui16RightCol, &ui16RightSubCol, + &ucRightCaseValue, FALSE) == 2) + { + uiRightValueLen += uiNextRightLen; + } + + // Compare all of the stuff now. + + if (ui16LeftCol == ui16RightCol) + { + if( (iCompareType == COMPARE_COL_AND_SUBCOL) || + (piSubColCompare && (*piSubColCompare == 0))) + { + if( ui16LeftSubCol != ui16RightSubCol) + { + if( iCompareType == COMPARE_COL_AND_SUBCOL) + { + iCompare = -1; + goto Exit; + } + + // At this point piSubColCompare cannot be NULL. + + *piSubColCompare = (ui16LeftSubCol < ui16RightSubCol) + ? -1 + : 1; + + // Write over the case compare value + + if( piCaseCompare ) + { + *piCaseCompare = *piSubColCompare; + } + } + } + + if (iCompareType != COMPARE_COL_AND_SUBCOL) + { + + // Check case? + + if (piCaseCompare && (*piCaseCompare == 0)) + { + if( ucLeftCaseValue != ucRightCaseValue) + { + *piCaseCompare = ucLeftCaseValue < ucRightCaseValue + ? -1 + : 1; + } + } + } + } + else + { + iCompare = (ui16LeftCol < ui16RightCol) ? -1 : 1; + } + + goto Exit; + } + + flmAssert( !uiLeftWpChar2 && !uiRightWpChar2); + + if (uiLangId != US_LANG) + { + const FLMBYTE * pucTmp; + + pucTmp = pLeftText + uiLeftValueLen; + uiLeftWpChar2 = flmCheckDoubleCollation( &ui16LeftWPChar, + &bLeftTwoIntoOne, &pucTmp, uiLangId); + uiLeftValueLen = (FLMUINT)(pucTmp - pLeftText); + + pucTmp = pRightText + uiRightValueLen; + uiRightWpChar2 = flmCheckDoubleCollation( &ui16RightWPChar, + &bRightTwoIntoOne, &pucTmp, uiLangId); + uiRightValueLen = (FLMUINT)(pucTmp - pRightText); + + // See if we got the same double character + + if (uiLeftWpChar2 == uiRightWpChar2 && + ui16LeftWPChar == ui16RightWPChar) + { + uiLeftWpChar2 = 0; + uiRightWpChar2 = 0; + goto Exit; + } + } + else if (ui16LeftWPChar == ui16RightWPChar) + { + + // Same WP character + + goto Exit; + } + + ui16LeftCol = flmGetCollation( ui16LeftWPChar, uiLangId); + + // Handle two characters collating as one. + + if (uiLeftWpChar2 && bLeftTwoIntoOne) + { + ui16LeftCol++; + } + + ui16RightCol = flmGetCollation( ui16RightWPChar, uiLangId); + + // Handle two characters collating as one. + + if (uiRightWpChar2 && bRightTwoIntoOne) + { + ui16RightCol++; + } + + if( ui16LeftCol == ui16RightCol) + { + // Should we bother to check subcollation? - don't bother with 7-bit + + if( ((iCompareType == COMPARE_COL_AND_SUBCOL) || + (piSubColCompare && (*piSubColCompare == 0))) && + ((ui16LeftWPChar | ui16RightWPChar) & 0xFF00)) + { + ui16LeftSubCol = flmTextGetSubCol( ui16LeftWPChar, + ui16LeftCol, uiLangId); + ui16RightSubCol= flmTextGetSubCol( ui16RightWPChar, + ui16RightCol, uiLangId); + + if (!piCaseCompare) + { + + // If the sub-collation value is the original + // character, it means that the collation could not + // distinguish the characters and sub-collation is being + // used to do it. However, this creates a problem when the + // characters are the same character except for case. In that + // scenario, we incorrectly return a not-equal when we are + // doing a case-insensitive comparison. So, at this point, + // we need to use the sub-collation for the upper-case of the + // character instead of the sub-collation for the character + // itself. + + if (ui16LeftSubCol == ui16LeftWPChar) + { + ui16LeftSubCol = flmTextGetSubCol( + flmCh6Upper( ui16LeftWPChar), + ui16LeftCol, uiLangId); + } + + if (ui16RightSubCol == ui16RightWPChar) + { + ui16RightSubCol= flmTextGetSubCol( + flmCh6Upper( ui16RightWPChar), + ui16RightCol, uiLangId); + } + } + + // YES - go for it... + + if( ui16LeftSubCol != ui16RightSubCol) + { + if( iCompareType == COMPARE_COL_AND_SUBCOL) + { + iCompare = (ui16LeftSubCol < ui16RightSubCol) ? -1 : 1; + goto Exit; + } + + // At this point piSubColCompare cannot be NULL. + + *piSubColCompare = (ui16LeftSubCol < ui16RightSubCol) + ? -1 + : 1; + + // Write over the case compare value + + if( piCaseCompare ) + { + *piCaseCompare = *piSubColCompare; + } + } + } + + if( iCompareType == COMPARE_COL_AND_SUBCOL) + { + goto Exit; + } + + if( piCaseCompare && (*piCaseCompare == 0)) + { + + // flmIsUpper() only returns FALSE (lower) or TRUE (not-lower) + + FLMBOOL bLeftUpper = flmIsUpper( ui16LeftWPChar); + FLMBOOL bRightUpper = flmIsUpper( ui16RightWPChar); + + if (bLeftUpper != bRightUpper) + { + *piCaseCompare = !bLeftUpper ? -1 : 1; + } + } + } + else + { + iCompare = (ui16LeftCol < ui16RightCol) ? -1 : 1; + } + + goto Exit; + + } + + if( ui16LeftUniChar && ui16RightUniChar) + { + // Compare two (non-convertable) UNICODE values. + // Check the obvious case of equal UNICODE values. + + if( ui16LeftUniChar == ui16RightUniChar) + { + goto Exit; + } + + // Compare subcollation or compare value? + + if( iCompareType != COMPARE_COLLATION) + { + iCompare = -1; + goto Exit; + } + + // For non-asian - we store these values in the sub-collcation area. + // We should return the differece in sub-collation values - but this + // may not work for all compares. + // + // For asian compares, most values we have a collation value. + // This is a BIG differece in comparing asian values. + // + // If we want sub-collation compare then set it, otherwise set main + // iCompare value. + + if( piSubColCompare ) + { + if( *piSubColCompare == 0) + { + *piSubColCompare = ui16LeftUniChar < ui16RightUniChar + ? -1 + : 1; + } + } + else + { + // Treat as the collation value - this is different than the index. + + iCompare = ui16LeftUniChar < ui16RightUniChar + ? -1 + : 1; + } + + goto Exit; + } + + // Compare subcollation or compare value? + + if( iCompareType != COMPARE_COLLATION) + { + iCompare = -1; + goto Exit; + } + + // Check for no left character. + + if( !ui16LeftWPChar && !ui16LeftUniChar) + { + // No left character. check if no right character. + + if( ui16RightWPChar || ui16RightUniChar) + { + iCompare = -1; + } + } + + // Check for no right character. + + else if( !ui16RightWPChar && !ui16RightUniChar) + { + iCompare = 1; + } + + // What remains is one WP char and one Unicode char. + // Remember the sub-collation comment above. Some WP char may not + // have a collation value (COLS0) so in US sort these values may be + // equal and have different sub-collation values. YECH!!!! + // + // The unicode value will always have collation value of COLS0 (0xFF) + // and subcollation value of 11110 [unicodeValue] + // The WP value could be anything & if collation value is COLS0 will + // have a subcollation value os 1110 [WPValue] + // + // So, we have to check to see of the WP collation value is COLS0. + // If not iCompare is used. If both represent high collation then + // the WP value will always have a lower sub-collation value. + // + // The (not so obvious) code would be to code up... + // iCompare = ui16LeftWPChar ? -1 : 1; + // if we didn't care about sub-collation (and we may not care). + // + // This is easier to over code than have ?: operators for the two cases. + + else if( ui16LeftWPChar) + { + // Remember - unicode subcol is always COLS0. + + if( flmGetCollation( ui16LeftWPChar, uiLangId) == COLS0) + { + if( piSubColCompare && (*piSubColCompare == 0)) + { + *piSubColCompare = -1; + } + } + else + { + iCompare = -1; + } + } + else + { + // left=unicode, right=WP + // Remember - unicode subcol is always COLS0 for non-asian. + + if( flmGetCollation( ui16RightWPChar, uiLangId) == COLS0) + { + if( piSubColCompare && (*piSubColCompare == 0)) + { + *piSubColCompare = 1; + } + } + else + { + iCompare = 1; + } + } + +Exit: + + if( !iCompare) + { + // Position to the next values if equal + + *puiLeftLen -= uiLeftValueLen; + *ppLeftText = pLeftText + uiLeftValueLen; + *puiLeftWpChar2 = uiLeftWpChar2; + *puiRightLen -= uiRightValueLen; + *ppRightText = pRightText + uiRightValueLen; + *puiRightWpChar2 = uiRightWpChar2; + } + + return( iCompare); +} + +/************************************************************************** +Desc: Get the Flaim collating string and convert back to a text string +Ret: Length of new wpStr +Notes: Allocates the area for the word string buffer if will be over 256. +***************************************************************************/ +FLMUINT FColStrToText( + FLMBYTE * fColStr, // Points to the Flaim collated string + FLMUINT * fcStrLenRV, // Length of the Flaim collated string + FLMBYTE * textStr, // Output string to build - TEXT string + FLMUINT fWPLang, // FLAIM WP language number + FLMBYTE * postBuf, // Lower/upper POST buffer or NULL + FLMUINT * postBytesRV, // Return next position to use in postBuf + FLMBOOL * pbDataTruncated, // Sets to TRUE if data had been truncated + FLMBOOL * pbFirstSubstring) // Sets to TRUE if first substring +{ + #define LOCAL_CHARS 150 + + FLMBYTE wordStr[LOCAL_CHARS * 2 + LOCAL_CHARS / 5]; // Sample + 20% + FLMBYTE * wsPtr = NULL; + FLMBYTE * wsAllocatedWsPtr = NULL; + FLMUINT wsLen; + FLMUINT textLen; + FLMBYTE * textPtr; + + if (*fcStrLenRV > LOCAL_CHARS) // If won't fit allocate 1280 + { + if (RC_BAD( f_alloc( MAX_KEY_SIZ * 2, &wsPtr))) + { + return (0); + } + + wsAllocatedWsPtr = wsPtr; + } + else + { + wsPtr = wordStr; + } + + if ((fWPLang >= FIRST_DBCS_LANG) && (fWPLang <= LAST_DBCS_LANG)) + { + wsLen = AsiaConvertColStr( fColStr, fcStrLenRV, wsPtr, pbDataTruncated, + pbFirstSubstring); + if (postBuf) + { + FLMUINT postBytes = *postBytesRV + 2; // Skip past marker + + // may change wsLen + + postBytes += AsiaParseCase( wsPtr, &wsLen, &postBuf[postBytes]); + *postBytesRV = postBytes; + } + } + else + { + wsLen = FWWSGetColStr( fColStr, fcStrLenRV, wsPtr, fWPLang, + pbDataTruncated, pbFirstSubstring); + + // If a post buffer is sent - turn unflagged chars to lower case + + if (postBuf) + { + FLMUINT postBytes = *postBytesRV; + + // Check if mixed case chars follow and always increment + // postBytes + // + + if (postBuf[postBytes++] == (COLL_MARKER | SC_MIXED)) + { + postBytes += FWWSToMixed( wsPtr, wsLen, &postBuf[postBytes], fWPLang); + } + + *postBytesRV = postBytes; + } + } + + // Copy word string to TEXT string area + + wsLen >>= 1; // Convert # of bytes to # of words + textPtr = textStr; + + while (wsLen--) + { + register FLMBYTE ch; + + register FLMBYTE cSet; + + // Put the character in a local variable for speed + + ch = *wsPtr++; + cSet = *wsPtr++; + + if ((!cSet) && (ch <= 127)) + { + + // Character set zero only needs one byte if the character is <= + // 127. Otherwise, it is handled like all other extended + // characters below. + // + + *textPtr++ = ch; + } + + // If the character set is > 63 it takes three bytes to store, + // otherwise only two bytes are needed. + + else if (cSet < 63) + { + *textPtr++ = (FLMBYTE) (CHAR_SET_CODE | cSet); + *textPtr++ = ch; + } + else if (cSet == 0xFF && ch == 0xFF) + { + *textPtr++ = UNICODE_CODE; + *textPtr++ = *(wsPtr + 1); // Character set + *textPtr++ = *wsPtr; // Character + wsPtr += 2; + wsLen--; // Skip past 4 bytes for UNICODE + } + else + { + *textPtr++ = EXT_CHAR_CODE; + *textPtr++ = cSet; + *textPtr++ = ch; + } + } + + textLen = (textPtr - textStr); // Compute total length + + if (wsAllocatedWsPtr != NULL) + { + f_free( &wsAllocatedWsPtr); + } + + return (textLen); +} + +/**************************************************************************** +Desc: Compare two entire strings. There is some debate how this routine + should compare the sub-collation values when wild cards are used. + THIS DOES NOT ALLOW WILD CARDS. +Return: Signed value of compare. + <0 if less than, 0 if equal, >0 if greater than + The case of returning 1 may be in using wild cards which + only need to return a does not match value. +****************************************************************************/ +FLMINT flmTextCompare( + FLMBYTE * pLeftBuf, + FLMUINT uiLeftLen, + FLMBYTE * pRightBuf, + FLMUINT uiRightLen, + FLMUINT uiFlags, + FLMUINT uiLang) +{ + FLMINT iCompare = 0; + FLMINT iSubColCompare = 0; + FLMINT * pSubColCompare; + FLMINT iCaseCompare = 0; + FLMINT * pCaseCompare; + FLMUINT uiLeadingSpace; + FLMUINT uiTrailingSpace; + FLMUINT16 ui16ColVal = 0; + FLMUINT16 ui16WPChar; + FLMUINT16 ui16UniChar; + FLMUINT uiLeftWpChar2 = 0; + FLMUINT uiRightWpChar2 = 0; + + uiTrailingSpace = uiLeadingSpace = + (uiFlags & FLM_MIN_SPACES) ? FLM_NO_SPACE : 0; + pCaseCompare = (uiFlags & FLM_NOCASE) ? NULL : &iCaseCompare; + pSubColCompare = &iSubColCompare; + + // Handle NULL buffers first. + + if (!pLeftBuf) + { + if (pRightBuf) + { + iCompare = -1; + } + goto Exit; + } + + while ((uiLeftLen || uiLeftWpChar2) && + (uiRightLen || uiRightWpChar2)) + { + if ((iCompare = flmTextCompareSingleChar( + &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, + &pRightBuf, &uiRightLen, &uiRightWpChar2, + pSubColCompare, pCaseCompare, NULL_WILD_CARD_CHECK, + COMPARE_COLLATION, &ui16ColVal, + uiFlags | uiLeadingSpace, uiLang)) != 0) + { + goto Exit; + } + uiLeadingSpace = 0; + } + + // EQUAL - as far as the collation values are concerned and one + // or both of the strings is at the end. + + if (uiLeftLen || uiLeftWpChar2) + { + uiLeftLen -= flmTextGetValue( pLeftBuf, uiLeftLen, &uiLeftWpChar2, + uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); + + if (uiLeftLen || ui16WPChar || ui16UniChar) + { + iCompare = 1; + } + } + else if (uiRightLen || uiRightWpChar2) + { + uiRightLen -= flmTextGetValue( pRightBuf, uiRightLen, &uiRightWpChar2, + uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); + if (uiRightLen || ui16WPChar || ui16UniChar) + { + iCompare = -1; + } + } + if (iCompare == 0) + { + + // All collation bytes equal - return subcollation/case difference. + + iCompare = (iSubColCompare != 0) ? iSubColCompare : iCaseCompare; + } + +Exit: + + return iCompare; +} + +/**************************************************************************** +Desc: Match two entire strings. +Return: FLM_TRUE or FLM_FALSE +Notes: This code calls the collation routine because in the future there + will be equal conditions with different unicode characters. + +DOCUMENTATION DEALING WITH WILD CARDS AND SPACE RULES. + + The space rules are not obvious when dealing with wild cards. + This will outline the rules that are being applied so that we can + do a regression test when this code changes. + + Rule #1: Return same result if leading or trailing wild card is added. + The underscore is also the space character in these examples + and the MIN_SPACES rule is being applied. + + Format: DataString Operator SearchString + + Example: if A == A A_ == A A == A_ A_ == A_ + then A == A* A_ == A* A == A_* A_ == A_* + and A == *A A_ == *A A == *A_ A_ == *A_ + and A == *A* A_ == *A* A == *A_* A_ == *A_* + where 'A' represent a string of any characters. + + Strictly put, the query Field == A_* can be broken down to + Field == A || Field == A_* + where the space after 'A' should not be treated as a trailing space. + + In addition we can apply the space before the string with the same results, + but we are not going to handle the case of *_A correctly. + This is because the query *_A should be expanded to + Field == A || Field == *_A + where the space before 'A' should not be treated as a leading space. + When we need to find "_A" in a search string then we will expand the + query to handle this. + + + Rule #2: The spaces before a trailing truncation are NOT to be treated + as trailing spaces if there are remaining bytes in the data string. + + Example: (A_B == A_*) but (AB != A_*) + + + Rule #3: Space value(s) without anything other value are equal to no values. + Example: (" " == "") + + + Rule #4: Trim leading/trailing spaces before and after wild cards. + SMI does this when formatting. + + _* and *_ same as * so A == _* and A = *_ but A != *_* + + + Additional wildcard cases to test for: + + Wildcard cases to handle. + (ABBBBC == A*BC) Hits the goto Compare_Again case three times. + (ABBBBD != A*B) Stuff still remains in dataString + (ABBBBC != A*BCD) Stuff still remains in searchString + +****************************************************************************/ +FLMUINT flmTextMatch( + FLMBYTE * pLeftBuf, + FLMUINT uiLeftLen, + FLMBYTE * pRightBuf, + FLMUINT uiRightLen, + FLMUINT uiFlags, + FLMBOOL bLeadingWildCard, + FLMBOOL bTrailingWildCard, + FLMUINT uiLang) +{ + FLMINT iCompare = 0; + FLMUINT uiLeadingSpace; + FLMUINT uiTrailingSpace; + FLMBOOL bHitWildCard; + FLMBOOL bHasWildCardPos; + FLMBOOL * pbHitWildCard; + FLMUINT uiValueLen; + FLMUINT16 ui16WPChar; + FLMUINT16 ui16UniChar; + FLMUINT16 ui16Tmp1; + FLMUINT16 ui16Tmp2; + FLMINT iCompareType; + FLMUINT uiLeftWpChar2 = 0; + FLMUINT uiRightWpChar2 = 0; + // LWCP = Last Wild Card Position - used for wild card state + FLMBYTE * pLWCPLeftBuf = NULL; + FLMBYTE * pLWCPRightBuf = NULL; + FLMUINT uiLWCPLeftLen = 0; + FLMUINT uiLWCPRightLen = 0; + FLMUINT uiLWCPLeftWpChar2 = 0; + FLMUINT uiLWCPRightWpChar2 = 0; + + if( uiFlags & FLM_COMPARE_COLLATED_VALUES) + { + iCompareType = COMPARE_COLLATION; + } + else + { + iCompareType = (uiFlags & FLM_NOCASE) + ? COMPARE_COL_AND_SUBCOL : COMPARE_VALUE; + } + + // Handle NULL buffers first - don't test for zero length values yet. + + if (!pLeftBuf) + { + if (pRightBuf) + { + iCompare = -1; + } + goto Exit; + } + + bHitWildCard = bHasWildCardPos = FALSE; + uiLeadingSpace = uiTrailingSpace = + (uiFlags & FLM_MIN_SPACES) ? FLM_NO_SPACE : 0; + pbHitWildCard = (uiFlags & FLM_WILD) ? &bHitWildCard : NULL; + + if (bLeadingWildCard) + { + goto Leading_Wild_Card; + } + + while (!iCompare && + (uiLeftLen || uiLeftWpChar2) && + (uiRightLen || uiRightWpChar2)) + { + iCompare = flmTextCompareSingleChar( + &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, + &pRightBuf, &uiRightLen, &uiRightWpChar2, + NULL_SUB_COL_CHECK, NULL_CASE_CHECK, pbHitWildCard, + iCompareType, NULL, + uiFlags | uiLeadingSpace, uiLang); + + uiLeadingSpace = 0; + if (bHitWildCard) + { + +Leading_Wild_Card: + + bHitWildCard = FALSE; + bHasWildCardPos = FALSE; // Turn off last wildcard. + + // If right side is done, we are done. + + if (!uiRightLen && !uiRightWpChar2) + { + uiLeftLen = 0; + uiLeftWpChar2 = 0; + break; + } + + // Save state on the RIGHT to handle the sick case of search key + // "b*aH" being able to match "baaaaaaaaaH" (Lambda Case) + // LWCP = LastWildCardPosition + + pLWCPRightBuf = pRightBuf; + uiLWCPRightLen = uiRightLen; + uiLWCPRightWpChar2 = uiRightWpChar2; + + // Find first matching character on the left side. + +Compare_Again: + + iCompare = -1; + while (iCompare && (uiLeftLen || uiLeftWpChar2)) + { + iCompare = flmTextCompareSingleChar( + &pLeftBuf, &uiLeftLen, &uiLeftWpChar2, + &pRightBuf, &uiRightLen, &uiRightWpChar2, + NULL_SUB_COL_CHECK, NULL_CASE_CHECK, NULL_WILD_CARD_CHECK, + iCompareType, NULL, + uiFlags | uiLeadingSpace, uiLang); + + uiLeadingSpace = 0; + + // Done with the right side? Return iCompare value. + + if (!uiRightLen && !uiRightWpChar2) + { + break; + } + + // Values different and still have stuff on left? + + if (iCompare && (uiLeftLen || uiLeftWpChar2)) + { + // Advance the left if there is anything left + uiValueLen = flmTextGetValue( pLeftBuf, uiLeftLen, + &uiLeftWpChar2, + uiFlags, &ui16Tmp1, &ui16Tmp2); + pLeftBuf += uiValueLen; + uiLeftLen -= uiValueLen; + } + } + + // Save state on the LEFT + + if (uiLeftLen || uiLeftWpChar2) + { + pLWCPLeftBuf = pLeftBuf; + uiLWCPLeftLen = uiLeftLen; + uiLWCPLeftWpChar2 = uiLeftWpChar2; + bHasWildCardPos = TRUE; + } + + // EQUAL - as far as the collation values are concerned. + } + } + + if (iCompare == 0) + { + // In here because LEFT and/or RIGHT are out of bytes. + // Check for trailing spaces if MIN_SPACES. + + if (uiLeftLen || uiLeftWpChar2) + { + if (!bTrailingWildCard) + { + uiLeftLen -= flmTextGetValue( pLeftBuf, uiLeftLen, + &uiLeftWpChar2, + uiFlags | uiTrailingSpace, &ui16WPChar, + &ui16UniChar); + + if (uiLeftLen || ui16WPChar || ui16UniChar) + { + iCompare = 1; + } + } + } + else if (uiRightLen || uiRightWpChar2) + { + uiRightLen -= flmTextGetValue( pRightBuf, uiRightLen, &uiRightWpChar2, + uiFlags | uiTrailingSpace, &ui16WPChar, &ui16UniChar); + + // Equals if right just had a trailing wild card. (else case) + + if (uiRightLen || !pbHitWildCard || ui16WPChar != '*') + { + if (uiRightLen || ui16WPChar || ui16UniChar) + { + iCompare = -1; + } + } + } + } + + // Handle the embedded wild card case. + + if (iCompare != 0 && bHasWildCardPos) + { + + // Restore wild card state. + + pLeftBuf = pLWCPLeftBuf; + uiLeftLen = uiLWCPLeftLen; + uiLeftWpChar2 = uiLWCPLeftWpChar2; + pRightBuf = pLWCPRightBuf; + uiRightLen = uiLWCPRightLen; + uiRightWpChar2 = uiLWCPRightWpChar2; + bHasWildCardPos = FALSE; + + goto Compare_Again; + } + +Exit: + + return (!iCompare ? FLM_TRUE : FLM_FALSE); +} + +/**************************************************************************** +Desc: Check for double characters that sort as 1 (like ch in Spanish) or + 1 character that should sort as 2 (like � sorts as ae in French). +Return: 0 = nothing changes. Otherwise, *pui16WpChar is the first + character, and the return value contains the 2nd character. + In addition, *pbTwoIntoOne will be TRUE if we should take two + characters and treat as one (i.e, change the collation on the + outside to one more than the collation of the first character). +****************************************************************************/ +FLMUINT16 flmCheckDoubleCollation( + FLMUINT16 * pui16WpChar, + FLMBOOL * pbTwoIntoOne, + const FLMBYTE ** ppucInputStr, + FLMUINT uiLanguage) +{ + FLMUINT16 ui16CurState; + FLMUINT16 ui16WpChar; + FLMUINT16 ui16SecondChar; + FLMUINT16 ui16LastChar = 0; + FLMUINT uiInLen; + FLMBOOL bUpperFlag; + + ui16WpChar = *pui16WpChar; + bUpperFlag = flmIsUpper( ui16WpChar); + + uiInLen = 0; + ui16SecondChar = 0; + + // Primer read + + if ((ui16CurState = getNextCharState( 0, uiLanguage)) == 0) + { + goto Exit; + } + + for (;;) + { + switch (ui16CurState) + { + case INSTSG: + { + *pui16WpChar = ui16SecondChar = (FLMUINT16) f_toascii( 's'); + *pbTwoIntoOne = FALSE; + goto Exit; + } + + case INSTAE: + { + if (bUpperFlag) + { + *pui16WpChar = (FLMUINT16) f_toascii( 'A'); + ui16SecondChar = (FLMUINT16) f_toascii( 'E'); + } + else + { + *pui16WpChar = (FLMUINT16) f_toascii( 'a'); + ui16SecondChar = (FLMUINT16) f_toascii( 'e'); + } + + *pbTwoIntoOne = FALSE; + goto Exit; + } + + case INSTIJ: + { + if (bUpperFlag) + { + *pui16WpChar = (FLMUINT16) f_toascii( 'I'); + ui16SecondChar = (FLMUINT16) f_toascii( 'J'); + } + else + { + *pui16WpChar = (FLMUINT16) f_toascii( 'i'); + ui16SecondChar = (FLMUINT16) f_toascii( 'j'); + } + + *pbTwoIntoOne = FALSE; + goto Exit; + } + + case INSTOE: + { + if (bUpperFlag) + { + *pui16WpChar = (FLMUINT16) f_toascii( 'O'); + ui16SecondChar = (FLMUINT16) f_toascii( 'E'); + } + else + { + *pui16WpChar = (FLMUINT16) f_toascii( 'o'); + ui16SecondChar = (FLMUINT16) f_toascii( 'e'); + } + + *pbTwoIntoOne = FALSE; + goto Exit; + } + + case WITHAA: + { + *pui16WpChar = (FLMUINT16) (bUpperFlag + ? (FLMUINT16) 0x122 + : (FLMUINT16) 0x123); + (*ppucInputStr)++; + break; + } + + case AFTERC: + { + *pui16WpChar = (FLMUINT16) (bUpperFlag + ? (FLMUINT16) f_toascii( 'C') + : (FLMUINT16) f_toascii( 'c')); + ui16SecondChar = ui16LastChar; + *pbTwoIntoOne = TRUE; + (*ppucInputStr)++; + goto Exit; + } + + case AFTERH: + { + *pui16WpChar = (FLMUINT16) (bUpperFlag + ? (FLMUINT16) f_toascii( 'H') + : (FLMUINT16) f_toascii( 'h')); + ui16SecondChar = ui16LastChar; + *pbTwoIntoOne = TRUE; + (*ppucInputStr)++; + goto Exit; + } + + case AFTERL: + { + *pui16WpChar = (FLMUINT16) (bUpperFlag + ? (FLMUINT16) f_toascii( 'L') + : (FLMUINT16) f_toascii( 'l')); + ui16SecondChar = ui16LastChar; + *pbTwoIntoOne = TRUE; + (*ppucInputStr)++; + goto Exit; + } + + default: + { + + // Handles STATE1 through STATE11 also + + break; + } + } + + if ((ui16CurState = getNextCharState( ui16CurState, + flmCh6Lower( ui16WpChar))) == 0) + { + goto Exit; + } + + ui16LastChar = ui16WpChar; + ui16WpChar = (FLMUINT16) * ((*ppucInputStr) + (uiInLen++)); + } + +Exit: + + return (ui16SecondChar); +} + +/**************************************************************************** +Desc: Convert a WPChar from hankaku (single wide) to zenkaku (double wide). +Ret: 0 = no conversion + 1 = converted character to zenkaku + 2 = ui16NextWpChar dakuten or handakuten voicing got combined +****************************************************************************/ +FLMUINT16 HanToZenkaku( + FLMUINT16 ui16WpChar, + FLMUINT16 ui16NextWpChar, + FLMUINT16 * pui16Zenkaku) +{ + FLMUINT16 ui16Zenkaku = 0; + FLMBYTE ucCharSet = ui16WpChar >> 8; + FLMBYTE ucCharVal = ui16WpChar & 0xFF; + FLMUINT uiLoop; + FLMUINT16 ui16CharsUsed = 1; + + switch (ucCharSet) + { + + // Character set 0 - symbols + + case 0: + { + + // Invalid? - all others are used. + + if (ucCharVal < 0x20) + { + ; + } + else if (ucCharVal <= 0x2F) + { + + // Symbols A + + ui16Zenkaku = 0x2400 + From0AToZen[ucCharVal - 0x20]; + } + else if (ucCharVal <= 0x39) + { + + // 0..9 + + ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); + } + else if (ucCharVal <= 0x40) + { + + // Symbols B + + ui16Zenkaku = 0x2400 + From0BToZen[ucCharVal - 0x3A]; + } + else if (ucCharVal <= 0x5A) + { + + // A..Z + + ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); + } + else if (ucCharVal <= 0x60) + { + + // Symbols C + + ui16Zenkaku = 0x2400 + From0CToZen[ucCharVal - 0x5B]; + } + else if (ucCharVal <= 0x7A) + { + + // a..z + + ui16Zenkaku = 0x2500 + (ucCharVal - 0x21); + } + else if (ucCharVal <= 0x7E) + { + + // Symbols D + + ui16Zenkaku = 0x2400 + From0DToZen[ucCharVal - 0x7B]; + } + break; + } + + // GREEK + + case 8: + { + if ((ucCharVal >= sizeof(From8ToZen)) || + ((ui16Zenkaku = 0x2600 + From8ToZen[ucCharVal]) == 0x26FF)) + { + ui16Zenkaku = 0; + } + break; + } + + // CYRILLIC + + case 10: + { + + // Check range + + ui16Zenkaku = 0x2700 + (ucCharVal >> 1); // Uppercase value + + // Convert to lower case? + + if (ucCharVal & 0x01) + { + ui16Zenkaku += 0x30; + } + break; + } + + // JAPANESE + + case 11: + { + if (ucCharVal < 5) + { + ui16Zenkaku = 0x2400 + From11AToZen[ucCharVal]; + } + else if (ucCharVal < 0x3D) // katakana? + { + if ((ui16Zenkaku = 0x2600 + From11BToZen[ucCharVal - 5]) == 0x26FF) + { + + // Dash - convert to this + + ui16Zenkaku = 0x241b; + } + else + { + if (ui16NextWpChar == 0xB3D) // dakuten? - voicing + { + + // First check exception(s) then check if voicing + // exists! + + if ((ui16Zenkaku != 0x2652) && // is not 'N'? + (flmKanaSubColTbl[ui16Zenkaku - 0x2600 + 1] == 3)) + { + ui16Zenkaku++; + + // Return 2 + + ui16CharsUsed++; + } + } + else if (ui16NextWpChar == 0xB3E) // handakuten? - voicing + { + + // Check if voicing exists! - will NOT access out of + // table + + if (flmKanaSubColTbl[ui16Zenkaku - 0x2600 + 2] == 5) + { + ui16Zenkaku += 2; + + // Return 2 + + ui16CharsUsed++; + } + } + } + } + else if (ucCharVal == 0x3D) // dakuten? + { + + // Convert to voicing symbol + + ui16Zenkaku = 0x240A; + } + else if (ucCharVal == 0x3E) // handakuten? + { + + // Convert to voicing symbol + + ui16Zenkaku = 0x240B; + } + + // else cannot convert + + break; + } + + // Other character sets CS 1,4,5,6 - symbols + + default: + { + + // Instead of includes more tables from char.asm - look down the + // Zen24Tohankaku[] table for a matching value - not much slower. + + for (uiLoop = 0; + uiLoop < (sizeof(Zen24ToHankaku) / sizeof(BYTE_WORD_TBL)); + uiLoop++) + { + if (Zen24ToHankaku[uiLoop].WordValue == ui16WpChar) + { + ui16Zenkaku = 0x2400 + Zen24ToHankaku[uiLoop].ByteValue; + break; + } + } + break; + } + } + + if (!ui16Zenkaku) + { + + // Change return value + + ui16CharsUsed = 0; + } + + *pui16Zenkaku = ui16Zenkaku; + return (ui16CharsUsed); +} + +/**************************************************************************** +Desc: Convert a zenkaku (double wide) char to a hankaku (single wide) char +Ret: Hankaku char or 0 if a conversion doesn't exist +****************************************************************************/ +FLMUINT16 ZenToHankaku( + FLMUINT16 ui16WpChar, + FLMUINT16 * DakutenOrHandakutenRV) +{ + FLMUINT16 ui16Hankaku = 0; + FLMBYTE ucCharSet = ui16WpChar >> 8; + FLMBYTE ucCharVal = ui16WpChar & 0xFF; + FLMUINT uiLoop; + + switch (ucCharSet) + { + + // SYMBOLS + + case 0x24: + { + for (uiLoop = 0; + uiLoop < (sizeof(Zen24ToHankaku) / sizeof(BYTE_WORD_TBL)); + uiLoop++) + { + + // List is sorted so table entry is more you are done + + if (Zen24ToHankaku[uiLoop].ByteValue >= ucCharVal) + { + if (Zen24ToHankaku[uiLoop].ByteValue == ucCharVal) + { + ui16Hankaku = Zen24ToHankaku[uiLoop].WordValue; + } + break; + } + } + break; + } + + // ROMAN - 0x250F..2559 Hiragana - 0x255E..2580 + + case 0x25: + { + if (ucCharVal >= 0x0F && ucCharVal < 0x5E) + { + ui16Hankaku = ucCharVal + 0x21; + } + break; + } + + // Katakana - 0x2600..2655 Greek - 0x265B..2695 + + case 0x26: + { + if (ucCharVal <= 0x55) // Katakana range + { + FLMBYTE ucCS11CharVal; + FLMUINT16 ui16NextWpChar = 0; + + if ((ucCS11CharVal = MapCS26ToCharSet11[ucCharVal]) != 0xFF) + { + if (ucCS11CharVal & 0x80) + { + if (ucCS11CharVal & 0x40) + { + + // Handakuten voicing + + ui16NextWpChar = 0xB3E; + } + else + { + + // Dakuten voicing + + ui16NextWpChar = 0xB3D; + } + + ucCS11CharVal &= 0x3F; + } + + ui16Hankaku = 0x0b00 + ucCS11CharVal; + if (ui16NextWpChar && DakutenOrHandakutenRV) + { + *DakutenOrHandakutenRV = ui16NextWpChar; + } + } + } + else if (ucCharVal <= 0x95) // Greek + { + FLMBYTE ucGreekChar = ucCharVal; + + // Make a zero based number. + + ucGreekChar -= 0x5E; + + // Check for lowercase + + if (ucGreekChar >= 0x20) + { + + // Convert to upper case for now + + ucGreekChar -= 0x20; + } + + if (ucGreekChar >= 2) + { + ucGreekChar++; + } + + if (ucGreekChar >= 19) + { + ucGreekChar++; + } + + // Convert to character set 8 + + ui16Hankaku = (ucGreekChar << 1) + 0x800; + if (ucCharVal >= (0x5E + 0x20)) + { + + // Adjust to lower case character + + ui16Hankaku++; + } + } + break; + } + + // Cyrillic + + case 0x27: + { + + // Uppercase? + + if (ucCharVal <= 0x20) + { + ui16Hankaku = (ucCharVal << 1) + 0xa00; + } + else if (ucCharVal >= 0x30 && ucCharVal <= 0x50) + { + + // Lower case + + ui16Hankaku = ((ucCharVal - 0x30) << 1) + 0xa01; + } + break; + } + } + + return (ui16Hankaku); +} diff --git a/flaim/src/kycompnd.cpp b/flaim/src/kycompnd.cpp deleted file mode 100644 index 994013b..0000000 --- a/flaim/src/kycompnd.cpp +++ /dev/null @@ -1,824 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Compound key building routines. -// Tabs: 3 -// -// Copyright (c) 1990-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kycompnd.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -FSTATIC RCODE KYCmpKeyElmBld( - FDB * pDb, - IXD_p pIxd, - FLMUINT uiContainerNum, - IFD_p pIfd, - FLMUINT uiAction, - FLMUINT uiDrn, - FLMBOOL * pbHadUniqueKeys, - FLMUINT uiCdlEntry, - FLMUINT uiCompoundPos, - FLMBYTE * pKeyBuf, - FLMUINT uiKeyLen, - FLMBYTE * pLowUpBuf, - FLMUINT uiLuLen, - FlmRecord * pRecord, - FLD_CONTEXT * pFldContext); - -/**************************************************************************** -Desc: Add an field into the CDL (Compound Data List) for this ISK. -****************************************************************************/ -RCODE KYCmpKeyAdd2Lst( - FDB * pDb, - IXD_p pIxd, /* Index definition. */ - IFD_p pIfd, /* Index field definition. */ - void * pvField, /* Field whose value is part of the key. */ - void * pRootContext) /* Points to root context of field path. */ -{ - CDL_p pCdl; - KREF_CNTRL_p pKrefCntrl; - CDL_p * ppCdlTbl; - RCODE rc = FERR_OK; - FLMUINT uiCdlEntry; - FLMUINT uiIxEntry; - - /* OCT98, Need to handle case of zero length data coming in. */ - pKrefCntrl = &pDb->KrefCntrl; - ppCdlTbl = pKrefCntrl->ppCdlTbl; - flmAssert( (ppCdlTbl != NULL) ); - - /* Figure out which CDL and index entry to use. */ - - uiIxEntry = (FLMUINT) (pIxd - pDb->pDict->pIxdTbl); - uiCdlEntry = (FLMUINT) (pIfd - pDb->pDict->pIfdTbl); - - /* - 2/25/99 - Removed code to not add the field if a duplicate - value is found. This dropped index keys with multiple contexts. - */ - - if( (pCdl = (CDL_p)GedPoolAlloc( &pDb->TempPool, - sizeof( CDL))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - flmAssert( (pKrefCntrl->pIxHasCmpKeys != NULL) ); - - pKrefCntrl->pIxHasCmpKeys [uiIxEntry] = TRUE; - pCdl->pField = pvField; - pCdl->pRootContext = pRootContext; - - /* Insert at first of CDL list */ - - pCdl->pNext = ppCdlTbl [uiCdlEntry]; - ppCdlTbl [uiCdlEntry] = pCdl; - pKrefCntrl->bHaveCompoundKey = TRUE; - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Called when an entire record has been processed by the key - building functions. Builds and add all compound keys to the table. -****************************************************************************/ -RCODE KYBuildCmpKeys( - FDB * pDb, - FLMUINT uiAction, - FLMUINT uiContainerNum, - FLMUINT uiDrn, - FLMBOOL * pbHadUniqueKeys, - FlmRecord * pRecord) -{ - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; - CDL_p * ppCdlTbl = pKrefCntrl->ppCdlTbl; - FLMBYTE * pKeyBuf = pKrefCntrl->pKrefKeyBuf; - FLMBYTE * pIxHasCmpKeys = pKrefCntrl->pIxHasCmpKeys; - IXD_p pIxd; - IFD_p pIfd; - IFD_p pFirstIfd; - FLMUINT uiFirstCdlEntry; - FLMUINT uiCdlEntry; - RCODE rc = FERR_OK; - FLMBOOL bBuildCmpKeys; - FLMUINT uiIxEntry; - FLMUINT uiTotalIndexes; - FLMUINT uiIfdCnt; - FLMUINT uiKeyLen; - FLMBYTE LowUpBuf [MAX_LOWUP_BUF]; - FLD_CONTEXT fldContext; - FDICT * pDict = pDb->pDict; - - LowUpBuf[0] = '\0'; - - if( pKrefCntrl->bHaveCompoundKey == FALSE) - goto Exit; - pKrefCntrl->bHaveCompoundKey = FALSE; - flmAssert( (pKeyBuf != NULL) && (pIxHasCmpKeys != NULL )); - - // Loop through all of the indexes looking for a CDL entry. - // VISIT: We need to find the indexes faster than looping! - - uiTotalIndexes = pDict->uiIxdCnt; - for (uiIxEntry = 0; uiIxEntry < uiTotalIndexes; uiIxEntry++) - { - // See if the index has compound keys to build. - - if( !pIxHasCmpKeys [uiIxEntry]) - { - continue; - } - pIxd = pDict->pIxdTbl + uiIxEntry; - pIxHasCmpKeys [uiIxEntry] = FALSE; // Clear the flag. - bBuildCmpKeys = TRUE; - - // Make sure that all required fields are present. - - pFirstIfd = pIfd = pIxd->pFirstIfd; - uiCdlEntry = uiFirstCdlEntry = (FLMUINT) (pFirstIfd - pDict->pIfdTbl); - for (uiIfdCnt = 0; - uiIfdCnt < pIxd->uiNumFlds; - pIfd++, uiCdlEntry++, uiIfdCnt++) - { - FLMUINT uiCompoundPos; - FLMBOOL bHitFound; - - // Loop on each compound field piece looking for REQUIRED field - // without any data - then we don't have to build a key. - - bHitFound = (pIfd->uiFlags & IFD_REQUIRED_PIECE) ? FALSE : TRUE; - uiCompoundPos = pIfd->uiCompoundPos; - for(;;) - { - if( !bHitFound) - { - if( ppCdlTbl [uiCdlEntry]) - { - bHitFound = TRUE; // Loop through all ixds - } - } - if( (pIfd->uiFlags & IFD_LAST) - || ((pIfd+1)->uiCompoundPos != uiCompoundPos)) - break; - pIfd++; - uiCdlEntry++; - uiIfdCnt++; - } - if( !bHitFound) - { - bBuildCmpKeys = FALSE; - break; - } - } - - // Build the individual compound keys. - - if( bBuildCmpKeys) - { - uiKeyLen = 0; - f_memset( &fldContext, 0, sizeof(FLD_CONTEXT)); - - if( RC_BAD(rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, - pFirstIfd, - uiAction, uiDrn, pbHadUniqueKeys, - uiFirstCdlEntry, 0, pKeyBuf, - uiKeyLen, LowUpBuf, 0, - pRecord, &fldContext))) - { - goto Exit; - } - } - - /* Reset the CDL pointers to NULL. */ - /* VISIT: It would be faster to - memset the whole thing in a single call. */ - - f_memset( (void *) (&ppCdlTbl [ uiFirstCdlEntry ]), - 0, sizeof(CDL_p) * pIxd->uiNumFlds); - } - -Exit: - return( rc); -} - -/**************************************************************************** -Desc: Build all compound keys for a record. -Notes: This routine is recursive in nature. Will recurse the number of - levels you have defined in the compound field. Please note that luLen - and uiKeyLen are never modified. This is so the while loop does not have - to reset them for every repeating field in the cdl link. -****************************************************************************/ -FSTATIC RCODE KYCmpKeyElmBld( - FDB * pDb, - IXD_p pIxd, // Index definition. - FLMUINT uiContainerNum, - IFD_p pIfd, // Index field definition. - FLMUINT uiAction, - FLMUINT uiDrn, - FLMBOOL * pbHadUniqueKeys, - FLMUINT uiCdlEntry, // CDL entry for the IFD. - FLMUINT uiCompoundPos, // Compound Piece number - zero based - FLMBYTE * pKeyBuf, // Key buffer to build the key in - FLMUINT uiKeyLen, // Total length left in the key buffer - FLMBYTE * pLowUpBuf, // For POST compound keys place bits here. - FLMUINT uiLuLen, // Length used in pLowUpBuf. - FlmRecord * pRecord, // Record being indexed. - FLD_CONTEXT * pFldContext // State to verify all fields are siblings. - ) -{ - RCODE rc = FERR_OK; - CDL_p * pCdlTbl = pDb->KrefCntrl.ppCdlTbl; - CDL_p pCdl = pCdlTbl [uiCdlEntry]; - FLMBYTE * pTmpBuf = NULL; - void * pvMark = NULL; - IFD_p pNextIfdPiece; - void * pvField; - void * pSaveParentAnchor; - FLMUINT uiNextCdlEntry; - FLMBOOL bBuiltKeyPiece; - FLMUINT uiElmLen; - FLMUINT uiPostFlag; - FLMUINT uiPostLen; - FLMUINT uiTempLuLen; - FLMUINT uiPieceLuLen; - FLMUINT uiNextPiecePos; // 0 if this is the last piece. - FLMUINT uiLanguage; - FLMUINT uiMaxKeySize = (pIxd->uiContainerNum) - ? MAX_KEY_SIZ - : MAX_KEY_SIZ - getIxContainerPartLen( pIxd); - FLMBOOL bFldIsEncrypted = FALSE; - - if ((uiLanguage = pIxd->uiLanguage) == 0xFFFF) - { - uiLanguage = pDb->pFile->FileHdr.uiDefaultLanguage; - } - - // Test for compound key being tons of levels. Still need to code for. - flmAssert( uiCompoundPos < MAX_COMPOUND_PIECES); - - /* Set if this piece is part of post. */ - - uiPostFlag = IFD_IS_POST_TEXT( pIfd); - - /* Add the DELIMITER, except on the first key element. */ - - if( uiCompoundPos != 0) - { - IFD_p pPrevIfd = pIfd - 1; // Works because IFD is on first - // if they repeat. - if( (uiLanguage >= FIRST_DBCS_LANG) && - (uiLanguage <= LAST_DBCS_LANG) && - (IFD_GET_FIELD_TYPE( pPrevIfd) == FLM_TEXT_TYPE) && - (!(pPrevIfd->uiFlags & IFD_CONTEXT))) - { - pKeyBuf [uiKeyLen++] = 0; - } - pKeyBuf [uiKeyLen++] = COMPOUND_MARKER; - } - - // Determine the next IFD compound piece. - - for( pNextIfdPiece = (IFD_p)NULL, - uiNextCdlEntry = uiCdlEntry + 1, - uiNextPiecePos = 0 - ; ((pIfd+uiNextPiecePos)->uiFlags & IFD_LAST) == 0 - ; ) - { - if( (pIfd+uiNextPiecePos)->uiCompoundPos != - (pIfd+uiNextPiecePos+1)->uiCompoundPos) - { - pNextIfdPiece = pIfd + uiNextPiecePos + 1; - uiNextCdlEntry = uiCdlEntry + uiNextPiecePos + 1; - break; - } - - if( !pCdl) - { - pIfd++; - pCdl = pCdlTbl [ ++uiCdlEntry]; - uiNextCdlEntry = uiCdlEntry + 1; - } - else - uiNextPiecePos++; - } - - pSaveParentAnchor = pFldContext->pParentAnchor; - bBuiltKeyPiece = FALSE; - - /* Loop on each CDL, but do at least once. */ - - while( pCdl || !bBuiltKeyPiece) - { - // Restore context values for each iteration. - pFldContext->pParentAnchor = pSaveParentAnchor; - - /* - If there is a field to process, verify that its path is - relative to the previous non-null compound pieces. - */ - if( pCdl) - { - pvField = pCdl->pField; - - // Validate the current and previous root contexts. - - if( KYValidatePathRelation( pRecord, pCdl->pRootContext, pvField, - pFldContext, uiCompoundPos) == FERR_FAILURE) - { - // This field didn't pass the test, get the next field. - goto Next_CDL_Field; - } - } - else - { - pvField = NULL; - } - bBuiltKeyPiece = TRUE; - uiPostLen = uiElmLen = 0; - uiTempLuLen = uiLuLen; - - if( pCdl && (pIfd->uiFlags & (IFD_EACHWORD|IFD_SUBSTRING)) - && (pRecord->getDataType( pvField) == FLM_TEXT_TYPE) - && pRecord->getDataLength( pvField) - && ((!pRecord->isEncryptedField( pvField) - || (pRecord->isEncryptedField( pvField) - && pDb->pFile->bInLimitedMode)))) - { - const FLMBYTE * pText = pRecord->getDataPtr( pvField); - FLMUINT uiTextLen = pRecord->getDataLength( pvField); - FLMUINT uiWordLen; - FLMBOOL bReturn; - FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) - ? TRUE : FALSE; - - if( !pTmpBuf) - { - pvMark = GedPoolMark( &pDb->TempPool); - if( (pTmpBuf = (FLMBYTE *)GedPoolAlloc( &pDb->TempPool, - (FLMUINT)MAX_KEY_SIZ + 8)) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Cleanup1; - } - } - - // Loop on each WORD in the value - - for(;;) - { - bReturn = (pIfd->uiFlags & IFD_EACHWORD) - ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, - pIfd->uiLimit, - pTmpBuf, &uiWordLen) - : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, - pIfd->uiFlags, pIfd->uiLimit, - pTmpBuf, &uiWordLen); - if( !bReturn) - { - break; - } - - uiTempLuLen = uiLuLen; - - // Compute number of bytes left - - uiElmLen = uiMaxKeySize - uiKeyLen - uiTempLuLen; - if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, - pTmpBuf, uiWordLen, - pIfd->uiFlags, pIfd->uiLimit, - NULL, &uiPieceLuLen, uiLanguage, TRUE, - bFirstSubstring, FALSE, NULL))) - { - goto Exit; - } - - bFirstSubstring = FALSE; - if( uiPostFlag) - { - uiElmLen -= uiPieceLuLen; - f_memcpy( &pLowUpBuf [uiTempLuLen], - &pKeyBuf[ uiKeyLen + uiElmLen ], uiPieceLuLen); - uiTempLuLen += uiPieceLuLen; - } - - if( !pNextIfdPiece) - { - - // All ISKs have been added so now output the key - - if( uiTempLuLen ) - { - uiPostLen = KYCombPostParts( pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen), - pLowUpBuf, uiTempLuLen, - uiLanguage, - (FLMUINT)(pIfd->uiFlags) ); - } - - if( RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen + uiPostLen), - TRUE, FALSE, FALSE))) - { - goto Cleanup1; - } - } - else if( RC_BAD( rc)) - { - goto Cleanup1; - } - else - { - - // RECURSIVE CALL to the Next ISK provided no overflow - - if( RC_BAD( rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, - pNextIfdPiece, - uiAction, uiDrn, pbHadUniqueKeys, - uiNextCdlEntry, - uiCompoundPos + 1, pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen), pLowUpBuf, - uiTempLuLen, pRecord, pFldContext))) - { - goto Cleanup1; - } - } - - if( (pIfd->uiFlags & IFD_SUBSTRING) && - (uiTextLen == 1 && - !(uiLanguage >= FIRST_DBCS_LANG && - uiLanguage <= LAST_DBCS_LANG))) - { - break; - } - } - -Cleanup1: - - if (RC_BAD( rc)) - { - goto Exit; - } - } - else /* NOT an EACHWORD attribute */ - { - if( pvField) /* May not have any data at any level */ - { - if( pIfd->uiFlags & IFD_CONTEXT) - { - pKeyBuf [uiKeyLen] = KY_CONTEXT_PREFIX; - flmUINT16ToBigEndian( (FLMUINT16)pRecord->getFieldID( pvField), &pKeyBuf [uiKeyLen + 1]); - uiKeyLen += KY_CONTEXT_LEN; - } - else if( pRecord->getDataLength( pvField)) - { - const FLMBYTE * pExportValue = pRecord->getDataPtr( pvField); - FLMUINT uiDataLength = pRecord->getDataLength( pvField); - - if (pRecord->isEncryptedField( pvField) && - pDb->pFile->bInLimitedMode) - { - pExportValue = pRecord->getEncryptionDataPtr( pvField); - uiDataLength = pRecord->getEncryptedDataLength( pvField); - bFldIsEncrypted = TRUE; - } - - /* Compute number of bytes left. */ - - uiElmLen = uiMaxKeySize - uiKeyLen - uiLuLen; - if( RC_BAD( rc = KYCollateValue( &pKeyBuf [uiKeyLen], &uiElmLen, - pExportValue, - uiDataLength, pIfd->uiFlags, - pIfd->uiLimit, NULL, &uiPieceLuLen, - uiLanguage, TRUE, FALSE, FALSE, NULL, NULL, - bFldIsEncrypted))) - { - goto Exit; - } - - if( uiPostFlag ) - { - uiElmLen -= uiPieceLuLen; - f_memcpy( &pLowUpBuf [uiTempLuLen], - &pKeyBuf [uiKeyLen + uiElmLen], uiPieceLuLen); - uiTempLuLen += uiPieceLuLen; - } - } - } - - if( !pNextIfdPiece) - { - - /* All IFDs have been added so now output the key. */ - - if( uiTempLuLen) - { - uiPostLen = KYCombPostParts( pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen), - pLowUpBuf, uiTempLuLen, - uiLanguage, (FLMUINT)(pIfd->uiFlags)); - } - - if( RC_BAD( rc = KYAddToKrefTbl( pDb, pIxd, uiContainerNum, - pIfd, uiAction, uiDrn, pbHadUniqueKeys, - pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen + uiPostLen), - TRUE, FALSE, bFldIsEncrypted))) - { - goto Exit; - } - } - else if( RC_BAD( rc)) - { - goto Exit; - } - else - { - - /* RECURSIVE CALL to the Next ISK provided no overflow. */ - - if( RC_BAD( rc = KYCmpKeyElmBld( pDb, pIxd, uiContainerNum, - pNextIfdPiece, - uiAction, uiDrn, pbHadUniqueKeys, - uiNextCdlEntry, - uiCompoundPos + 1, pKeyBuf, - (FLMUINT)(uiKeyLen + uiElmLen), pLowUpBuf, - uiTempLuLen, pRecord, pFldContext))) - { - goto Exit; - } - } - } -Next_CDL_Field: - - if( pCdl) - { - pCdl = pCdl->pNext; - } - - // If the CDL list is empty, goto the next IFD if same uiCompoundPos. - - while ((!pCdl) - && ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) - { - pIfd++; - pCdl = pCdlTbl [++uiCdlEntry]; - } - - /* - Here is the tough part of the new compound indexing strategy (Aug98). - If all fields failed the validate field path test and this piece of - the compound key is required, then goto exit NOW which will not - build any key with the previous built key pieces. - */ - - if( !pCdl && !bBuiltKeyPiece && ((pIfd->uiFlags & IFD_OPTIONAL) == 0)) - { - goto Exit; - } - } // end while( pCdl || !bBuiltKeyPiece) - -Exit: - - if( pvMark) - { - GedPoolReset( &pDb->TempPool, pvMark); - } - - return( rc); - } - - -/**************************************************************************** -Desc: Validate that the current field is related to the other fields - in the compound key index. The context (left-most) fields of the - field paths must all be siblings of each other in order to - be related. -Notes: If the GEDCOM implementation changes to where finding the level - of a field is expensive, we need to set local level variables. -****************************************************************************/ -RCODE KYValidatePathRelation( - FlmRecord * pRecord, - void * pCurContext, // Current compound piece context. - void * pCurFld, // Current compound field. - FLD_CONTEXT * pFldContext, /* Points to field path state. - ->pParentAnchor is used as the parent - of related siblings. There can only - be one parent anchor per compound - set. All remaining fields must - be a child of this - parent anchor.*/ - FLMUINT uiCompoundPos) // Compound piece position -{ - RCODE rc = FERR_OK; - void * pCurParent; - FLMUINT uiPrevCompoundPos; - FLMBOOL bMatchedContext; - - // If too many compound level, just exit and don't check. - if( uiCompoundPos >= MAX_COMPOUND_PIECES) - { - goto Exit; - } - - pCurParent = pRecord->parent( pCurContext); - - // First time in is the easy case - just set the parent anchor. - // A value of NULL is OK. - - if( uiCompoundPos == 0) - { - pFldContext->pParentAnchor = pCurParent; - goto Exit; - } - - bMatchedContext = FALSE; - // uiCompoundPos used at exit to save state. - uiPrevCompoundPos = uiCompoundPos; - while( uiPrevCompoundPos--) - { - if( pFldContext->rootContexts[ uiPrevCompoundPos] == pCurContext) - { - // Check this field against the current field values. - - rc = KYVerifyMatchingPaths( pRecord, pCurContext, pCurFld, - pFldContext->leafFlds[ uiPrevCompoundPos]); - - // Return failure on any failure. Otherwise continue. - if( rc == FERR_FAILURE) - { - goto Exit; - } - bMatchedContext = TRUE; - } - } - if( bMatchedContext) - { - /* - If we had some base relation match, there is no need to - verify that the parents are the same. - */ - goto Exit; - } - - // Verify that the parent anchor equals the parent of pCurContext. - // GedParent() supports passing a NULL value. - - if( pFldContext->pParentAnchor != pCurParent) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } - -Exit: - // Set the state variables for this compound position. - if( RC_OK(rc)) - { - pFldContext->rootContexts[ uiCompoundPos ] = pCurContext; - pFldContext->leafFlds[ uiCompoundPos] = pCurFld; - } - return( rc); -} - -/**************************************************************************** -Desc: Verify that two paths with a common context match paths. - If the tag of pCurContext has a previous match in the compound - key, the field should also match (more of a relational validation). - This means that for keys (A.B.C.D AND A.B.C.E) the 'A.B.C' fields should - be the same field. ALL previous field pieces must be checked for this. - This could be (but isn't being) done by finding the best match" - and only comparing the current with the best match. - - Hard Example: - Do these fields match - A.B.D.E.F and A.C.D.E.G? - We don't want to keep the field path of the two fields around because - this is more state than we need right now. These match only if the - 'A's are the same field. - - A A - B C - D D - E E - F G -Ret: FERR_OK or FERR_FAILURE -****************************************************************************/ -RCODE KYVerifyMatchingPaths( - FlmRecord * pRecord, - void * pCurContext, // Same value as pMatchFld's context. - void * pCurFld, // Current field - void * pMatchFld) // Some field from a previous piece. -{ - RCODE rc = FERR_OK; - FLMUINT uiCurLevel; - FLMUINT uiMatchLevel; - FLMBOOL bMismatchFound = FALSE; - - // If a field equals a context then don't bother to check. - - if( (pCurContext == pCurFld) || (pCurContext == pMatchFld)) - { - goto Exit; - } - - // Go up the parent line until levels match. - - uiCurLevel = pRecord->getLevel( pCurFld); - uiMatchLevel = pRecord->getLevel( pMatchFld); - flmAssert( pRecord->getLevel( pCurContext) < uiCurLevel); - - while( uiCurLevel != uiMatchLevel) - { - if( uiCurLevel > uiMatchLevel) - { - pCurFld = pRecord->parent( pCurFld); - uiCurLevel--; - } - else - { - pMatchFld = pRecord->parent( pMatchFld); - uiMatchLevel--; - } - } - // Go up until you hit the matching context. - - while( pCurFld != pCurContext) - { - if( pRecord->getFieldID( pCurFld) == pRecord->getFieldID( pMatchFld)) - { - // If the fields are NOT the same we MAY have a mismatch. - if( pCurFld != pMatchFld) - { - bMismatchFound = TRUE; - } - } - else - { - // Tags are different - start over checking - bMismatchFound = FALSE; - } - // Go to the next parent. - pCurFld = pRecord->parent( pCurFld); - pMatchFld = pRecord->parent( pMatchFld); - } - if( bMismatchFound) - { - rc = RC_SET( FERR_FAILURE); - } - -Exit: - return( rc); -} - - -/**************************************************************************** -Desc: Combine the bits from all POST text keys. -****************************************************************************/ -FLMUINT KYCombPostParts( - FLMBYTE * pKeyBuf, - FLMUINT uiKeyLen, - FLMBYTE * pLowUpBuf, - FLMUINT uiLuLen, - FLMUINT uiLanguage, - FLMUINT uiIfdAttr - ) -{ - FLMUINT wReturnLen; - - if( !uiLuLen) - return( 0); /* Don't add any more if no pLowUpBuf[] */ - - wReturnLen = (FLMUINT)(uiLuLen + 2); - if( (uiLanguage >= FIRST_DBCS_LANG) && - (uiLanguage <= LAST_DBCS_LANG) && - ((uiIfdAttr & 0x0F) == FLM_TEXT_TYPE) && - (!(uiIfdAttr & IFD_CONTEXT ))) - { - pKeyBuf [uiKeyLen++] = 0; /* Add two bytes */ - wReturnLen++; - } - pKeyBuf [uiKeyLen++] = END_COMPOUND_MARKER; - - f_memcpy( &pKeyBuf [uiKeyLen], pLowUpBuf, uiLuLen ); /* Move pLowUpBuf[] */ - pKeyBuf [uiKeyLen + uiLuLen] = (FLMBYTE) uiLuLen; /* Last byte is uiLuLen */ - - return( wReturnLen ); -} diff --git a/flaim/src/kyeword.cpp b/flaim/src/kyeword.cpp deleted file mode 100644 index b293e90..0000000 --- a/flaim/src/kyeword.cpp +++ /dev/null @@ -1,224 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Eachword/substring parsing for eachword/substring indexing. -// Tabs: 3 -// -// Copyright (c) 1990-2000,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyeword.cpp 12313 2006-01-19 15:14:44 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -/**************************************************************************** -Desc: Substring-ize the string in a node. Normalize spaces and hyphens if - told to. Example: ABC DEF - ABC DEF - BC DEF - C DEF - DEF -VISIT: This needs a lot of word to decide what to do with Kanji and - word joining charactings. Need to use the routines in fqtextc.cpp - to determine the character type. -****************************************************************************/ -FLMBOOL KYSubstringParse( - const FLMBYTE ** ppText, // [in][out] points to text - FLMUINT * puiTextLen, // [in][out] length of text - FLMUINT uiIfdFlags, // [in] flags - FLMUINT uiLimitParm, // [in] Max characters - FLMBYTE * pKeyBuf, // [out] key buffer to fill - FLMUINT * puiKeyLen) // [out] returns length -{ - const FLMBYTE * pText = *ppText; - FLMUINT uiLen = *puiTextLen; - FLMUINT uiWordLen = 0; - FLMUINT uiLimit = uiLimitParm ? uiLimitParm : IFD_DEFAULT_SUBSTRING_LIMIT; - FLMUINT uiFlags = 0; - FLMUINT uiLeadingSpace = FLM_NO_SPACE; - - FLMBOOL bIgnoreSpaceDefault = (uiIfdFlags & IFD_NO_SPACE) ? TRUE : FALSE; - FLMBOOL bIgnoreSpace = TRUE; - FLMBOOL bIgnoreDash = (uiIfdFlags & IFD_NO_DASH) ? TRUE : FALSE; - FLMBOOL bMinSpaces = (uiIfdFlags & (IFD_MIN_SPACES | IFD_NO_SPACE)) ? TRUE : FALSE; - FLMBOOL bNoUnderscore = (uiIfdFlags & IFD_NO_UNDERSCORE) ? TRUE : FALSE; - FLMBOOL bFirstCharacter = TRUE; - - // Set uiFlags - if( bIgnoreSpaceDefault) - uiFlags |= FLM_NO_SPACE; - if( bIgnoreDash) - uiFlags |= FLM_NO_DASH; - if( bNoUnderscore) - uiFlags |= FLM_NO_UNDERSCORE; - if( uiIfdFlags & IFD_MIN_SPACES) - uiFlags |= FLM_MIN_SPACES; - - /* - The limit must return one more than requested in order - for the text to collation routine to set the truncated flag. - */ - uiLimit++; - - while( uiLen && uiLimit--) - { - FLMBYTE ch = *pText; - FLMUINT16 ui16WPValue; - FLMUNICODE ui16UniValue; - FLMUINT uiCharLen; - - if( (ch & ASCII_CHAR_MASK) == ASCII_CHAR_CODE) - { - if( ch == ASCII_UNDERSCORE && bNoUnderscore) - { - ch = ASCII_SPACE; - } - if( ch == ASCII_SPACE && bMinSpaces) - { - if( !bIgnoreSpace) - { - pKeyBuf[ uiWordLen++ ] = ASCII_SPACE; - } - bIgnoreSpace = TRUE; - pText++; - uiLen--; - continue; - } - ui16WPValue = (FLMUINT16) ch; - uiCharLen = 1; - } - else - { - if( (uiCharLen = flmTextGetValue( pText, uiLen, NULL, - uiFlags | uiLeadingSpace, - &ui16WPValue, &ui16UniValue)) == 0) - break; - flmAssert( uiCharLen <= uiLen); - } - uiLeadingSpace = 0; - bIgnoreSpace = bIgnoreSpaceDefault; - uiLen -= uiCharLen; - while( uiCharLen--) - { - pKeyBuf[ uiWordLen++ ] = *pText++; - } - - // If on the first word position to start on next character - // for the next call. - if( bFirstCharacter) - { - bFirstCharacter = FALSE; - // First character - set return value. - *ppText = pText; - *puiTextLen = uiLen; - } - } - pKeyBuf[ uiWordLen ] = '\0'; - // Case of all spaces - the FALSE will trigger indexing is done. - *puiKeyLen = (FLMUINT)uiWordLen; - return( ( uiWordLen) ? TRUE : FALSE); -} - -/**************************************************************************** -Desc: Keyword-ize the information in a node - node is assumed to be a - TEXT node. -VISIT: This needs a lot of work to decide what to do with Kanji and - word joining charactings. Need to use the routines in fqtextc.cpp - to determine the character type. Also, the code should be redone to - be like the substring code above instead of count the buffer. -****************************************************************************/ -FLMBOOL KYEachWordParse( - const FLMBYTE ** pText, - FLMUINT * puiTextLen, - FLMUINT uiLimitParm, // [in] Max characters - FLMBYTE * pKeyBuf, // [out] Buffer of at least MAX_KEY_SIZ - FLMUINT * puiKeyLen) -{ - const FLMBYTE * pKey = NULL; - const FLMBYTE * pTmpKey; - FLMUINT uiLimit = uiLimitParm ? uiLimitParm : IFD_DEFAULT_SUBSTRING_LIMIT; - FLMUINT uiLen; - FLMUINT uiBytesProcessed = 0; - FLMBOOL bSkippingDelim = TRUE; - FLMBOOL bHaveWord = FALSE; - FLMUINT uiWordLen = 0; - FLMUINT16 ui16WPValue; - FLMUNICODE ui16UniValue; - FLMUINT uiCharLen; - FLMUINT uiType; - - uiLen = *puiTextLen; - pTmpKey = *pText; - while ((uiBytesProcessed < uiLen) && (!bHaveWord) && uiLimit) - { - uiCharLen = flmTextGetCharType( pTmpKey, uiLen, - &ui16WPValue, &ui16UniValue, &uiType); - - /* Determine how to handle what we got. */ - - if (bSkippingDelim) - { - - /* - If we were skipping delimiters, and we run into a non-delimiter - character, set the bSkippingDelim flag to FALSE to indicate the - beginning of a word. - */ - - if (uiType & SDWD_CHR) - { - pKey = pTmpKey; - uiWordLen = uiCharLen; - bSkippingDelim = FALSE; - uiLimit--; - } - } - else - { - - /* - If we were NOT skipping delimiters, and we run into a delimiter - output the word. - */ - - if (uiType & (DELI_CHR | WDJN_CHR)) - bHaveWord = TRUE; - else - { - uiWordLen += uiCharLen; - uiLimit--; - } - } - - /* Increment str to skip past what we are pointing at. */ - - pTmpKey += uiCharLen; - uiBytesProcessed += uiCharLen; - } - - *pText = pTmpKey; - *puiTextLen -= uiBytesProcessed; - - /* Return the word, if any. */ - - if (uiWordLen) - { - *puiKeyLen = uiWordLen; - f_memcpy( pKeyBuf, pKey, uiWordLen); - } - - return( ( uiWordLen) ? TRUE : FALSE); -} diff --git a/flaim/src/kyget.cpp b/flaim/src/kyget.cpp index 3534cb9..6e941ff 100644 --- a/flaim/src/kyget.cpp +++ b/flaim/src/kyget.cpp @@ -1,886 +1,909 @@ -//------------------------------------------------------------------------- -// Desc: Get index keys from a record. -// Tabs: 3 -// -// Copyright (c) 1992-2001,2003-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyget.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -typedef struct CMP_KEY_ELM * CMP_KEY_ELM_p; - -typedef struct CMP_KEY_ELM -{ - const FLMBYTE * pValue; - FLMUINT uiValueLen; - FLMUINT uiType; - FLMUINT uiTagNum; - CMP_KEY_ELM_p pParent; - FLMBOOL bFirstSubstring; - FLMBOOL bSubstringComponent; -} CMP_KEY_ELM; - -FSTATIC RCODE flmKeyAdd( - FDB_p pDb, - IXD_p pIxd, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - POOL * pPool, - FLMBOOL bRemoveDups, - REC_KEY ** ppKeyList); - -FSTATIC RCODE flmGetFieldKeys( - FDB_p pDb, - IXD_p pIxd, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - void ** ppPathFlds, - FLMUINT uiLeafFieldLevel, - void * pvField, - FLMBOOL bRemoveDups, - POOL * pPool, - REC_KEY ** ppKeyList, - FLMBOOL * bHasCmpKeys); - -FSTATIC RCODE flmBuildCompoundKey( - FDB_p pDb, - IXD_p pIxd, - CMP_KEY_ELM_p pCmpKeyElm, - FLMBOOL bRemoveDups, - POOL * pPool, - FLMUINT uiContainerNum, - REC_KEY ** ppKeyList); - -FSTATIC RCODE flmGetCmpKeyElement( - FDB_p pDb, - IXD_p pIxd, - IFD_p pIfd, - FLMUINT uiCdlEntry, - FLMUINT uiCompoundPos, - CMP_KEY_ELM_p pParent, - FLMBOOL bRemoveDups, - POOL * pPool, - REC_KEY ** ppKeyList, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - FLD_CONTEXT * pFldContext); - -FSTATIC RCODE flmGetCompoundKeys( - FDB_p pDb, - IXD_p pIxd, - FLMBOOL bRemoveDups, - POOL * pPool, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - REC_KEY ** ppKeyList); - - -/*************************************************************************** -Desc: This routine adds a key to a key list. -*****************************************************************************/ -FSTATIC RCODE flmKeyAdd( - FDB_p pDb, - IXD_p pIxd, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - POOL * pPool, - FLMBOOL bRemoveDups, - REC_KEY ** ppKeyList) -{ - RCODE rc = FERR_OK; - REC_KEY * pTempRecKey; - FLMBYTE Key1Buf [MAX_KEY_SIZ]; - FLMUINT uiKey1Len; - FLMBYTE Key2Buf [MAX_KEY_SIZ]; - FLMUINT uiKey2Len; - - /* First see if the key is already in the list. */ - - pTempRecKey = *ppKeyList; - if( pTempRecKey && bRemoveDups) - { - if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, pRecord, uiContainerNum, - Key1Buf, &uiKey1Len, 0))) - goto Exit; - - while (pTempRecKey != NULL) - { - - /* Build the collated keys for each key tree in *ppKeyList */ - - if( RC_BAD( rc = KYTreeToKey( pDb, pIxd, pTempRecKey->pKey, - uiContainerNum, - Key2Buf, &uiKey2Len, 0))) - goto Exit; - - /* - If the key was found, return success - don't add to list. - Also, free up the memory pool back to where the key - started. - */ - - if (KYKeyCompare( Key1Buf, uiKey1Len, Key2Buf, uiKey2Len) == BT_EQ_KEY) - { - // Should return FERR_OK. - goto Exit; - } - pTempRecKey = pTempRecKey->pNextKey; - } - } - - if ((pTempRecKey = (REC_KEY *)GedPoolAlloc( pPool, - sizeof(REC_KEY))) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pTempRecKey->pKey = pRecord; - pRecord->AddRef(); - pTempRecKey->pNextKey = *ppKeyList; - *ppKeyList = pTempRecKey; -Exit: - return( rc); -} - -/*************************************************************************** -Desc: This routine gets all of the keys for a field and either saves them - as an element for a compound key, or saves them into the key list. -*****************************************************************************/ -FSTATIC RCODE flmGetFieldKeys( - FDB_p pDb, - IXD_p pIxd, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - void ** ppPathFlds, - FLMUINT uiLeafFieldLevel, - void * pvField, - FLMBOOL bRemoveDups, - POOL * pPool, - REC_KEY ** ppKeyList, - FLMBOOL * pbHasCmpKeys) -{ - RCODE rc = FERR_OK; - IFD_p pIfd; - FlmRecord * pFieldRecord = NULL; - void * pvRootContext; - void * pvValueField; - const FLMBYTE * pExportPtr = NULL; - FLMBYTE * pImportDataPtr; - FLMUINT uiCounter; - FLMUINT uiTagNum; - FLMUINT uiExportLen; - FLMUINT uiFieldType; - FLMUINT * puiFieldPath; - FLMUINT uiLevel; - FLMUINT uiLanguage = pIxd->uiLanguage; - FLMBYTE * pbyTmpBuf = NULL; - - uiTagNum = pRecord->getFieldID( pvField); - - // See if the field is defined in this index. - - pIfd = pIxd->pFirstIfd; - for (uiCounter = 0; uiCounter < pIxd->uiNumFlds; uiCounter++, pIfd++ ) - { - if (pIfd->uiFldNum == uiTagNum) - { - if (flmCheckIfdPath( pIfd, pRecord, ppPathFlds, uiLeafFieldLevel, - pvField, &pvRootContext)) - { - break; // Found one that matches. - } - } - } - - /* If the field is not part of the index, return. */ - - if( uiCounter == pIxd->uiNumFlds) - goto Exit; /* Should return FERR_OK. */ - - /* At this point, we know the field is part of the index. */ - - pExportPtr = pRecord->getDataPtr( pvField); - uiExportLen = pRecord->getDataLength( pvField); - uiFieldType = pRecord->getDataType( pvField); - - /* - VISIT: - Scott thinks we should treat all keys like a compound key and get rid of the - flmKeyAdd() call above. - */ - - if (pIfd->uiFlags & IFD_COMPOUND) - { - rc = KYCmpKeyAdd2Lst( pDb, pIxd, pIfd, pvField, pvRootContext); - *pbHasCmpKeys = TRUE; - } - else - { - if( (pFieldRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pFieldRecord->setContainerID( uiContainerNum); - - // Build a record with just this field in it. - puiFieldPath = pIfd->pFieldPathPToC; - for( uiLevel = 0; *puiFieldPath; puiFieldPath++) - { - if( RC_BAD( rc = pFieldRecord->insertLast( uiLevel++, - *puiFieldPath, FLM_CONTEXT_TYPE, &pvValueField))) - { - goto Exit; - } - } - - if (pIfd->uiFlags & IFD_CONTEXT) - { - /* Create the field and put it into the key list. */ - - rc = flmKeyAdd( pDb, pIxd, pFieldRecord, uiContainerNum, - pPool, bRemoveDups, ppKeyList); - } - else if ((pIfd->uiFlags & (IFD_EACHWORD|IFD_SUBSTRING)) && - (uiFieldType == FLM_TEXT_TYPE)) - { - const FLMBYTE * pText = pExportPtr; - FLMUINT uiTextLen = uiExportLen; - FLMUINT uiKeyLen; - FLMBOOL bReturn; - FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) - ? TRUE : FALSE; - - if (!pbyTmpBuf) - { - if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf))) - { - goto Exit; - } - } - - /* Get each word out of the key and save as a separate key. */ - - for( pText = pExportPtr;;) - { - bReturn = (pIfd->uiFlags & IFD_EACHWORD) - ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, - pIfd->uiLimit, - pbyTmpBuf, &uiKeyLen) - : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, - pIfd->uiFlags, pIfd->uiLimit, - pbyTmpBuf, &uiKeyLen); - if( !bReturn) - break; - - if (!pFieldRecord) - { - if( (pFieldRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pFieldRecord->setContainerID( uiContainerNum); - puiFieldPath = pIfd->pFieldPathPToC; - - for( uiLevel = 0; *puiFieldPath; puiFieldPath++) - { - if (RC_BAD( rc = pFieldRecord->insertLast( uiLevel++, - *puiFieldPath, FLM_CONTEXT_TYPE, &pvValueField))) - { - goto Exit; - } - } - } - - if( RC_BAD( rc = pFieldRecord->allocStorageSpace( pvValueField, - FLM_TEXT_TYPE, - uiKeyLen, - 0, 0, 0, - &pImportDataPtr, - NULL))) - { - goto Exit; - } - f_memcpy( pImportDataPtr, pbyTmpBuf, uiKeyLen); - - if( (pIfd->uiFlags & IFD_SUBSTRING) && !bFirstSubstring) - { - pFieldRecord->setLeftTruncated( pvValueField, TRUE); - } - if( RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord, - uiContainerNum, pPool, bRemoveDups, ppKeyList))) - { - goto Exit; - } - pFieldRecord->Release(); - pFieldRecord = NULL; - - if( (pIfd->uiFlags & IFD_SUBSTRING) && - uiTextLen == 1 && - !(uiLanguage >= FIRST_DBCS_LANG && - uiLanguage <= LAST_DBCS_LANG)) - { - break; - } - bFirstSubstring = FALSE; - } - } - else - { - /* Oct98 - Accept zero length fields. */ - /* Copy the field and put it into the key list. */ - - if( RC_BAD( rc = pFieldRecord->allocStorageSpace( - pvValueField, - pRecord->getDataType( pvField), - uiExportLen, - 0, 0, 0, &pImportDataPtr, NULL))) - { - goto Exit; - } - f_memcpy( pImportDataPtr, pExportPtr, uiExportLen); - - if( RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord, - uiContainerNum, pPool, bRemoveDups, ppKeyList))) - { - goto Exit; - } - } - } - -Exit: - - if (pFieldRecord) - { - pFieldRecord->Release(); - } - - if (pbyTmpBuf) - { - f_free( &pbyTmpBuf); - } - return( rc); -} - -/*************************************************************************** -Desc: This routine builds a compound key and saves it into the key list. -*****************************************************************************/ -FSTATIC RCODE flmBuildCompoundKey( - FDB_p pDb, - IXD_p pIxd, - CMP_KEY_ELM_p pCmpKeyElm, - FLMBOOL bRemoveDups, - POOL * pPool, - FLMUINT uiContainerNum, - REC_KEY ** ppKeyList) -{ - RCODE rc = FERR_OK; - FlmRecord * pRecord = NULL; - FLMBYTE * pImportDataPtr; - - // Build fields for each value in the list. - - while (pCmpKeyElm) - { - if (pCmpKeyElm->uiTagNum != 0) - { - void * pvValueField; - FLMUINT uiExportLen = pCmpKeyElm->uiValueLen; - - if (!pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pRecord->setContainerID( uiContainerNum); - } - - // VISIT: Add full path of each key. - if( RC_BAD( rc = pRecord->insertLast( 0, - pCmpKeyElm->uiTagNum, pCmpKeyElm->uiType, &pvValueField))) - goto Exit; - - // VISIT: Don't know what type. - - if( RC_BAD( rc = pRecord->allocStorageSpace( pvValueField, - pCmpKeyElm->uiType, - uiExportLen, - 0, 0, 0, - &pImportDataPtr, - NULL))) - { - goto Exit; - } - - if( uiExportLen) - { - f_memcpy( pImportDataPtr, pCmpKeyElm->pValue, uiExportLen); - } - - if( pCmpKeyElm->bSubstringComponent && - !pCmpKeyElm->bFirstSubstring) - { - pRecord->setLeftTruncated( pvValueField, TRUE); - } - } - pCmpKeyElm = pCmpKeyElm->pParent; - } - - /* Add the key to the key list. */ - - if( pRecord) - { - if (RC_BAD( rc = flmKeyAdd( pDb, pIxd, pRecord, uiContainerNum, - pPool, bRemoveDups, ppKeyList))) - { - goto Exit; - } - } - -Exit: - - if (pRecord) - { - pRecord->Release(); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine gets an element of a compound key and links it to - the previous element in the compound key. -Note: This routine recursively calls itself. - The code is very similar to KYCmpKeyElmBld() in kycompnd.cpp. -*****************************************************************************/ -FSTATIC RCODE flmGetCmpKeyElement( - FDB_p pDb, - IXD_p pIxd, - IFD_p pIfd, - FLMUINT uiCdlEntry, - FLMUINT uiCompoundPos, - CMP_KEY_ELM_p pParent, - FLMBOOL bRemoveDups, - POOL * pPool, - REC_KEY ** ppKeyList, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - FLD_CONTEXT * pFldContext) -{ - RCODE rc = FERR_OK; - CDL_p * ppCdlTbl = pDb->KrefCntrl.ppCdlTbl; - CDL_p pCdl = ppCdlTbl [uiCdlEntry]; - CMP_KEY_ELM CmpKeyElm; - void * pvField; - void * pSaveParentAnchor; - FLMBYTE * pbyTmpBuf = NULL; - IFD_p pNextIfdPiece; - FLMUINT uiNextCdlEntry; - FLMUINT uiNextPiecePos; // 0 if this is the last piece. - FLMUINT uiLanguage = pIxd->uiLanguage; - FLMBOOL bBuiltKeyPiece; - - /* If there are no values, see if we are on the last IFD. */ - - CmpKeyElm.pParent = pParent; - CmpKeyElm.pValue = NULL; - CmpKeyElm.uiType = 0; - CmpKeyElm.uiValueLen = 0; - CmpKeyElm.uiTagNum = 0; - CmpKeyElm.bFirstSubstring = FALSE; - CmpKeyElm.bSubstringComponent = FALSE; - - // New 05/06/96 - // Determine the next IFD compound piece. - - for( pNextIfdPiece = (IFD_p)NULL, - uiNextCdlEntry = uiCdlEntry + 1, - uiNextPiecePos = 0 - ; ((pIfd+uiNextPiecePos)->uiFlags & IFD_LAST) == 0 - ; ) - { - if ((pIfd+uiNextPiecePos)->uiCompoundPos != - (pIfd+uiNextPiecePos+1)->uiCompoundPos) - { - pNextIfdPiece = pIfd + uiNextPiecePos + 1; - uiNextCdlEntry = uiCdlEntry + uiNextPiecePos + 1; - break; - } - if( !pCdl) - { - pIfd++; - pCdl = ppCdlTbl [++uiCdlEntry]; - uiNextCdlEntry = uiCdlEntry + 1; - } - else - uiNextPiecePos++; - } - - pSaveParentAnchor = pFldContext->pParentAnchor; - bBuiltKeyPiece = FALSE; - - /* Loop through all of the values in this IFD. */ - - while (pCdl || !bBuiltKeyPiece) - { - - // Restore context values for each iteration. - pFldContext->pParentAnchor = pSaveParentAnchor; - - /* - If there is a field to process, verify that its path is - relative to the previous non-null compound pieces. - */ - if( pCdl) - { - pvField = pCdl->pField; - - // Validate the current and previous root contexts. - - if( KYValidatePathRelation( pRecord, pCdl->pRootContext, pvField, - pFldContext, uiCompoundPos) == FERR_FAILURE) - { - // This field didn't pass the test, get the next field. - goto Next_CDL_Node; - } - - CmpKeyElm.pValue = pRecord->getDataPtr( pvField); - CmpKeyElm.uiValueLen = pRecord->getDataLength( pvField); - CmpKeyElm.uiType = pRecord->getDataType( pvField); - CmpKeyElm.uiTagNum = pRecord->getFieldID( pvField); - CmpKeyElm.bFirstSubstring = FALSE; - CmpKeyElm.bSubstringComponent = FALSE; - } - else - { - pvField = NULL; - } - if (pRecord && - (pIfd->uiFlags & (IFD_EACHWORD|IFD_SUBSTRING)) && - CmpKeyElm.uiType == FLM_TEXT_TYPE && - pRecord->getDataLength( pvField)) - { - const FLMBYTE * pText = pRecord->getDataPtr( pvField); - FLMUINT uiTextLen = pRecord->getDataLength( pvField); - FLMUINT uiKeyLen; - FLMBOOL bReturn; - FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) - ? TRUE : FALSE; - - if (!pbyTmpBuf) - { - if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf))) - { - goto Exit; - } - } - - for(;;) - { - bReturn = (pIfd->uiFlags & IFD_EACHWORD) - ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, - pIfd->uiLimit, - pbyTmpBuf, &uiKeyLen) - : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, - pIfd->uiFlags, pIfd->uiLimit, - pbyTmpBuf, &uiKeyLen); - if( !bReturn) - break; - - CmpKeyElm.pValue = pbyTmpBuf; - CmpKeyElm.uiValueLen = uiKeyLen; - CmpKeyElm.uiType = FLM_TEXT_TYPE; - CmpKeyElm.bFirstSubstring = bFirstSubstring; - CmpKeyElm.bSubstringComponent = - (pIfd->uiFlags & IFD_SUBSTRING) ? TRUE : FALSE; - if (pIfd->uiFlags & IFD_LAST) - rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm, - bRemoveDups, pPool, uiContainerNum, ppKeyList); - else - rc = flmGetCmpKeyElement( pDb, pIxd, (pIfd + 1), - uiCdlEntry + 1, uiCompoundPos + 1, - &CmpKeyElm, bRemoveDups, pPool, ppKeyList, - pRecord, uiContainerNum, pFldContext); - if (RC_BAD( rc)) - goto Exit; - - if( (pIfd->uiFlags & IFD_SUBSTRING) && - uiTextLen == 1 && - !(uiLanguage >= FIRST_DBCS_LANG && - uiLanguage <= LAST_DBCS_LANG)) - { - break; - } - bFirstSubstring = FALSE; - } - } - else - { - CmpKeyElm.bSubstringComponent = FALSE; - if (pIfd->uiFlags & IFD_CONTEXT) - CmpKeyElm.uiValueLen = 0; - if (pIfd->uiFlags & IFD_LAST) - { - rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm, bRemoveDups, - pPool, uiContainerNum, ppKeyList); - } - else - { - rc = flmGetCmpKeyElement( pDb, pIxd, pNextIfdPiece, - uiNextCdlEntry, uiCompoundPos+1, &CmpKeyElm, - bRemoveDups, pPool, ppKeyList, pRecord, uiContainerNum, - pFldContext); - } - - if (RC_BAD( rc)) - { - goto Exit; - } - } - bBuiltKeyPiece = TRUE; - -Next_CDL_Node: - /* Go to next cdl. */ - if (pCdl) - pCdl = pCdl->pNext; - - // If the CDL list is empty, goto the next IFD if same uiCompoundPos. - - while ((!pCdl) - && ((pIfd->uiFlags & IFD_LAST) == 0) - && (pIfd->uiCompoundPos == (pIfd+1)->uiCompoundPos)) - { - pIfd++; - pCdl = ppCdlTbl [++uiCdlEntry]; - } - /* - Here is the tough part of the new compound indexing strategy (Aug98). - If all nodes failed the validate field path test and this piece of - the compound key is required, then goto exit NOW which will not - build any key with the previous built key pieces. - */ - - if( !pCdl && !bBuiltKeyPiece && ((pIfd->uiFlags & IFD_OPTIONAL) == 0)) - { - goto Exit; - } - } -Exit: - if (pbyTmpBuf) - { - f_free( &pbyTmpBuf); - } - return( rc); -} - -/*************************************************************************** -Desc: This routine builds all of the compound keys whose elements have - been previously saved off of the index's IFD structures. -Note: Already knows that there are compound keys. -*****************************************************************************/ -FSTATIC RCODE flmGetCompoundKeys( - FDB_p pDb, - IXD_p pIxd, - FLMBOOL bRemoveDups, - POOL * pPool, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - REC_KEY ** ppKeyList) -{ - RCODE rc = FERR_OK; - IFD_p pFirstIfd; - IFD_p pIfd; - CDL_p * ppCdlTbl = pDb->KrefCntrl.ppCdlTbl; - FLMUINT uiFirstCdlEntry; - FLMUINT uiCdlEntry; - FLMUINT wIfdCnt; - FLMBOOL bBuildCmpKeys = TRUE; - - pFirstIfd = pIxd->pFirstIfd; - uiFirstCdlEntry = (FLMUINT) (pFirstIfd - pDb->pDict->pIfdTbl); - - // Make sure we have all of the required fields for key generation. - - for (wIfdCnt = 0, pIfd = pFirstIfd, uiCdlEntry = uiFirstCdlEntry; - wIfdCnt < pIxd->uiNumFlds; - pIfd++, wIfdCnt++, uiCdlEntry++) - { - - /* - If field is not optional and no data list found, - there are no compound keys to build. - */ - FLMUINT uiCompoundPos; - FLMBOOL bHitFound; - - // Loop on each compound field piece looking for REQUIRED field - // without any data. - - bHitFound = (pIfd->uiFlags & IFD_OPTIONAL) ? TRUE : FALSE; - uiCompoundPos = pIfd->uiCompoundPos; - for(;;) - { - if (!bHitFound) - { - if (ppCdlTbl [uiCdlEntry]) - { - bHitFound = TRUE; // Loop through all ixds - } - } - if ((pIfd->uiFlags & IFD_LAST) - || ((pIfd+1)->uiCompoundPos != uiCompoundPos)) - break; - pIfd++; - uiCdlEntry++; - wIfdCnt++; - } - if( !bHitFound) - { - bBuildCmpKeys = FALSE; - break; - } - } - - /* Build the individual compound keys. */ - - if (bBuildCmpKeys) - { - FLD_CONTEXT fldContext; - - f_memset( &fldContext, 0, sizeof(FLD_CONTEXT)); - rc = flmGetCmpKeyElement( pDb, pIxd, pFirstIfd, - uiFirstCdlEntry, 0, NULL, bRemoveDups, pPool, ppKeyList, pRecord, - uiContainerNum, &fldContext); - } - - return( rc); -} - -/*************************************************************************** -Desc: This routine builds all of the keys in a record for a particular - index in the database. -*****************************************************************************/ -RCODE flmGetRecKeys( - FDB_p pDb, - IXD_p pIxd, - FlmRecord * pRecord, - FLMUINT uiContainerNum, - FLMBOOL bRemoveDups, - POOL * pPool, - REC_KEY ** ppKeyList) -{ - RCODE rc = FERR_OK; - void * pvField; - FlmRecord * pTmpRec = NULL; - FLMUINT uiFieldCount; - FLMUINT uiSaveFieldID = pRecord->getFieldID( pRecord->root()); - FLMBOOL bResetID = FALSE; - FLMBOOL bHasCmpKeys = FALSE; - FLMBOOL bDictIx = FALSE; - void * pathFlds[ GED_MAXLVLNUM + 1]; - FLMUINT uiLeafFieldLevel; - - *ppKeyList = NULL; - - if( pIxd->uiIndexNum == FLM_DICT_INDEX) - { - bDictIx = TRUE; - - /* - Temporary convert the record's tag number to FLM_NAME_TAG so - that we will generate the appropriate name key. - */ - - if ((uiSaveFieldID >= FLM_DICT_FIELD_NUMS) && - (uiSaveFieldID <= FLM_LAST_DICT_FIELD_NUM)) - { - if( pRecord->isReadOnly()) - { - if( (pTmpRec = pRecord->copy()) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - pRecord = pTmpRec; - } - - pRecord->setFieldID( pRecord->root(), FLM_NAME_TAG); - bResetID = TRUE; - } - } - - /* Process all fields in the tree. */ - - uiFieldCount = 256; - for( pvField = pRecord->root(); pvField; pvField = pRecord->next( pvField)) - { - // Is if field is indexed before building the keys. - - uiLeafFieldLevel = (FLMINT)pRecord->getLevel( pvField); - pathFlds[ uiLeafFieldLevel] = pvField; - if( RC_BAD( rc = flmGetFieldKeys( pDb, pIxd, pRecord, uiContainerNum, - pathFlds, uiLeafFieldLevel, - pvField, bRemoveDups, - pPool, ppKeyList, &bHasCmpKeys))) - { - goto Exit; - } - - /* Release the CPU periodically to prevent CPU hog problems. */ - - if( uiFieldCount-- == 0) - { - f_yieldCPU(); - uiFieldCount = 128; - } - - } - - /* If OK, get the compound keys. */ - - if (bHasCmpKeys) - { - if (RC_BAD( rc = flmGetCompoundKeys( pDb, pIxd, bRemoveDups, - pPool, pRecord, uiContainerNum, ppKeyList))) - { - goto Exit; - } - } - -Exit: - - if( pTmpRec) - { - pTmpRec->Release(); - } - else if( bResetID) - { - pRecord->setFieldID( pRecord->root(), uiSaveFieldID); - } - - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Get index keys from a record. +// Tabs: 3 +// +// Copyright (c) 1992-2001,2003-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: kyget.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +typedef struct CMP_KEY_ELM +{ + const FLMBYTE * pValue; + FLMUINT uiValueLen; + FLMUINT uiType; + FLMUINT uiTagNum; + CMP_KEY_ELM * pParent; + FLMBOOL bFirstSubstring; + FLMBOOL bSubstringComponent; +} CMP_KEY_ELM; + +FSTATIC RCODE flmKeyAdd( + FDB * pDb, + IXD * pIxd, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + POOL * pPool, + FLMBOOL bRemoveDups, + REC_KEY ** ppKeyList); + +FSTATIC RCODE flmGetFieldKeys( + FDB * pDb, + IXD * pIxd, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + void ** ppPathFlds, + FLMUINT uiLeafFieldLevel, + void * pvField, + FLMBOOL bRemoveDups, + POOL * pPool, + REC_KEY ** ppKeyList, + FLMBOOL * bHasCmpKeys); + +FSTATIC RCODE flmBuildCompoundKey( + FDB * pDb, + IXD * pIxd, + CMP_KEY_ELM * pCmpKeyElm, + FLMBOOL bRemoveDups, + POOL * pPool, + FLMUINT uiContainerNum, + REC_KEY ** ppKeyList); + +FSTATIC RCODE flmGetCmpKeyElement( + FDB * pDb, + IXD * pIxd, + IFD * pIfd, + FLMUINT uiCdlEntry, + FLMUINT uiCompoundPos, + CMP_KEY_ELM * pParent, + FLMBOOL bRemoveDups, + POOL * pPool, + REC_KEY ** ppKeyList, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + FLD_CONTEXT * pFldContext); + +FSTATIC RCODE flmGetCompoundKeys( + FDB * pDb, + IXD * pIxd, + FLMBOOL bRemoveDups, + POOL * pPool, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + REC_KEY ** ppKeyList); + +/**************************************************************************** +Desc: This routine adds a key to a key list. +****************************************************************************/ +FSTATIC RCODE flmKeyAdd( + FDB * pDb, + IXD * pIxd, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + POOL * pPool, + FLMBOOL bRemoveDups, + REC_KEY ** ppKeyList) +{ + RCODE rc = FERR_OK; + REC_KEY * pTempRecKey; + FLMBYTE Key1Buf[MAX_KEY_SIZ]; + FLMUINT uiKey1Len; + FLMBYTE Key2Buf[MAX_KEY_SIZ]; + FLMUINT uiKey2Len; + + // First see if the key is already in the list. + + pTempRecKey = *ppKeyList; + if (pTempRecKey && bRemoveDups) + { + if (RC_BAD( rc = KYTreeToKey( pDb, pIxd, pRecord, uiContainerNum, + Key1Buf, &uiKey1Len, 0))) + { + goto Exit; + } + + while (pTempRecKey != NULL) + { + + // Build the collated keys for each key tree in *ppKeyList + + if (RC_BAD( rc = KYTreeToKey( pDb, pIxd, pTempRecKey->pKey, + uiContainerNum, Key2Buf, &uiKey2Len, 0))) + { + goto Exit; + } + + // If the key was found, return success - don't add to list. + // Also, free up the memory pool back to where the key started. + + if (KYKeyCompare( Key1Buf, uiKey1Len, Key2Buf, uiKey2Len) == BT_EQ_KEY) + { + + // Should return FERR_OK. + + goto Exit; + } + + pTempRecKey = pTempRecKey->pNextKey; + } + } + + if ((pTempRecKey = (REC_KEY *) GedPoolAlloc( pPool, + sizeof( REC_KEY))) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pTempRecKey->pKey = pRecord; + pRecord->AddRef(); + pTempRecKey->pNextKey = *ppKeyList; + *ppKeyList = pTempRecKey; +Exit: + + return (rc); +} + +/**************************************************************************** +Desc: This routine gets all of the keys for a field and either saves them + as an element for a compound key, or saves them into the key list. +****************************************************************************/ +FSTATIC RCODE flmGetFieldKeys( + FDB * pDb, + IXD * pIxd, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + void ** ppPathFlds, + FLMUINT uiLeafFieldLevel, + void * pvField, + FLMBOOL bRemoveDups, + POOL * pPool, + REC_KEY ** ppKeyList, + FLMBOOL * pbHasCmpKeys) +{ + RCODE rc = FERR_OK; + IFD * pIfd; + FlmRecord * pFieldRecord = NULL; + void * pvRootContext; + void * pvValueField; + const FLMBYTE * pExportPtr = NULL; + FLMBYTE * pImportDataPtr; + FLMUINT uiCounter; + FLMUINT uiTagNum; + FLMUINT uiExportLen; + FLMUINT uiFieldType; + FLMUINT * puiFieldPath; + FLMUINT uiLevel; + FLMUINT uiLanguage = pIxd->uiLanguage; + FLMBYTE * pbyTmpBuf = NULL; + + uiTagNum = pRecord->getFieldID( pvField); + + // See if the field is defined in this index. + + pIfd = pIxd->pFirstIfd; + for (uiCounter = 0; uiCounter < pIxd->uiNumFlds; uiCounter++, pIfd++) + { + if (pIfd->uiFldNum == uiTagNum) + { + if (flmCheckIfdPath( pIfd, pRecord, ppPathFlds, uiLeafFieldLevel, + pvField, &pvRootContext)) + { + // Found one that matches. + + break; + } + } + } + + // If the field is not part of the index, return. + + if (uiCounter == pIxd->uiNumFlds) + { + goto Exit; + } + + // At this point, we know the field is part of the index. + + pExportPtr = pRecord->getDataPtr( pvField); + uiExportLen = pRecord->getDataLength( pvField); + uiFieldType = pRecord->getDataType( pvField); + + if (pIfd->uiFlags & IFD_COMPOUND) + { + rc = KYCmpKeyAdd2Lst( pDb, pIxd, pIfd, pvField, pvRootContext); + *pbHasCmpKeys = TRUE; + } + else + { + if ((pFieldRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pFieldRecord->setContainerID( uiContainerNum); + + // Build a record with just this field in it. + + puiFieldPath = pIfd->pFieldPathPToC; + for (uiLevel = 0; *puiFieldPath; puiFieldPath++) + { + if (RC_BAD( rc = pFieldRecord->insertLast( uiLevel++, *puiFieldPath, + FLM_CONTEXT_TYPE, &pvValueField))) + { + goto Exit; + } + } + + if (pIfd->uiFlags & IFD_CONTEXT) + { + + // Create the field and put it into the key list. + + rc = flmKeyAdd( pDb, pIxd, pFieldRecord, uiContainerNum, pPool, + bRemoveDups, ppKeyList); + } + else if ((pIfd->uiFlags & (IFD_EACHWORD | IFD_SUBSTRING)) && + (uiFieldType == FLM_TEXT_TYPE)) + { + const FLMBYTE * pText = pExportPtr; + FLMUINT uiTextLen = uiExportLen; + FLMUINT uiKeyLen; + FLMBOOL bReturn; + FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) + ? TRUE + : FALSE; + + if (!pbyTmpBuf) + { + if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf))) + { + goto Exit; + } + } + + // Get each word out of the key and save as a separate key. + + for (pText = pExportPtr;;) + { + bReturn = (pIfd->uiFlags & IFD_EACHWORD) + ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, + pIfd->uiLimit, pbyTmpBuf, &uiKeyLen) + : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, + pIfd->uiFlags, pIfd->uiLimit, pbyTmpBuf, + &uiKeyLen); + if (!bReturn) + { + break; + } + + if (!pFieldRecord) + { + if ((pFieldRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pFieldRecord->setContainerID( uiContainerNum); + puiFieldPath = pIfd->pFieldPathPToC; + + for (uiLevel = 0; *puiFieldPath; puiFieldPath++) + { + if (RC_BAD( rc = pFieldRecord->insertLast( uiLevel++, + *puiFieldPath, FLM_CONTEXT_TYPE, &pvValueField))) + { + goto Exit; + } + } + } + + if (RC_BAD( rc = pFieldRecord->allocStorageSpace( pvValueField, + FLM_TEXT_TYPE, uiKeyLen, 0, 0, 0, &pImportDataPtr, NULL))) + { + goto Exit; + } + + f_memcpy( pImportDataPtr, pbyTmpBuf, uiKeyLen); + + if ((pIfd->uiFlags & IFD_SUBSTRING) && !bFirstSubstring) + { + pFieldRecord->setLeftTruncated( pvValueField, TRUE); + } + + if (RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord, uiContainerNum, + pPool, bRemoveDups, ppKeyList))) + { + goto Exit; + } + + pFieldRecord->Release(); + pFieldRecord = NULL; + + if ((pIfd->uiFlags & IFD_SUBSTRING) && + uiTextLen == 1 && !(uiLanguage >= FIRST_DBCS_LANG && + uiLanguage <= LAST_DBCS_LANG)) + { + break; + } + + bFirstSubstring = FALSE; + } + } + else + { + if (RC_BAD( rc = pFieldRecord->allocStorageSpace( pvValueField, + pRecord->getDataType( pvField), uiExportLen, 0, 0, 0, + &pImportDataPtr, NULL))) + { + goto Exit; + } + + f_memcpy( pImportDataPtr, pExportPtr, uiExportLen); + + if (RC_BAD( rc = flmKeyAdd( pDb, pIxd, pFieldRecord, uiContainerNum, + pPool, bRemoveDups, ppKeyList))) + { + goto Exit; + } + } + } + +Exit: + + if (pFieldRecord) + { + pFieldRecord->Release(); + } + + if (pbyTmpBuf) + { + f_free( &pbyTmpBuf); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine builds a compound key and saves it into the key list. +****************************************************************************/ +FSTATIC RCODE flmBuildCompoundKey( + FDB * pDb, + IXD * pIxd, + CMP_KEY_ELM * pCmpKeyElm, + FLMBOOL bRemoveDups, + POOL * pPool, + FLMUINT uiContainerNum, + REC_KEY ** ppKeyList) +{ + RCODE rc = FERR_OK; + FlmRecord * pRecord = NULL; + FLMBYTE * pImportDataPtr; + + // Build fields for each value in the list. + + while (pCmpKeyElm) + { + if (pCmpKeyElm->uiTagNum != 0) + { + void * pvValueField; + FLMUINT uiExportLen = pCmpKeyElm->uiValueLen; + + if (!pRecord) + { + if ((pRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pRecord->setContainerID( uiContainerNum); + } + + // VISIT: Add full path of each key. + + if (RC_BAD( rc = pRecord->insertLast( 0, pCmpKeyElm->uiTagNum, + pCmpKeyElm->uiType, &pvValueField))) + { + goto Exit; + } + + // VISIT: Don't know what type. + + if (RC_BAD( rc = pRecord->allocStorageSpace( pvValueField, + pCmpKeyElm->uiType, uiExportLen, 0, 0, 0, &pImportDataPtr, + NULL))) + { + goto Exit; + } + + if (uiExportLen) + { + f_memcpy( pImportDataPtr, pCmpKeyElm->pValue, uiExportLen); + } + + if (pCmpKeyElm->bSubstringComponent && !pCmpKeyElm->bFirstSubstring) + { + pRecord->setLeftTruncated( pvValueField, TRUE); + } + } + + pCmpKeyElm = pCmpKeyElm->pParent; + } + + // Add the key to the key list. + + if (pRecord) + { + if (RC_BAD( rc = flmKeyAdd( pDb, pIxd, pRecord, uiContainerNum, pPool, + bRemoveDups, ppKeyList))) + { + goto Exit; + } + } + +Exit: + + if (pRecord) + { + pRecord->Release(); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine gets an element of a compound key and links it to the + previous element in the compound key. +****************************************************************************/ +FSTATIC RCODE flmGetCmpKeyElement( + FDB * pDb, + IXD * pIxd, + IFD * pIfd, + FLMUINT uiCdlEntry, + FLMUINT uiCompoundPos, + CMP_KEY_ELM * pParent, + FLMBOOL bRemoveDups, + POOL * pPool, + REC_KEY ** ppKeyList, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + FLD_CONTEXT * pFldContext) +{ + RCODE rc = FERR_OK; + CDL ** ppCdlTbl = pDb->KrefCntrl.ppCdlTbl; + CDL * pCdl = ppCdlTbl[uiCdlEntry]; + CMP_KEY_ELM CmpKeyElm; + void * pvField; + void * pSaveParentAnchor; + FLMBYTE * pbyTmpBuf = NULL; + IFD * pNextIfdPiece; + FLMUINT uiNextCdlEntry; + FLMUINT uiNextPiecePos; + FLMUINT uiLanguage = pIxd->uiLanguage; + FLMBOOL bBuiltKeyPiece; + + // If there are no values, see if we are on the last IFD. + + CmpKeyElm.pParent = pParent; + CmpKeyElm.pValue = NULL; + CmpKeyElm.uiType = 0; + CmpKeyElm.uiValueLen = 0; + CmpKeyElm.uiTagNum = 0; + CmpKeyElm.bFirstSubstring = FALSE; + CmpKeyElm.bSubstringComponent = FALSE; + + // Determine the next IFD compound piece. + + for (pNextIfdPiece = (IFD*) NULL, uiNextCdlEntry = uiCdlEntry + + 1, uiNextPiecePos = 0; + ((pIfd + uiNextPiecePos)->uiFlags & IFD_LAST) == 0;) + { + if ((pIfd + uiNextPiecePos)->uiCompoundPos != + (pIfd + uiNextPiecePos + 1)->uiCompoundPos) + { + pNextIfdPiece = pIfd + uiNextPiecePos + 1; + uiNextCdlEntry = uiCdlEntry + uiNextPiecePos + 1; + break; + } + + if (!pCdl) + { + pIfd++; + pCdl = ppCdlTbl[++uiCdlEntry]; + uiNextCdlEntry = uiCdlEntry + 1; + } + else + { + uiNextPiecePos++; + } + } + + pSaveParentAnchor = pFldContext->pParentAnchor; + bBuiltKeyPiece = FALSE; + + // Loop through all of the values in this IFD. + + while (pCdl || !bBuiltKeyPiece) + { + + // Restore context values for each iteration. + + pFldContext->pParentAnchor = pSaveParentAnchor; + + // If there is a field to process, verify that its path is relative + // to the previous non-null compound pieces. + + if (pCdl) + { + pvField = pCdl->pField; + + // Validate the current and previous root contexts. + + if (KYValidatePathRelation( pRecord, pCdl->pRootContext, pvField, + pFldContext, uiCompoundPos) == FERR_FAILURE) + { + + // This field didn't pass the test, get the next field. + + goto Next_CDL_Node; + } + + CmpKeyElm.pValue = pRecord->getDataPtr( pvField); + CmpKeyElm.uiValueLen = pRecord->getDataLength( pvField); + CmpKeyElm.uiType = pRecord->getDataType( pvField); + CmpKeyElm.uiTagNum = pRecord->getFieldID( pvField); + CmpKeyElm.bFirstSubstring = FALSE; + CmpKeyElm.bSubstringComponent = FALSE; + } + else + { + pvField = NULL; + } + + if (pRecord && + (pIfd->uiFlags & (IFD_EACHWORD | IFD_SUBSTRING)) && + CmpKeyElm.uiType == FLM_TEXT_TYPE && + pRecord->getDataLength( pvField)) + { + const FLMBYTE * pText = pRecord->getDataPtr( pvField); + FLMUINT uiTextLen = pRecord->getDataLength( pvField); + FLMUINT uiKeyLen; + FLMBOOL bReturn; + FLMBOOL bFirstSubstring = (pIfd->uiFlags & IFD_SUBSTRING) + ? TRUE + : FALSE; + + if (!pbyTmpBuf) + { + if (RC_BAD( rc = f_alloc( MAX_KEY_SIZ, &pbyTmpBuf))) + { + goto Exit; + } + } + + for (;;) + { + bReturn = (pIfd->uiFlags & IFD_EACHWORD) + ? (FLMBOOL) KYEachWordParse( &pText, &uiTextLen, + pIfd->uiLimit, pbyTmpBuf, &uiKeyLen) + : (FLMBOOL) KYSubstringParse( &pText, &uiTextLen, + pIfd->uiFlags, pIfd->uiLimit, pbyTmpBuf, + &uiKeyLen); + if (!bReturn) + { + break; + } + + CmpKeyElm.pValue = pbyTmpBuf; + CmpKeyElm.uiValueLen = uiKeyLen; + CmpKeyElm.uiType = FLM_TEXT_TYPE; + CmpKeyElm.bFirstSubstring = bFirstSubstring; + CmpKeyElm.bSubstringComponent = (pIfd->uiFlags & IFD_SUBSTRING) + ? TRUE + : FALSE; + + if (pIfd->uiFlags & IFD_LAST) + { + rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm, bRemoveDups, + pPool, uiContainerNum, ppKeyList); + } + else + { + rc = flmGetCmpKeyElement( pDb, pIxd, (pIfd + 1), uiCdlEntry + 1, + uiCompoundPos + 1, &CmpKeyElm, + bRemoveDups, pPool, ppKeyList, pRecord, + uiContainerNum, pFldContext); + } + + if (RC_BAD( rc)) + { + goto Exit; + } + + if ((pIfd->uiFlags & IFD_SUBSTRING) && + uiTextLen == 1 && !(uiLanguage >= FIRST_DBCS_LANG && + uiLanguage <= LAST_DBCS_LANG)) + { + break; + } + + bFirstSubstring = FALSE; + } + } + else + { + CmpKeyElm.bSubstringComponent = FALSE; + if (pIfd->uiFlags & IFD_CONTEXT) + { + CmpKeyElm.uiValueLen = 0; + } + + if (pIfd->uiFlags & IFD_LAST) + { + rc = flmBuildCompoundKey( pDb, pIxd, &CmpKeyElm, bRemoveDups, pPool, + uiContainerNum, ppKeyList); + } + else + { + rc = flmGetCmpKeyElement( pDb, pIxd, pNextIfdPiece, uiNextCdlEntry, + uiCompoundPos + 1, &CmpKeyElm, bRemoveDups, + pPool, ppKeyList, pRecord, uiContainerNum, + pFldContext); + } + + if (RC_BAD( rc)) + { + goto Exit; + } + } + + bBuiltKeyPiece = TRUE; + +Next_CDL_Node: + + // Go to next cdl. + + if (pCdl) + { + pCdl = pCdl->pNext; + } + + // If the CDL list is empty, goto the next IFD if same + // uiCompoundPos. + + while( (!pCdl) && ((pIfd->uiFlags & IFD_LAST) == 0) && + (pIfd->uiCompoundPos == (pIfd + 1)->uiCompoundPos)) + { + pIfd++; + pCdl = ppCdlTbl[++uiCdlEntry]; + } + + // If all nodes failed the validate field path test and this piece + // of the compound key is required, then goto exit NOW which will + // not build any key with the previous built key pieces. + + if (!pCdl && !bBuiltKeyPiece && ((pIfd->uiFlags & IFD_OPTIONAL) == 0)) + { + goto Exit; + } + } + +Exit: + + if (pbyTmpBuf) + { + f_free( &pbyTmpBuf); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine builds all of the compound keys whose elements have + been previously saved off of the index's IFD structures. +Note: Already knows that there are compound keys. +****************************************************************************/ +FSTATIC RCODE flmGetCompoundKeys( + FDB * pDb, + IXD * pIxd, + FLMBOOL bRemoveDups, + POOL * pPool, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + REC_KEY ** ppKeyList) +{ + RCODE rc = FERR_OK; + IFD * pFirstIfd; + IFD * pIfd; + CDL ** ppCdlTbl = pDb->KrefCntrl.ppCdlTbl; + FLMUINT uiFirstCdlEntry; + FLMUINT uiCdlEntry; + FLMUINT wIfdCnt; + FLMBOOL bBuildCmpKeys = TRUE; + + pFirstIfd = pIxd->pFirstIfd; + uiFirstCdlEntry = (FLMUINT) (pFirstIfd - pDb->pDict->pIfdTbl); + + // Make sure we have all of the required fields for key generation. + + for (wIfdCnt = 0, pIfd = pFirstIfd, uiCdlEntry = uiFirstCdlEntry; + wIfdCnt < pIxd->uiNumFlds; + pIfd++, wIfdCnt++, uiCdlEntry++) + { + + // If field is not optional and no data list found, there are no + // compound keys to build. + + FLMUINT uiCompoundPos; + FLMBOOL bHitFound; + + // Loop on each compound field piece looking for REQUIRED field + // without any data. + + bHitFound = (pIfd->uiFlags & IFD_OPTIONAL) ? TRUE : FALSE; + uiCompoundPos = pIfd->uiCompoundPos; + + for (;;) + { + if (!bHitFound) + { + if (ppCdlTbl[uiCdlEntry]) + { + bHitFound = TRUE; + } + } + + if ((pIfd->uiFlags & IFD_LAST) || + ((pIfd + 1)->uiCompoundPos != uiCompoundPos)) + { + break; + } + + pIfd++; + uiCdlEntry++; + wIfdCnt++; + } + + if (!bHitFound) + { + bBuildCmpKeys = FALSE; + break; + } + } + + // Build the individual compound keys. + + if (bBuildCmpKeys) + { + FLD_CONTEXT fldContext; + + f_memset( &fldContext, 0, sizeof(FLD_CONTEXT)); + rc = flmGetCmpKeyElement( pDb, pIxd, pFirstIfd, uiFirstCdlEntry, 0, NULL, + bRemoveDups, pPool, ppKeyList, pRecord, + uiContainerNum, &fldContext); + } + + return (rc); +} + +/**************************************************************************** +Desc: This routine builds all of the keys in a record for a particular + index in the database. +****************************************************************************/ +RCODE flmGetRecKeys( + FDB * pDb, + IXD * pIxd, + FlmRecord * pRecord, + FLMUINT uiContainerNum, + FLMBOOL bRemoveDups, + POOL * pPool, + REC_KEY ** ppKeyList) +{ + RCODE rc = FERR_OK; + void * pvField; + FlmRecord * pTmpRec = NULL; + FLMUINT uiFieldCount; + FLMUINT uiSaveFieldID = pRecord->getFieldID( pRecord->root()); + FLMBOOL bResetID = FALSE; + FLMBOOL bHasCmpKeys = FALSE; + FLMBOOL bDictIx = FALSE; + void * pathFlds[GED_MAXLVLNUM + 1]; + FLMUINT uiLeafFieldLevel; + + *ppKeyList = NULL; + + if (pIxd->uiIndexNum == FLM_DICT_INDEX) + { + bDictIx = TRUE; + + // Temporary convert the record's tag number to FLM_NAME_TAG so that + // we will generate the appropriate name key. + + if ((uiSaveFieldID >= FLM_DICT_FIELD_NUMS) && + (uiSaveFieldID <= FLM_LAST_DICT_FIELD_NUM)) + { + if (pRecord->isReadOnly()) + { + if ((pTmpRec = pRecord->copy()) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pRecord = pTmpRec; + } + + pRecord->setFieldID( pRecord->root(), FLM_NAME_TAG); + bResetID = TRUE; + } + } + + // Process all fields in the tree. + + uiFieldCount = 256; + for (pvField = pRecord->root(); pvField; pvField = pRecord->next( pvField)) + { + + // Is if field is indexed before building the keys. + + uiLeafFieldLevel = (FLMINT) pRecord->getLevel( pvField); + pathFlds[uiLeafFieldLevel] = pvField; + if (RC_BAD( rc = flmGetFieldKeys( pDb, pIxd, pRecord, uiContainerNum, + pathFlds, uiLeafFieldLevel, pvField, bRemoveDups, pPool, + ppKeyList, &bHasCmpKeys))) + { + goto Exit; + } + + // Release the CPU periodically to prevent CPU hog problems. + + if (uiFieldCount-- == 0) + { + f_yieldCPU(); + uiFieldCount = 128; + } + } + + // If OK, get the compound keys. + + if (bHasCmpKeys) + { + if (RC_BAD( rc = flmGetCompoundKeys( pDb, pIxd, bRemoveDups, pPool, + pRecord, uiContainerNum, ppKeyList))) + { + goto Exit; + } + } + +Exit: + + if (pTmpRec) + { + pTmpRec->Release(); + } + else if (bResetID) + { + pRecord->setFieldID( pRecord->root(), uiSaveFieldID); + } + + return (rc); +} diff --git a/flaim/src/kyqsort.cpp b/flaim/src/kyqsort.cpp deleted file mode 100644 index 8ba8754..0000000 --- a/flaim/src/kyqsort.cpp +++ /dev/null @@ -1,615 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Key sorting - for indexing. -// Tabs: 3 -// -// Copyright (c) 1990-2000,2002-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyqsort.cpp 12315 2006-01-19 15:16:37 -0700 (Thu, 19 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define KY_SWAP( pKrefTbl, leftP, rightP) \ - pTempKref = pKrefTbl [leftP]; \ - pKrefTbl [leftP] = pKrefTbl [rightP]; \ - pKrefTbl [rightP] = pTempKref - -FSTATIC FLMINT _KrefCompare( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p pKreftA, - KREF_ENTRY_p pKreftB); - -FSTATIC RCODE KYAddUniqueKeys( - FDB * pDb); - -FSTATIC RCODE _KrefQuickSort( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p * pEntryTbl, - FLMUINT uiLowerBounds, - FLMUINT uiUpperBounds); - -FSTATIC RCODE _KrefKillDups( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p * pKrefTbl, - FLMUINT * puiKrefTotalRV); - -/**************************************************************************** -Desc: Checks if the current database has any UNIQUE indexes that need - to checked. Also does duplicate processing for the record. -****************************************************************************/ -RCODE KYProcessDupKeys( - FDB * pDb, - FLMBOOL bHadUniqueKeys - ) -{ - RCODE rc = FERR_OK; - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; - FLMUINT uiCurRecKrefCnt; - - pKrefCntrl->uiTrnsSeqCntr++; - - // Sort and remove duplicates from the list of this record. - - uiCurRecKrefCnt = pKrefCntrl->uiCount - pKrefCntrl->uiLastRecEnd; - - if( uiCurRecKrefCnt > 1) - { - FLMUINT uiSortFlags = KY_DUP_CHK_SRT; - - /* NLM - release cpu. - the QuickSort can take a while */ - - f_yieldCPU(); - - if( RC_BAD( rc = _KrefQuickSort( &uiSortFlags, - &pKrefCntrl->pKrefTbl [pKrefCntrl->uiLastRecEnd], - 0, uiCurRecKrefCnt - 1))) - { - goto Exit; - } - - /* Found any duplicates? */ - - if( uiSortFlags & KY_DUPS_FOUND) - { - if( RC_BAD( rc = _KrefKillDups( &uiSortFlags, - &pKrefCntrl->pKrefTbl [pKrefCntrl->uiLastRecEnd], - &uiCurRecKrefCnt))) - { - goto Exit; - } - pKrefCntrl->uiCount = pKrefCntrl->uiLastRecEnd + uiCurRecKrefCnt; - } - } - - if( bHadUniqueKeys) - { - /* Now check the keys for uniquness in table, and database. */ - - if( RC_BAD(rc = KYAddUniqueKeys( pDb))) - { - goto Exit; - } - } -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Remove anything that was put into the KREF table by the current - record update operation. -****************************************************************************/ -void KYAbortCurrentRecord( - FDB * pDb) -{ - flmAssert( pDb->KrefCntrl.bKrefSetup); - - // Reset the CDL and pIxHasCmpKeys tables - - if (pDb->pDict->uiIfdCnt) - { - f_memset( pDb->KrefCntrl.ppCdlTbl, 0, - pDb->pDict->uiIfdCnt * sizeof( CDL_p)); - } - if (pDb->pDict->uiIxdCnt) - { - f_memset( pDb->KrefCntrl.pIxHasCmpKeys, 0, pDb->pDict->uiIxdCnt); - } - pDb->KrefCntrl.uiCount = pDb->KrefCntrl.uiLastRecEnd; - GedPoolReset( pDb->KrefCntrl.pPool, pDb->KrefCntrl.pReset); -} - -/**************************************************************************** -Desc: Commit (write out) all reference lists from the CURRENT pDb. - Will take care of optimially freeing or resetting memory. -Note: Before 11/96 there was code to not write out references that did - not belong to the specific commited DB transaction. - This isn't saving us any time so just output everything so we don't - have really hard bugs to debug. -****************************************************************************/ -RCODE KYKeysCommit( - FDB * pDb, - FLMBOOL bCommittingTrans) -{ - RCODE rc = FERR_OK; - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; - - // If KrefCntrl has not been initialized, there is no - // work to do. - - if( pKrefCntrl->bKrefSetup) - { - LFILE * pLFile = NULL; - FLMUINT uiTotal = pKrefCntrl->uiLastRecEnd; - KREF_ENTRY_p pKref; - KREF_ENTRY_p * pKrefTbl = pKrefCntrl->pKrefTbl; - FLMUINT uiKrefNum; - FLMUINT uiLastIxNum; - - // We should not have reached this point if bAbortTrans is TRUE - - flmAssert( RC_OK( pDb->AbortRc)); - - // uiTotal and uiLastRecEnd must be the same at this point. - // If not, we have a bug. - - flmAssert( uiTotal == pKrefCntrl->uiLastRecEnd); - - // Sort the KREF table, if it contains more than one record and key. - // This will sort all keys from the same index the same. - - if ((uiTotal > 1) && (pKrefCntrl->uiTrnsSeqCntr > 1)) - { - FLMUINT uiQsortFlags = KY_FINAL_SRT; - - // NLM - release cpu - the quick sort can really pig out the CPU. - - f_yieldCPU(); - - if (RC_BAD( rc = _KrefQuickSort( &uiQsortFlags, pKrefTbl, 0, uiTotal - 1 ))) - goto Exit; - } - - // Initialization of FOR loop - uiLastIxNum = 0; - - // Loop through the KREF table outputting all keys - for( uiKrefNum = 0; uiKrefNum < uiTotal; uiKrefNum++) - { - pKref = pKrefTbl [uiKrefNum]; - - // See if the LFILE changed - - flmAssert( pKref->ui16IxNum > 0 && - pKref->ui16IxNum < FLM_UNREGISTERED_TAGS); // Sanity check - - if( pKref->ui16IxNum != uiLastIxNum) - { - uiLastIxNum = pKref->ui16IxNum; - if( RC_BAD( rc = fdictGetIndex( - pDb->pDict, pDb->pFile->bInLimitedMode, - uiLastIxNum, &pLFile, NULL, TRUE))) - { - goto Exit; - } - } - - // Flush the key to the index - - if( RC_BAD(rc = FSRefUpdate( pDb, pLFile, pKref))) - { - goto Exit; - } - } - - if (bCommittingTrans) - { - KrefCntrlFree( pDb); - } - else - { - // Empty the table out so we can add more keys in this trans. - - GedPoolReset( pKrefCntrl->pPool, NULL); - pKrefCntrl->uiCount = - pKrefCntrl->uiTotalBytes = - pKrefCntrl->uiLastRecEnd = - pKrefCntrl->uiTrnsSeqCntr = 0; - } - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Adds all unique key values. Backs out on any unique error so that - the transaction may continue. -Notes: All duplicates have been removed as well as matching keys. -****************************************************************************/ -FSTATIC RCODE KYAddUniqueKeys( - FDB * pDb) -{ - RCODE rc = FERR_OK; - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; - KREF_ENTRY_p * pKrefTbl = pKrefCntrl->pKrefTbl; - KREF_ENTRY_p pKref; - FLMUINT uiCurKrefNum, uiPrevKrefNum; - FLMUINT uiTargetCount; - FLMUINT uiLastIxNum; - LFILE * pLFile; - FLMBOOL bUniqueErrorHit = FALSE; - - // Unique indexes can't be built in the background - - flmAssert( !(pDb->uiFlags & FDB_BACKGROUND_INDEXING)); - - // Start at the first key for this current record checking for - // all keys that belong to a unique index. We must keep all keys around - // until the last key is added/delete so that we can back out all of the - // changes on a unique error. - - for( uiCurKrefNum = pKrefCntrl->uiLastRecEnd, - uiLastIxNum = 0, - uiTargetCount = pKrefCntrl->uiCount; - uiCurKrefNum < uiTargetCount; - // Increment uiCurKrefNum at bottom of loop - ) - { - pKref = pKrefTbl [uiCurKrefNum]; - - if( pKref->uiFlags & KREF_UNIQUE_KEY) - { - flmAssert( pKref->ui16IxNum > 0 && - pKref->ui16IxNum < FLM_UNREGISTERED_TAGS); // Sanity check - - if( pKref->ui16IxNum != uiLastIxNum) - { - uiLastIxNum = pKref->ui16IxNum; - if (RC_BAD( rc = fdictGetIndex( - pDb->pDict, pDb->pFile->bInLimitedMode, - uiLastIxNum, &pLFile, NULL))) - { - // Return the index offline error - should not happen - flmAssert( rc != FERR_INDEX_OFFLINE); - goto Exit; - } - } - - // Flush the key to the index. - - if( RC_BAD(rc = FSRefUpdate( pDb, pLFile, pKref))) - { - pDb->Diag.uiInfoFlags |= FLM_DIAG_INDEX_NUM; - pDb->Diag.uiIndexNum = pKref->ui16IxNum; - - // Check only for FERR_NOT_UNIQUE - - if( rc != FERR_NOT_UNIQUE) - goto Exit; - - bUniqueErrorHit = TRUE; - - // Cycle through again backing out all keys. - - uiTargetCount = uiCurKrefNum; - uiCurKrefNum = pKrefCntrl->uiLastRecEnd; - // Make sure uiCurKrefNum is NOT incremented at the top of loop. - continue; - } - // Toggle the delete flag so on unique error we can back out. - // This sets the ADD to DELETE and the DELETE to ADD (0) - - pKref->uiFlags ^= KREF_DELETE_FLAG; - } - uiCurKrefNum++; - } - - if( bUniqueErrorHit) - { - rc = RC_SET( FERR_NOT_UNIQUE); - pKrefCntrl->uiCount = pKrefCntrl->uiLastRecEnd; - } - else - { - // Scoot ever key down removing the processed keys. - - for( uiCurKrefNum = uiPrevKrefNum = pKrefCntrl->uiLastRecEnd, - uiTargetCount = pKrefCntrl->uiCount; - uiCurKrefNum < uiTargetCount; - uiCurKrefNum++) - { - pKref = pKrefTbl [uiCurKrefNum]; - - if( !(pKref->uiFlags & KREF_UNIQUE_KEY )) - { - pKrefTbl [ uiPrevKrefNum++ ] = pKrefTbl [uiCurKrefNum ]; - } - } - pKrefCntrl->uiCount = uiPrevKrefNum; - } - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Compare function used to compare two keys. The compare is - different depending on the sort pass this is on. -Note: We must compare each item in the structure because UNIX will - place structure elements in any order it feels. - - (SORT1) KY_DUP_CHK_SRT == pLfd | key | DELETE_FLAG - (SORT2) KY_FINAL_SRT == pLfd | key | DRN | TrnsSeq - set IGNORE on EQ -****************************************************************************/ -FSTATIC FLMINT _KrefCompare( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p pKrefA, - KREF_ENTRY_p pKrefB ) -{ - FLMUINT uiMinLen; /* Minimum key length of A or B */ - FLMINT iCompare; - - /* Compare (SORT1) #1, (SORT2) #2 - Index Number. */ - - if ((iCompare = ((FLMINT) pKrefA->ui16IxNum) - ((FLMINT) pKrefB->ui16IxNum)) != 0) - return( iCompare); - - /* Compare (SORT1) #2, (SORT2) #3: KEY - including NULL character at end. */ - /* Comparing the NULL character advoids checking the key length. */ - /* VISIT: There could be a BUG where key length should be checked, but - it has to do with not storing all compound key pieces in the key. */ - - uiMinLen = f_min( pKrefA->ui16KeyLen, pKrefB->ui16KeyLen) + 1; - if ((iCompare = f_memcmp( &pKrefA [1], &pKrefB [1], uiMinLen)) == 0) - { - if( *puiQsortFlags & KY_FINAL_SRT) - { - /* Compare (SORT2) The DRN so we load by low DRN to high DRN. */ - - if( pKrefA->uiDrn < pKrefB->uiDrn) - return -1; - else if( pKrefA->uiDrn > pKrefB->uiDrn ) - return 1; - - /* - Compare (SORT2) Sequence number, so operations occur in - correct order. - this will ALWAYS set iCompare to -1 or 1. - It is only possible to have different operations here like - ADD - DELETE - ADD - DELETE when sorted by uiTrnsSeq. This - is why we will set KY_DUPS_FOUND to get rid of duplicates. - */ - - iCompare = ((FLMINT)pKrefA->uiTrnsSeq) - ((FLMINT)pKrefB->uiTrnsSeq); - - } - else // if( *puiQsortFlags & KY_DUP_CHK_SRT ) - { - - /* Compare (SORT1) Operation Flag, Delete or Add. */ - - *puiQsortFlags |= KY_DUPS_FOUND; - - /* Sort so the delete elements are first. */ - - if ((iCompare = ((FLMINT)(pKrefB->uiFlags & KREF_DELETE_FLAG)) - - ((FLMINT)(pKrefA->uiFlags & KREF_DELETE_FLAG))) == 0) - { - /* Exact duplicate - will remove later */ - - pKrefA->uiFlags |= KREF_EQUAL_FLAG; - pKrefB->uiFlags |= KREF_EQUAL_FLAG; - } - else - { - /* Data is same but different operation, (delete then an add). */ - - pKrefA->uiFlags |= KREF_IGNORE_FLAG; - pKrefB->uiFlags |= KREF_IGNORE_FLAG; - } - } - } - return( iCompare); -} - -/*************************************************************************** -Desc: Quick sort an array of KREF_ENTRY_p values. -Notes: Optimized the above quicksort algorithm. This is the same code - as the quick sort in FRSET.C which has lots of comments. We - didn't combine the code because a general quick sort would be - slower for the KREF and I didn't want to change that much code. -****************************************************************************/ - -FSTATIC RCODE _KrefQuickSort( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p * pEntryTbl, - FLMUINT uiLowerBounds, - FLMUINT uiUpperBounds) -{ - FLMUINT uiLBPos, uiUBPos, uiMIDPos; - FLMUINT uiLeftItems, uiRightItems; - KREF_ENTRY_p pCurEntry, pTempKref; - FLMINT iCompare; - -Iterate_Larger_Half: - - uiUBPos = uiUpperBounds; - uiLBPos = uiLowerBounds; - uiMIDPos = (uiUpperBounds + uiLowerBounds + 1) / 2; - pCurEntry = pEntryTbl[ uiMIDPos ]; - for( ;;) - { - while( (uiLBPos == uiMIDPos) // Don't compare with target - || ((iCompare = - _KrefCompare( puiQsortFlags, pEntryTbl[ uiLBPos], pCurEntry)) < 0)) - { - if( uiLBPos >= uiUpperBounds) break; - uiLBPos++; - } - - while( (uiUBPos == uiMIDPos) // Don't compare with target - || (((iCompare = - _KrefCompare( puiQsortFlags, pCurEntry, pEntryTbl[ uiUBPos])) < 0))) - { - if( !uiUBPos) break; - uiUBPos--; - } - - if( uiLBPos < uiUBPos ) // Interchange and continue loop. - { - /* Interchange [uiLBPos] with [uiUBPos]. */ - - KY_SWAP( pEntryTbl, uiLBPos, uiUBPos ); - uiLBPos++; // Scan from left to right. - uiUBPos--; // Scan from right to left. - } - else // Past each other - done - { - break; - } - } - /* Check for swap( LB, MID ) - cases 3 and 4 */ - - if( uiLBPos < uiMIDPos ) - { - /* Interchange [uiLBPos] with [uiMIDPos] */ - - KY_SWAP( pEntryTbl, uiMIDPos, uiLBPos ); - uiMIDPos = uiLBPos; - } - else if( uiMIDPos < uiUBPos ) - { - /* Interchange [uUBPos] with [uiMIDPos] */ - - KY_SWAP( pEntryTbl, uiMIDPos, uiUBPos ); - uiMIDPos = uiUBPos; - } - - /* Check the left piece. */ - - uiLeftItems = (uiLowerBounds + 1 < uiMIDPos ) - ? uiMIDPos - uiLowerBounds // 2 or more - : 0; - uiRightItems = (uiMIDPos + 1 < uiUpperBounds ) - ? uiUpperBounds - uiMIDPos // 2 or more - : 0; - - if( uiLeftItems < uiRightItems ) - { - /* Recurse on the LEFT side and goto the top on the RIGHT side. */ - - if( uiLeftItems ) - { - (void) _KrefQuickSort( puiQsortFlags, pEntryTbl, - uiLowerBounds, uiMIDPos - 1 ); - } - uiLowerBounds = uiMIDPos + 1; - goto Iterate_Larger_Half; - } - else if( uiLeftItems ) // Compute a truth table to figure out this check. - { - /* Recurse on the RIGHT side and goto the top for the LEFT side. */ - - if( uiRightItems ) - { - (void) _KrefQuickSort( puiQsortFlags, pEntryTbl, - uiMIDPos + 1, uiUpperBounds ); - } - uiUpperBounds = uiMIDPos - 1; - goto Iterate_Larger_Half; - } -//Exit: - return FERR_OK; -} - -/**************************************************************************** -Desc: Kill all duplicate references out of the kref list -Notes: This will ONLY work if EVERY kref has been compared to its neighbor. - We may have to compare every neighbor again if the new quick sort - doesn't work. -****************************************************************************/ -FSTATIC RCODE _KrefKillDups( - FLMUINT * puiQsortFlags, - KREF_ENTRY_p * pKrefTbl, /* Portion of KREF table where duplicates - are to be eliminated. */ - FLMUINT * puiKrefTotalRV)/* Number of elements in portion of KREF table - where duplicates are to be eliminated. - It returns the number of elements that - are left after duplicates are eliminated.*/ -{ - FLMUINT uiTotal = (*puiKrefTotalRV); - FLMUINT uiCurKrefNum; - KREF_ENTRY_p pCurKref; - FLMUINT uiLastUniqueKrefNum = 0; - - for (uiCurKrefNum = 1; uiCurKrefNum < uiTotal; uiCurKrefNum++) - { - pCurKref = pKrefTbl [uiCurKrefNum]; - - /* - If the current KREF equals the last unique one, we can - remove it from the list by skipping the current entry. - To check if they are equal, first look at the KREF_EQUAL_FLAGs - on both of them. If both KREFs have this flag set, we still - have to call the compare routine. The flags could have been set for - two pairs of different keys - such as A, A, B, B. In this - sequence of keys, all four KREFs would have the flag set, but - the 2nd "A" is not equal to the 1st "B" - thus the need for the - call to krefCompare to confirm that the keys are really equal. - */ - - if ((pKrefTbl [uiLastUniqueKrefNum]->uiFlags & KREF_EQUAL_FLAG) && - (pCurKref->uiFlags & KREF_EQUAL_FLAG) && - (_KrefCompare( puiQsortFlags, pKrefTbl[uiLastUniqueKrefNum], pCurKref) == 0)) - { - /* - If the current KREF had it's ignore flag set, propagate that - to the last unique KREF also and remove the current key. - This will remove all but the first duplicate key. - This is possible because quick sort may not compare every item. - */ - - if (pCurKref->uiFlags & KREF_IGNORE_FLAG) - pKrefTbl [uiLastUniqueKrefNum]->uiFlags |= KREF_IGNORE_FLAG; - } - else - { - // Increment to the next slot if we like this kref. - - if( !(pKrefTbl [uiLastUniqueKrefNum]->uiFlags & KREF_IGNORE_FLAG)) - { - uiLastUniqueKrefNum++; - } - - // Move the item to the current location. - - pKrefTbl [uiLastUniqueKrefNum] = pCurKref; - - } - } - if( !(pKrefTbl [uiLastUniqueKrefNum]->uiFlags & KREF_IGNORE_FLAG)) - { - uiLastUniqueKrefNum++; - } - - *puiKrefTotalRV = uiLastUniqueKrefNum; // One based number -//Exit: - return( FERR_OK); -} diff --git a/flaim/src/kyunlock.cpp b/flaim/src/kyunlock.cpp deleted file mode 100644 index 3b7c6d1..0000000 --- a/flaim/src/kyunlock.cpp +++ /dev/null @@ -1,162 +0,0 @@ -//------------------------------------------------------------------------- -// Desc: Unlock/free KREF structures. -// Tabs: 3 -// -// Copyright (c) 1992-2000,2002-2003,2005-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: kyunlock.cpp 12329 2006-01-20 17:49:30 -0700 (Fri, 20 Jan 2006) ahodgkinson $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define KREF_TBL_SIZE 512 -#define KREF_TBL_THRESHOLD 400 -#define KREF_POOL_BLOCK_SIZE 8192 -#define KREF_TOTAL_BYTES_THRESHOLD ((KREF_POOL_BLOCK_SIZE * 3) - 250) - -/**************************************************************************** -Desc: Setup routine for the KREF_CNTRL structure for record updates. - Will check to see if all structures, buffers and memory pools - need to be allocated: Kref key buffer, CDL table, KrefTbl and pool. - The goal is to have only one allocation for most small transactions. - As of Nov 96, each DB will have its own KREF_CNTRL struture so the - session temp pool does not have to be used. This means that the - CDL and cmpKeys arrays do not have to be allocated for each - record operation (like we did in the session pool). -****************************************************************************/ -RCODE KrefCntrlCheck( - FDB_p pDb) -{ - RCODE rc = FERR_OK; // Set for cleaner code. - KREF_CNTRL_p pKrefCntrl; - - pKrefCntrl = &pDb->KrefCntrl; - - /* Check if we need to flush between the records and not during - the processing of a record. This simplifies how we reuse the memory. - */ - - if( pKrefCntrl->bKrefSetup) - { - if( (pKrefCntrl->uiCount >= KREF_TBL_THRESHOLD) - || (pKrefCntrl->uiTotalBytes >= KREF_TOTAL_BYTES_THRESHOLD)) - - { - if( RC_BAD( rc = KYKeysCommit( pDb, FALSE))) - { - goto Exit; - } - } - } - else - { - FLMUINT uiKrefTblSize = KREF_TBL_SIZE * sizeof(KREF_ENTRY_p); - FLMUINT uiCDLSize = pDb->pDict->uiIfdCnt * sizeof( CDL_p); - FLMUINT uiIxdSize = pDb->pDict->uiIxdCnt; - FLMUINT uiKeyBufSize = MAX_KEY_SIZ + 8; - - f_memset( pKrefCntrl, 0, sizeof( KREF_CNTRL)); - pKrefCntrl->bKrefSetup = TRUE; - if (pDb->uiTransType == FLM_UPDATE_TRANS) - { - pKrefCntrl->pPool = &pDb->pFile->krefPool; - pKrefCntrl->bReusePool = TRUE; - } - else - { - pKrefCntrl->pPool = &pDb->tmpKrefPool; - pKrefCntrl->bReusePool = FALSE; - } - - if (pKrefCntrl->bReusePool) - { - GedPoolReset( pKrefCntrl->pPool, NULL); - } - else - { - GedPoolInit( pKrefCntrl->pPool, KREF_POOL_BLOCK_SIZE); - } - - if( RC_BAD( rc = f_alloc( uiKrefTblSize, - &pKrefCntrl->pKrefTbl)) - || (uiCDLSize && RC_BAD( rc = f_calloc( uiCDLSize, - &pKrefCntrl->ppCdlTbl))) - || (uiIxdSize && RC_BAD( rc = f_calloc( uiIxdSize, - &pKrefCntrl->pIxHasCmpKeys))) - || RC_BAD( rc = f_calloc( uiKeyBufSize, - &pKrefCntrl->pKrefKeyBuf))) - { - KrefCntrlFree( pDb); - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pKrefCntrl->uiKrefTblSize = KREF_TBL_SIZE; - } - - pKrefCntrl->pReset = GedPoolMark( pKrefCntrl->pPool); - -Exit: - - return( rc); -} - -/**************************************************************************** -Desc: Resets or frees the memory associated with the KREF. -****************************************************************************/ -void KrefCntrlFree( - FDB_p pDb) -{ - KREF_CNTRL_p pKrefCntrl = &pDb->KrefCntrl; - - if( pKrefCntrl->bKrefSetup) - { - if (pKrefCntrl->bReusePool) - { - GedPoolReset( pKrefCntrl->pPool, NULL); - } - else - { - GedPoolFree( pKrefCntrl->pPool); - } - - if( pKrefCntrl->pKrefTbl) - { - f_free( &pKrefCntrl->pKrefTbl); - } - - if( pKrefCntrl->ppCdlTbl) - { - f_free( &pKrefCntrl->ppCdlTbl); - } - - if( pKrefCntrl->pIxHasCmpKeys) - { - f_free( &pKrefCntrl->pIxHasCmpKeys); - } - - if( pKrefCntrl->pKrefKeyBuf) - { - f_free( &pKrefCntrl->pKrefKeyBuf); - } - - // Just set everyone back to zero. - - f_memset( pKrefCntrl, 0, sizeof(KREF_CNTRL)); - } -} diff --git a/flaim/src/lock.cpp b/flaim/src/lock.cpp index 1cade82..529bec9 100644 --- a/flaim/src/lock.cpp +++ b/flaim/src/lock.cpp @@ -24,10 +24,323 @@ #include "flaimsys.h" +/**************************************************************************** +Desc: Obtains a a lock on the database. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbLock( + HFDB hDb, + FLOCK_TYPE eLockType, + FLMINT iPriority, + FLMUINT uiTimeout) +{ + RCODE rc = FERR_OK; + FLMBOOL bIgnore; + FDB * pDb = (FDB *)hDb; + + if (IsInCSMode( hDb)) + { + fdbInitCS( pDb); + + CS_CONTEXT * pCSContext = pDb->pCSContext; + FCL_WIRE Wire( pCSContext, pDb); + + if( !pCSContext->bConnectionGood) + { + rc = RC_SET( FERR_BAD_SERVER_CONNECTION); + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendOp( + FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_LOCK))) + { + goto Exit; + } + + if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_NUMBER1, + (FLMUINT)eLockType))) + { + goto Transmission_Error; + } + + if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_SIGNED_NUMBER, + 0, iPriority))) + { + goto Transmission_Error; + } + + if (RC_BAD( rc = Wire.sendNumber( WIRE_VALUE_FLAGS, uiTimeout))) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendTerminate())) + { + goto Transmission_Error; + } + + // Read the response + + if (RC_BAD( rc = Wire.read())) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.getRCode())) + { + goto Exit; + } + + goto Exit; + +Transmission_Error: + + pCSContext->bConnectionGood = FALSE; + goto Exit; + } + + if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, + FDB_TRANS_GOING_OK, 0, &bIgnore))) + { + goto Exit; + } + + // eLockType better be exclusive or shared + + if ((eLockType != FLM_LOCK_EXCLUSIVE) && (eLockType != FLM_LOCK_SHARED)) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Nesting of locks is not allowed - this test also keeps this call from + // being executed inside an update transaction that implicitly acquired + // the lock. + + if (pDb->uiFlags & + (FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED | FDB_FILE_LOCK_IMPLICIT)) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Attempt to acquire the lock. + + if (RC_BAD( rc = pDb->pFile->pFileLockObj->Lock( TRUE, pDb, FALSE, + (FLMBOOL)((eLockType == FLM_LOCK_EXCLUSIVE) + ? (FLMBOOL)TRUE + : (FLMBOOL)FALSE), + uiTimeout, iPriority, + pDb->pDbStats))) + { + goto Exit; + } + + pDb->uiFlags |= FDB_HAS_FILE_LOCK; + + if (eLockType == FLM_LOCK_SHARED) + { + pDb->uiFlags |= FDB_FILE_LOCK_SHARED; + } + +Exit: + + flmExit( FLM_DB_LOCK, pDb, rc); + return( rc); +} + +/**************************************************************************** +Desc: Releases a lock on the database +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbUnlock( + HFDB hDb) +{ + RCODE rc = FERR_OK; + FDB * pDb = (FDB *)hDb; + FLMBOOL bIgnore; + + if (IsInCSMode( hDb)) + { + fdbInitCS( pDb); + + CS_CONTEXT * pCSContext = pDb->pCSContext; + FCL_WIRE Wire( pCSContext, pDb); + + if( !pCSContext->bConnectionGood) + { + rc = RC_SET( FERR_BAD_SERVER_CONNECTION); + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.sendOp( + FCS_OPCLASS_DATABASE, FCS_OP_DATABASE_UNLOCK))) + { + goto Exit; + } + + if( RC_BAD( rc = Wire.sendTerminate())) + { + goto Transmission_Error; + } + + // Read the response + + if (RC_BAD( rc = Wire.read())) + { + goto Transmission_Error; + } + + if( RC_BAD( rc = Wire.getRCode())) + { + goto Exit; + } + + goto Exit; + +Transmission_Error: + + pCSContext->bConnectionGood = FALSE; + goto Exit; + } + + if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, + FDB_TRANS_GOING_OK | FDB_CLOSING_OK, 0, &bIgnore))) + { + goto Exit; + } + + // If we don't have an explicit lock, can't do the unlock. It is + // also illegal to do the unlock during an update transaction. + + if (!(pDb->uiFlags & FDB_HAS_FILE_LOCK) || + (pDb->uiFlags & FDB_FILE_LOCK_IMPLICIT) || + (pDb->uiTransType == FLM_UPDATE_TRANS)) + { + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Unlock the file. + + if (RC_BAD( rc = pDb->pFile->pFileLockObj->Unlock( TRUE, pDb))) + { + goto Exit; + } + + // Unset the flags that indicated the file was explicitly locked. + + pDb->uiFlags &= (~(FDB_HAS_FILE_LOCK | FDB_FILE_LOCK_SHARED)); + +Exit: + + if( RC_OK( rc)) + { + rc = flmCheckDatabaseState( pDb); + } + + flmExit( FLM_DB_UNLOCK, pDb, rc); + return( rc); +} + +/**************************************************************************** +Desc : Returns information about current and pending locks on the + database. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbGetLockInfo( + HFDB hDb, + FLMINT iPriority, + FLOCK_INFO * pLockInfo) +{ + RCODE rc = FERR_OK; + FDB * pDb = NULL; + FLMBOOL bIgnore; + + if (IsInCSMode( hDb)) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + + pDb = (FDB *)hDb; + if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, + FDB_TRANS_GOING_OK, 0, &bIgnore))) + { + goto Exit; + } + + pDb->pFile->pFileLockObj->GetLockInfo( iPriority, pLockInfo); + +Exit: + + flmExit( FLM_DB_GET_LOCK_INFO, pDb, rc); + return( rc); +} + +/**************************************************************************** +Desc : Returns information about the lock held by the specified database + handle. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbGetLockType( + HFDB hDb, + FLOCK_TYPE * peLockType, + FLMBOOL * pbImplicit) +{ + RCODE rc = FERR_OK; + FDB * pDb = NULL; + FLMBOOL bIgnore; + + if( peLockType) + { + *peLockType = FLM_LOCK_NONE; + } + + if( pbImplicit) + { + *pbImplicit = FALSE; + } + + if (IsInCSMode( hDb)) + { + rc = RC_SET( FERR_NOT_IMPLEMENTED); + goto Exit; + } + + pDb = (FDB *)hDb; + if (RC_BAD( rc = fdbInit( pDb, FLM_NO_TRANS, + FDB_TRANS_GOING_OK, 0, &bIgnore))) + { + goto Exit; + } + + if( pDb->uiFlags & FDB_HAS_FILE_LOCK) + { + if( peLockType) + { + if( pDb->uiFlags & FDB_FILE_LOCK_SHARED) + { + *peLockType = FLM_LOCK_SHARED; + } + else + { + *peLockType = FLM_LOCK_EXCLUSIVE; + } + } + + if( pbImplicit) + { + *pbImplicit = (pDb->uiFlags & FDB_FILE_LOCK_IMPLICIT) + ? TRUE + : FALSE; + } + } + +Exit: + + flmExit( FLM_DB_GET_LOCK_TYPE, pDb, rc); + return( rc); +} + /**************************************************************************** Desc: This routine locks a database for exclusive access. -Ret: FERR_OK - Indicates that the database was successfully locked. - FCERR_LOCK - Error locking database file. ****************************************************************************/ RCODE dbLock( FDB * pDb, @@ -99,9 +412,6 @@ Exit: /**************************************************************************** Desc: This routine unlocks a database that was previously locked using the dbLock routine. -Ret: FERR_OK - Indicates that the database was - successfully unlocked. - FERR_UNLOCK - Error unlocking file. ****************************************************************************/ RCODE dbUnlock( FDB * pDb) @@ -126,6 +436,5 @@ RCODE dbUnlock( } } -// Exit: return( rc); } diff --git a/flaim/src/rcache.cpp b/flaim/src/rcache.cpp index 2dd585b..98bc7a4 100644 --- a/flaim/src/rcache.cpp +++ b/flaim/src/rcache.cpp @@ -25,8 +25,9 @@ #include "flaimsys.h" #if defined( FLM_NLM) && !defined( __MWERKS__) -// Disable "Warning! W549: col(XX) 'sizeof' operand contains -// compiler generated information" + // Disable "Warning! W549: col(XX) 'sizeof' operand contains + // compiler generated information" + #pragma warning 549 9 #endif @@ -37,8 +38,9 @@ FSTATIC void rcaRelocate( void * pvOldAlloc, void * pvNewAlloc); -// Extended record object for accessing private members of FlmRecord - +/**************************************************************************** +Desc: Extended record object for accessing private members of FlmRecord +****************************************************************************/ struct FlmRecordExt { static FINLINE void clearCached( @@ -109,8 +111,11 @@ struct FlmRecordExt // Functions for calculating minimum and maximum record counts for a // given hash table size. -#define FLM_RCA_MIN_REC_CNT(uiHashTblSz) ((uiHashTblSz) / 4) -#define FLM_RCA_MAX_REC_CNT(uiHashTblSz) ((uiHashTblSz) * 4) +#define FLM_RCA_MIN_REC_CNT(uiHashTblSz) \ + ((uiHashTblSz) / 4) + +#define FLM_RCA_MAX_REC_CNT(uiHashTblSz) \ + ((uiHashTblSz) * 4) // Hash function for hashing to records in record cache. @@ -118,7 +123,7 @@ struct FlmRecordExt (RCACHE **)(&(gv_FlmSysData.RCacheMgr.ppHashBuckets[(uiDrn) & \ (gv_FlmSysData.RCacheMgr.uiHashMask)])) -/* LOCAL STATIC FUNCTION PROTOTYPES */ +// Local functions FSTATIC void flmRcaFreePurged( RCACHE * pRCache); @@ -136,12 +141,12 @@ FSTATIC RCODE flmRcaSetMemLimit( FLMUINT uiMaxCacheBytes); FSTATIC RCODE flmRcaWaitNotify( - FNOTIFY ** ppNotifyListRV); + FNOTIFY ** ppNotifyListRV); FSTATIC void flmRcaNotify( - FNOTIFY * pNotify, - RCACHE * pUseRCache, - RCODE NotifyRc); + FNOTIFY * pNotify, + RCACHE * pUseRCache, + RCODE NotifyRc); FSTATIC RCODE flmRcaAllocCacheStruct( RCACHE ** ppRCache); @@ -161,16 +166,16 @@ FSTATIC void flmRcaLinkIntoRCache( FSTATIC void flmRcaLinkToFFILE( RCACHE * pRCache, - FFILE_p pFile, - FDB_p pDb, + FFILE * pFile, + FDB * pDb, FLMUINT uiLowTransId, FLMBOOL bMostCurrent); #ifdef FLM_DEBUG FSTATIC RCODE flmRcaCheck( - FDB_p pDb, - FLMUINT uiContainer, - FLMUINT uiDrn); + FDB * pDb, + FLMUINT uiContainer, + FLMUINT uiDrn); #endif /**************************************************************************** @@ -395,7 +400,7 @@ Desc: This routine links a record to an FFILE list at the head of the list. ****************************************************************************/ FINLINE void flmRcaLinkToFileAtHead( RCACHE * pRCache, - FFILE_p pFile) + FFILE * pFile) { pRCache->pPrevInFile = NULL; if ((pRCache->pNextInFile = pFile->pFirstRecord) != NULL) @@ -419,7 +424,7 @@ Desc: This routine links a record to an FFILE list at the end of the list. ****************************************************************************/ FINLINE void flmRcaLinkToFileAtEnd( RCACHE * pRCache, - FFILE_p pFile) + FFILE * pFile) { pRCache->pNextInFile = NULL; if( (pRCache->pPrevInFile = pFile->pLastRecord) != NULL) @@ -452,6 +457,7 @@ FINLINE void flmRcaUnlinkFromFile( { pRCache->pFile->pLastRecord = pRCache->pPrevInFile; } + if( pRCache->pPrevInFile) { pRCache->pPrevInFile->pNextInFile = pRCache->pNextInFile; @@ -460,6 +466,7 @@ FINLINE void flmRcaUnlinkFromFile( { pRCache->pFile->pFirstRecord = pRCache->pNextInFile; } + pRCache->pPrevInFile = pRCache->pNextInFile = NULL; RCA_UNSET_LINKED_TO_FILE( pRCache->uiFlags); } @@ -496,6 +503,7 @@ FINLINE void flmRcaUnlinkFromHashBucket( { pRCache->pNextInBucket->pPrevInBucket = pRCache->pPrevInBucket; } + if (pRCache->pPrevInBucket) { pRCache->pPrevInBucket->pNextInBucket = pRCache->pNextInBucket; @@ -521,6 +529,7 @@ FINLINE void flmRcaLinkToVerList( { pNewerVer->pOlderVersion = pRCache; } + if ((pRCache->pOlderVersion = pOlderVer) != NULL) { pOlderVer->pNewerVersion = pRCache; @@ -538,6 +547,7 @@ FINLINE void flmRcaUnlinkFromVerList( { pRCache->pNewerVersion->pOlderVersion = pRCache->pOlderVersion; } + if (pRCache->pOlderVersion) { pRCache->pOlderVersion->pNewerVersion = pRCache->pNewerVersion; @@ -877,9 +887,10 @@ FSTATIC FLMUINT flmRcaGetBestHashTblSize( // we are either below the lowest minimum, or higher than the // highest maximum. - uiHashTblSize = (FLMUINT)((uiCurrRecCount < FLM_RCA_MIN_REC_CNT( MIN_RCACHE_BUCKETS)) - ? (FLMUINT)MIN_RCACHE_BUCKETS - : (FLMUINT)MAX_RCACHE_BUCKETS); + uiHashTblSize = + (FLMUINT)((uiCurrRecCount < FLM_RCA_MIN_REC_CNT( MIN_RCACHE_BUCKETS)) + ? (FLMUINT)MIN_RCACHE_BUCKETS + : (FLMUINT)MAX_RCACHE_BUCKETS); } else @@ -1496,7 +1507,7 @@ Desc: This routine finds a record in the record cache. If it cannot void flmRcaFindRec( FLMUINT uiContainer, FLMUINT uiDrn, - FFILE_p pFile, + FFILE * pFile, FLMUINT uiVersionNeeded, FLMBOOL bDontPoisonCache, FLMUINT * puiNumLooks, @@ -1761,8 +1772,8 @@ Desc: This routine links a new record to its FFILE according to whether ****************************************************************************/ FSTATIC void flmRcaLinkToFFILE( RCACHE * pRCache, - FFILE_p pFile, - FDB_p pDb, + FFILE * pFile, + FDB * pDb, FLMUINT uiLowTransId, FLMBOOL bMostCurrent) { @@ -1959,7 +1970,7 @@ RCODE flmRcaRetrieveRec( { RCODE rc = FERR_OK; FLMBOOL bRCacheMutexLocked = FALSE; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; RCACHE * pRCache; RCACHE * pNewerRCache; RCACHE * pOlderRCache; @@ -1970,7 +1981,7 @@ RCODE flmRcaRetrieveRec( FLMUINT uiLowTransId; FLMBOOL bMostCurrent; FLMUINT uiCurrTransId; - FNOTIFY_p pNotify; + FNOTIFY * pNotify; FLMUINT uiNumLooks; FLMBOOL bInitializedFdb = FALSE; FLMBOOL bDontPoisonCache = pDb->uiFlags & FDB_DONT_POISON_CACHE @@ -2096,6 +2107,7 @@ Start_Find: // because they won't match a NULL FFILE. The result of not setting // the FFILE is that multiple copies of the same version of a particular // record could end up in cache. + pRCache->pFile = pFile; flmRcaLinkIntoRCache( pNewerRCache, pOlderRCache, @@ -2265,7 +2277,7 @@ RCODE flmRcaInsertRec( FlmRecord * pRecord) // Record to be inserted. { RCODE rc = FERR_OK; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; FLMUINT uiContainer = pLFile->uiLfNum; FLMBOOL bMutexLocked = FALSE; RCACHE * pRCache; @@ -2483,7 +2495,7 @@ RCODE flmRcaRemoveRec( RCACHE * pRCache; RCACHE * pNewerRCache; RCACHE * pOlderRCache; - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; flmAssert( uiDrn != 0); @@ -2564,7 +2576,7 @@ Desc: This routine is called when an FFILE structure is going to be removed of all records that have been cached for that FFILE. ****************************************************************************/ void flmRcaFreeFileRecs( - FFILE_p pFile) + FFILE * pFile) { FLMUINT uiNumFreed = 0; @@ -2599,10 +2611,9 @@ Desc: This routine is called when an update transaction aborts. At that the record cache. ****************************************************************************/ void flmRcaAbortTrans( - FDB * pDb - ) + FDB * pDb) { - FFILE_p pFile = pDb->pFile; + FFILE * pFile = pDb->pFile; RCACHE * pRCache; RCACHE * pOlderVersion; FLMUINT uiOlderTransId = @@ -2784,7 +2795,7 @@ Desc: ****************************************************************************/ #ifdef FLM_DEBUG FSTATIC RCODE flmRcaCheck( - FDB_p pDb, + FDB * pDb, FLMUINT uiContainer, FLMUINT uiDrn) { diff --git a/flaim/src/recover.cpp b/flaim/src/recover.cpp index ff950d7..19414ef 100644 --- a/flaim/src/recover.cpp +++ b/flaim/src/recover.cpp @@ -47,22 +47,17 @@ Ret: FERR_OK Indicates that we would have read beyond the log end-of-file. other other FLAIM error codes -SWPVISIT: Why is the block decrypted and then encrypted again? The block - does not change any - all we did was verify the checksum. - Note - blkChecksum() removes the checksum so we will still have - to call the checksum routine two times or have carnal knowledge - and remember the checksum low byte. ****************************************************************************/ FSTATIC RCODE flmReadLog( FDB * pDb, - FLMUINT uiLogEOF, /* Address of end of rollback log. */ - FLMUINT * puiCurrAddrRV, /* This is the current address we are - readingin the log file. It - will be updated after reading the - data. */ - FLMBYTE * pBlk, /* This is the buffer that is to hold - the data that is read from the - log file. */ + FLMUINT uiLogEOF, // Address of end of rollback log + FLMUINT * puiCurrAddrRV, // This is the current address we are + // reading in the log file. It + // will be updated after reading the + // data + FLMBYTE * pBlk, // This is the buffer that is to hold + // the data that is read from the + // log file FLMBOOL * pbIsBeforeImageBlkRV // Is block a before-image block? ) { @@ -76,7 +71,7 @@ FSTATIC RCODE flmReadLog( uiFilePos = *puiCurrAddrRV; - /* Verify that we are not going to read beyond the log EOF */ + // Verify that we are not going to read beyond the log EOF if (!FSAddrIsAtOrBelow( uiFilePos + uiBlkSize, uiLogEOF)) { @@ -84,7 +79,7 @@ FSTATIC RCODE flmReadLog( goto Exit; } - /* Position to the appropriate place and read the data */ + // Position to the appropriate place and read the data if (pDbStats) { @@ -125,7 +120,7 @@ FSTATIC RCODE flmReadLog( goto Exit; } - /* Verify the checksum on the block BEFORE decrypting */ + // Verify the checksum on the block if( RC_BAD( rc = BlkCheckSum( pBlk, CHECKSUM_CHECK, BT_END, uiBlkSize))) { @@ -136,16 +131,12 @@ FSTATIC RCODE flmReadLog( goto Exit; } - // See if BI bits are set. Unset them before - // decrypting or doing anything else with the - // the block so that the block type is accurate. - *pbIsBeforeImageBlkRV = (FLMBOOL)((BH_IS_BI( pBlk)) ? (FLMBOOL)TRUE : (FLMBOOL)FALSE); BH_UNSET_BI( pBlk); - /* Adjust the current address for the next read */ + // Adjust the current address for the next read uiFilePos += uiBlkSize; if (FSGetFileOffset( uiFilePos) >= pFile->uiMaxFileSize) @@ -163,9 +154,8 @@ FSTATIC RCODE flmReadLog( uiFileNumber++; } - if (uiFileNumber > - MAX_LOG_BLOCK_FILE_NUMBER( - pFile->FileHdr.uiVersionNum)) + if (uiFileNumber > + MAX_LOG_BLOCK_FILE_NUMBER( pFile->FileHdr.uiVersionNum)) { rc = RC_SET( FERR_DB_FULL); goto Exit; @@ -195,22 +185,20 @@ Ret: FERR_OK ****************************************************************************/ FSTATIC RCODE flmProcessBeforeImage( FDB * pDb, - FLMUINT uiLogEOF, /* Address of the end of the rollback - log. */ - FLMUINT * puiCurrAddrRV, /* This is the current offset we are - reading in the log file. - It will be updated after reading the - data. */ - FLMBYTE * pBlk, /* This is a pointer to a buffer that - will be used to hold the block that - is read. */ + FLMUINT uiLogEOF, // Address of the end of the rollback + // log + FLMUINT * puiCurrAddrRV, // This is the current offset we are + // reading in the log file. + // It will be updated after reading the + // data + FLMBYTE * pBlk, // This is a pointer to a buffer that + // will be used to hold the block that + // is read FLMBOOL bDoingRecovery, // Are we doing a recovery as opposed to // rolling back a transaction? - FLMUINT uiMaxTransID // Maximum transaction ID to recover to when + FLMUINT uiMaxTransID) // Maximum transaction ID to recover to when // bDoingRecovery is TRUE. This parameter // is ignored when bDoingRecover is FALSE. - - ) { RCODE rc = FERR_OK; FFILE * pFile = pDb->pFile; @@ -221,7 +209,7 @@ FSTATIC RCODE flmProcessBeforeImage( F_TMSTAMP StartTime; DB_STATS * pDbStats = pDb->pDbStats; - /* Read the block from the log */ + // Read the block from the log if (RC_BAD( rc = flmReadLog( pDb, uiLogEOF, puiCurrAddrRV, pBlk, &bIsBeforeImageBlk))) @@ -263,15 +251,15 @@ FSTATIC RCODE flmProcessBeforeImage( goto Exit; } - /* Determine the block address before setting the checksum. */ + // Determine the block address before setting the checksum uiBlkAddress = (FLMUINT)GET_BH_ADDR( pBlk); uiBlkLength = getEncryptSize( pBlk); - /* Set the block checksum AFTER encrypting */ + // Set the block checksum AFTER encrypting BlkCheckSum( pBlk, CHECKSUM_SET, - uiBlkAddress, pFile->FileHdr.uiBlockSize ); + uiBlkAddress, pFile->FileHdr.uiBlockSize); if (pDbStats) @@ -284,10 +272,9 @@ FSTATIC RCODE flmProcessBeforeImage( pDb->pSFileHdl->setMaxAutoExtendSize( pFile->uiMaxFileSize); pDb->pSFileHdl->setExtendSize( pFile->uiFileExtendSize); - rc = pDb->pSFileHdl->WriteBlock( uiBlkAddress, - uiBlkLength, pBlk, - pFile->FileHdr.uiBlockSize, - NULL, &uiBytesWritten); + rc = pDb->pSFileHdl->WriteBlock( uiBlkAddress, uiBlkLength, pBlk, + pFile->FileHdr.uiBlockSize, NULL, &uiBytesWritten); + #ifdef FLM_DBG_LOG flmDbgLogWrite( pFile->uiFFileId, uiBlkAddress, 0, FB2UD( &pBlk [BH_TRANS_ID]), @@ -319,14 +306,13 @@ RCODE flmWriteLogHdr( FLMBYTE * pucLogHdr, // Log header buffer. FLMBYTE * pucCPLogHdr, // Log header as it was at the time // of the checkpoint. - FLMBOOL bIsCheckpoint // Are we writing a checkpoint? If we + FLMBOOL bIsCheckpoint) // Are we writing a checkpoint? If we // we are, we may write the log header // as is. Otherwise, we need to make // sure we don't write out certain // parts of the log header - they must // not be updated on disk until a // checkpoint actually occurs. - ) { RCODE rc = FERR_OK; FLMUINT uiBytesWritten; @@ -360,7 +346,7 @@ RCODE flmWriteLogHdr( // Only copy the part of the header that is relevant for this // database version. - if( pFile->FileHdr.uiVersionNum < FLM_VER_4_3) + if( pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { f_memcpy( pucTmpLogHdr, pucLogHdr, LOG_HEADER_SIZE_VER40); } @@ -396,13 +382,13 @@ RCODE flmWriteLogHdr( f_memcpy( &pucTmpLogHdr [LOG_PF_NUM_AVAIL_BLKS], &pucCPLogHdr [LOG_PF_NUM_AVAIL_BLKS], 4); - if( pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) + if( pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) { f_memcpy( &pucTmpLogHdr [LOG_BLK_CHG_SINCE_BACKUP], &pucCPLogHdr [LOG_BLK_CHG_SINCE_BACKUP], 4); } - if( pFile->FileHdr.uiVersionNum >= FLM_VER_4_31) + if( pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31) { f_memcpy( &pucTmpLogHdr [LOG_LAST_RFL_COMMIT_ID], &pucCPLogHdr [LOG_LAST_RFL_COMMIT_ID], 4); @@ -412,7 +398,7 @@ RCODE flmWriteLogHdr( // If this is not a 4.3 database, make sure the old values // in the log header slots are preserved. - if( pFile->FileHdr.uiVersionNum < FLM_VER_4_3) + if( pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { // Compatibility for parts that were unused. @@ -430,7 +416,7 @@ RCODE flmWriteLogHdr( uiNewCheckSum = lgHdrCheckSum( pucTmpLogHdr, FALSE); UW2FBA( (FLMUINT16)uiNewCheckSum, &pucTmpLogHdr [LOG_HDR_CHECKSUM]); - /* Now update the log header record on disk. */ + // Now update the log header record on disk if (pDbStats) { @@ -578,6 +564,7 @@ RCODE flmPhysRollback( } Exit: + pDb->pSFileHdl->disableFlushMinimize(); // Free the memory handle, if one was allocated. diff --git a/flaim/src/rfl.cpp b/flaim/src/rfl.cpp index 0fd46f5..90072b8 100644 --- a/flaim/src/rfl.cpp +++ b/flaim/src/rfl.cpp @@ -1,7665 +1,8179 @@ -//------------------------------------------------------------------------- -// Desc: Routines for roll-forward logging. -// Tabs: 3 -// -// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. -// -// This program is free software; you can redistribute it and/or -// modify it under the terms of version 2 of the GNU General Public -// License as published by the Free Software Foundation. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, contact Novell, Inc. -// -// To contact Novell about this file by physical or electronic mail, -// you may find current contact information at www.novell.com -// -// $Id: rfl.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ -//------------------------------------------------------------------------- - -#include "flaimsys.h" - -#define MOD_512( uiNum) (FLMUINT)((uiNum) & 511) -#define ON_512_BYTE_BOUNDARY( uiNum) (!MOD_512(uiNum)) -#define ROUND_DOWN_TO_NEAREST_512( uiNum) \ - (FLMUINT)((uiNum) & (~((FLMUINT)511))) - -FSTATIC RCODE RflCheckMaxLogged( - FLMUINT * puiMaxBytesNeededRV, - FLMUINT uiPacketsLogged, - FLMUINT * puiCurrTotalLoggedRV, - FLMUINT uiBytesToLog); - -FSTATIC void RflChangeCallback( - GRD_DifferenceData & DiffData, - void * CallbackData); - -/******************************************************************** -Desc: Constructor -*********************************************************************/ -F_Rfl::F_Rfl() -{ - m_pFile = NULL; - m_hBufMutex = F_MUTEX_NULL; - m_pCommitBuf = NULL; - m_pCurrentBuf = NULL; - m_uiRflWriteBufs = DEFAULT_RFL_WRITE_BUFFERS; - m_uiBufferSize = DEFAULT_RFL_BUFFER_SIZE; - f_memset( &m_Buf1, 0, sizeof( m_Buf1)); - f_memset( &m_Buf2, 0, sizeof( m_Buf2)); - m_bKeepRflFiles = FALSE; - m_uiRflMinFileSize = DEFAULT_MIN_RFL_FILE_SIZE; - m_uiRflMaxFileSize = DEFAULT_MAX_RFL_FILE_SIZE; - m_pFileHdl = NULL; - m_uiLastRecoverFileNum = 0; - f_memset( m_ucCurrSerialNum, 0, sizeof( m_ucCurrSerialNum)); - m_bLoggingOff = FALSE; - m_bLoggingUnknown = FALSE; - m_uiUnknownPacketLen = 0; - m_bReadingUnknown = FALSE; - m_uiUnknownPacketBodyLen = 0; - m_pucUnknownPacketBody = NULL; - m_uiUnknownBodyLenProcessed = 0; - m_uiUnknownPacketRc = FERR_OK; - m_uiTransStartFile = 0; - m_uiTransStartAddr = 0; - m_uiCurrTransID = 0; - m_uiLastTransID = 0; - m_uiLastLoggedCommitTransID = 0; - m_uiOperCount = 0; - m_uiRflReadOffset = 0; - m_uiFileEOF = 0; - m_pRestore = NULL; - f_memset( m_szDbPrefix, 0, sizeof( m_szDbPrefix)); - f_memset( m_szRflDir, 0, sizeof( m_szRflDir)); - m_bRflDirSameAsDb = FALSE; - m_bCreateRflDir = FALSE; - f_memset( m_ucNextSerialNum, 0, sizeof( m_ucNextSerialNum)); - m_bRflVolumeOk = TRUE; - m_bRflVolumeFull = FALSE; -} - -/******************************************************************** -Desc: Destructor -*********************************************************************/ -F_Rfl::~F_Rfl() -{ - // Better not be in the middle of logging unknown packets for - // the application. - - flmAssert( !m_bLoggingUnknown); - - if (m_Buf1.pIOBuffer) - { - m_Buf1.pIOBuffer->Release(); - m_Buf1.pIOBuffer = NULL; - } - if (m_Buf2.pIOBuffer) - { - m_Buf2.pIOBuffer->Release(); - m_Buf2.pIOBuffer = NULL; - } - - if( m_Buf1.pBufferMgr) - { - flmAssert( !m_Buf1.pBufferMgr->havePendingIO() && - !m_Buf1.pBufferMgr->haveUsed()); - m_Buf1.pBufferMgr->Release(); - m_Buf1.pBufferMgr = NULL; - } - - if( m_Buf2.pBufferMgr) - { - flmAssert( !m_Buf2.pBufferMgr->havePendingIO() && - !m_Buf2.pBufferMgr->haveUsed()); - m_Buf2.pBufferMgr->Release(); - m_Buf2.pBufferMgr = NULL; - } - - if (m_hBufMutex != F_MUTEX_NULL) - { - f_mutexDestroy( &m_hBufMutex); - } - - if (m_pFileHdl) - { - m_pFileHdl->Close(); - m_pFileHdl->Release(); - m_pFileHdl = NULL; - m_pFile = NULL; - } -} - -/******************************************************************** -Desc: Returns a boolean indicating whether or not we are at - the end of the RFL log - will only be TRUE when we are - doing recovery. -*********************************************************************/ -FLMBOOL F_Rfl::atEndOfLog( void) -{ - return( (!m_pRestore && - m_uiFileEOF && - m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes >= m_uiFileEOF && - m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && - m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) - ? TRUE - : FALSE); -} - -/******************************************************************** -Desc: Gets the base RFL file name - does not have directory part. - This needs to be separate from the F_Rfl object so it can - be called without having to instantiate and set up an F_Rfl - object. -*********************************************************************/ -void rflGetBaseFileName( - FLMUINT uiDbVersion, - const char * pszDbPrefix, - FLMUINT uiFileNum, - char * pszBaseNameOut) -{ - FLMINT iCnt = 0; - FLMUINT uiDigit; - char * pszTmp = pszBaseNameOut; - - if (uiDbVersion < FLM_VER_4_3) - { - - // Output the database name prefix (up to three characters). - - f_strcpy( pszTmp, pszDbPrefix); - while (*pszTmp) - { - pszTmp++; - } - - // Output as five digit base 36 number. - - pszTmp += 4; - while (iCnt < 5) - { - uiDigit = (FLMUINT)(uiFileNum % 36); - uiFileNum /= 36; - if (uiDigit <= 9) - { - uiDigit += NATIVE_ZERO; - } - else - { - uiDigit += (NATIVE_LOWER_A - 10); - } - - *pszTmp = (FLMBYTE)uiDigit; - pszTmp--; - iCnt++; - } - - // Skip to end of digits and append ".log" to name - - pszTmp += 6; - f_strcpy( pszTmp, ".log"); - } - else - { - - // Output as eight digit hex number. - - pszTmp += 7; - while (iCnt < 8) - { - uiDigit = (FLMUINT)(uiFileNum & 0xF); - uiFileNum >>= 4; - if (uiDigit <= 9) - { - uiDigit += NATIVE_ZERO; - } - else - { - uiDigit += (NATIVE_LOWER_A - 10); - } - *pszTmp = (FLMBYTE)uiDigit; - pszTmp--; - iCnt++; - } - - // Skip to end of digits and append ".log" to name - - pszTmp += 9; - f_strcpy( pszTmp, ".log"); - } -} - -/******************************************************************** -Desc: Gets the base RFL file name - does not have directory part. -*********************************************************************/ -void F_Rfl::getBaseRflFileName( - FLMUINT uiFileNum, - char * pszBaseName) -{ - rflGetBaseFileName( m_pFile->FileHdr.uiVersionNum, - m_szDbPrefix, - uiFileNum, pszBaseName); -} - -/******************************************************************** -Desc: Generates the full roll forward log file name. - Name is based on the sequence number and the first three - characters of the database if the DB is less than version 4.3. - Otherwise, it is a hex number. -*********************************************************************/ -RCODE F_Rfl::getFullRflFileName( - FLMUINT uiFileNum, - char * pszRflFileName) -{ - RCODE rc = FERR_OK; - char szBaseName [F_FILENAME_SIZE]; - - // Get the directory name. - - f_strcpy( pszRflFileName, m_szRflDir); - - // Get the base RFL file name. - - getBaseRflFileName( uiFileNum, szBaseName); - - // Append the two together. - - if (RC_BAD( rc = f_pathAppend( pszRflFileName, szBaseName))) - { - goto Exit; - } - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Positions to the offset specified in the RFL file. -*********************************************************************/ -RCODE F_Rfl::positionTo( - FLMUINT uiFileOffset - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesToRead; - FLMUINT uiBytesRead; - - // Should never be attempting to position to something less - // than 512 - the header is stored in the first 512 bytes. - - flmAssert( uiFileOffset >= 512); - - // If the position is within our current buffer, see if we - // can adjust things without having to go back and re-read - // the buffer from disk. - - if (m_pCurrentBuf->uiRflBufBytes && - uiFileOffset >= m_pCurrentBuf->uiRflFileOffset && - uiFileOffset <= m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes) - { - - // Whatever is in the buffer beyond uiFileOffset is irrelevant - // and can be discarded. - - m_pCurrentBuf->uiRflBufBytes = uiFileOffset - - m_pCurrentBuf->uiRflFileOffset; - } - else - { - - // Populate the buffer from the 512 byte boundary that is just - // before the offset we are trying to position to. - - uiBytesToRead = MOD_512( uiFileOffset); - m_pCurrentBuf->uiRflFileOffset = ROUND_DOWN_TO_NEAREST_512( uiFileOffset); - m_pCurrentBuf->uiRflBufBytes = MOD_512( uiFileOffset); - if (m_pCurrentBuf->uiRflBufBytes) - { - if (RC_BAD( rc = m_pFileHdl->SectorRead( m_pCurrentBuf->uiRflFileOffset, - m_pCurrentBuf->uiRflBufBytes, - m_pCurrentBuf->pIOBuffer->m_pucBuffer, - &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - rc = RC_SET( FERR_NOT_RFL); - } - else - { - m_bRflVolumeOk = FALSE; - } - goto Exit; - } - else if (uiBytesRead < m_pCurrentBuf->uiRflBufBytes) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Get the ACTUAL RFL directory, using as input parameters the - database version, the name of the database, and the - user specified RFL directory. Also return the database - prefix. -*********************************************************************/ -RCODE rflGetDirAndPrefix( - FLMUINT uiDbVersionNum, - const char * pszDbFileName, - const char * pszRflDirIn, - char * pszRflDirOut, - char * pszDbPrefixOut) -{ - RCODE rc = FERR_OK; - char szDbPath [F_PATH_MAX_SIZE]; - char szBaseName [F_FILENAME_SIZE]; - - // Parse the database name into directory and base name - - if (RC_BAD( rc = f_pathReduce( pszDbFileName, - szDbPath, szBaseName))) - { - goto Exit; - } - - // Get the base path - - flmGetDbBasePath( pszDbPrefixOut, szBaseName, NULL); - - if (uiDbVersionNum >= FLM_VER_4_3) - { - - // Determine the RFL directory. If one was - // specified, it is whatever was specified. - // Otherwise, it is relative to the database - // directory. - - if (pszRflDirIn && *pszRflDirIn) - { - f_strcpy( pszRflDirOut, pszRflDirIn); - } - else - { - f_strcpy( pszRflDirOut, szDbPath); - } - - // For 4.3 and above, the RFL files go in - // a subdirectory underneath the directory where - // the database is located or the specified - // directory. - - f_strcpy( szBaseName, pszDbPrefixOut); - f_strcat( szBaseName, ".rfl"); - f_pathAppend( pszRflDirOut, szBaseName); - } - else - { - f_strcpy( pszRflDirOut, szDbPath); - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Set the RFL directory. If pszRflDir is NULL or empty string, - the RFL directory is set to the same directory as the - database. -*********************************************************************/ -RCODE F_Rfl::setRflDir( - const char * pszRflDir) -{ - // Better have set up the FFILE pointer. - - flmAssert( m_pFile != NULL); - - m_bRflDirSameAsDb = (!pszRflDir || !(*pszRflDir)) - ? TRUE - : FALSE; - - flmAssert( m_pFile->FileHdr.uiVersionNum); - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - - // Don't allow RFL directory to be specified for versions - // less than 4.3 - - pszRflDir = NULL; - m_bRflDirSameAsDb = TRUE; - } - - m_bCreateRflDir = - (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - ? TRUE - : FALSE; - return( rflGetDirAndPrefix( - m_pFile->FileHdr.uiVersionNum, m_pFile->pszDbPath, - pszRflDir, m_szRflDir, m_szDbPrefix)); -} - -/******************************************************************** -Desc: Gets an RFL file name - based on DB name and RFL directory. -*********************************************************************/ -RCODE rflGetFileName( - FLMUINT uiDbVersion, - const char * pszDbName, - const char * pszRflDir, - FLMUINT uiFileNum, - char * pszRflFileName) -{ - RCODE rc = FERR_OK; - char szDbPrefix[ F_FILENAME_SIZE]; - char szBaseName[ F_FILENAME_SIZE]; - - // Get the full RFL file name. - - if (RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDbName, - pszRflDir, pszRflFileName, szDbPrefix))) - { - goto Exit; - } - rflGetBaseFileName( uiDbVersion, szDbPrefix, uiFileNum, szBaseName); - if (RC_BAD( rc = f_pathAppend( pszRflFileName, szBaseName))) - { - goto Exit; - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Gets an RFL file number from the RFL file name. -*********************************************************************/ -FLMBOOL rflGetFileNum( - FLMUINT uiDbVersion, - const char * pszDbPrefix, - const char * pszRflFileName, - FLMUINT * puiFileNum) -{ - FLMBOOL bGotNum = FALSE; - char szDir[F_PATH_MAX_SIZE]; - char szBaseName[F_FILENAME_SIZE]; - char * pszTmp; - FLMUINT uiCharCnt; - - if( RC_BAD( f_pathReduce( pszRflFileName, szDir, szBaseName))) - { - goto Exit; - } - - // See if it has a .log extension. - - pszTmp = &szBaseName [0]; - while (*pszTmp && *pszTmp != '.') - { - pszTmp++; - } - - // If we do not have a .log extension, it is not a legitimate - // RFL file. - - if (f_stricmp( pszTmp, ".log") != 0) - { - goto Exit; - } - - // Parse out the name according to the rules for this DB version. - - *pszTmp = 0; // Set period to zero - pszTmp = &szBaseName [0]; - *puiFileNum = 0; - uiCharCnt = 0; - if (uiDbVersion >= FLM_VER_4_3) - { - - // Name up to the period should be a hex number - - while (*pszTmp) - { - (*puiFileNum) <<= 4; - if (*pszTmp >= NATIVE_ZERO && *pszTmp <= NATIVE_NINE) - { - *puiFileNum += (FLMUINT)(*pszTmp - NATIVE_ZERO); - } - else if (*pszTmp >= NATIVE_LOWER_A && *pszTmp <= NATIVE_LOWER_F) - { - *puiFileNum += ((FLMUINT)(*pszTmp - NATIVE_LOWER_A) + 10); - } - else if (*pszTmp >= NATIVE_UPPER_A && *pszTmp <= NATIVE_UPPER_F) - { - *puiFileNum += ((FLMUINT)(*pszTmp - NATIVE_UPPER_A) + 10); - } - else - { - goto Exit; // Not a hex number - } - uiCharCnt++; - pszTmp++; - } - - // Better have been exactly 8 hex digits. - - bGotNum = (FLMBOOL)((uiCharCnt == 8) - ? TRUE - : FALSE); - } - else - { - FLMUINT uiLen = f_strlen( pszTmp); - FLMUINT uiPrefixLen = f_strlen( pszDbPrefix); - - // Length of base name without the .log extension better - // be exactly 5 more characters than the length of - // the prefix. - - if (uiLen != uiPrefixLen + 5) - { - flmAssert( 0); - goto Exit; - } - - // Prefix better match. - - while (uiPrefixLen) - { - if (f_toupper( *pszTmp) != f_toupper( *pszDbPrefix)) - { - goto Exit; - } - uiPrefixLen--; - pszTmp++; - pszDbPrefix++; - } - - // Rest of the name is the five digits that are a base 36 number. - - while (*pszTmp) - { - (*puiFileNum) *= 36; - if (*pszTmp >= NATIVE_ZERO && *pszTmp <= NATIVE_NINE) - { - *puiFileNum += (FLMUINT)(*pszTmp - NATIVE_ZERO); - } - else if (*pszTmp >= NATIVE_LOWER_A && *pszTmp <= NATIVE_LOWER_Z) - { - *puiFileNum += ((FLMUINT)(*pszTmp - NATIVE_LOWER_A) + 10); - } - else if (*pszTmp >= NATIVE_UPPER_A && *pszTmp <= NATIVE_UPPER_Z) - { - *puiFileNum += ((FLMUINT)(*pszTmp - NATIVE_UPPER_A) + 10); - } - else - { - goto Exit; // Not a base 36 number - } - pszTmp++; - } - bGotNum = TRUE; - } -Exit: - return( bGotNum); -} - -/******************************************************************** -Desc: Sets up the RFL object - associating with a file, etc. -*********************************************************************/ -RCODE F_Rfl::setup( - FFILE * pFile, - const char * pszRflDir) -{ - RCODE rc = FERR_OK; - - // Better not already be associated with an FFILE - - flmAssert( m_pFile == NULL); - m_pFile = pFile; - - // Allocate memory for the RFL buffers - -#ifndef FLM_UNIX - if (!gv_FlmSysData.bOkToDoAsyncWrites) -#endif - { - m_uiRflWriteBufs = 1; - m_uiBufferSize = - DEFAULT_RFL_WRITE_BUFFERS * DEFAULT_RFL_BUFFER_SIZE; - } - - if (RC_BAD( rc = f_mutexCreate( &m_hBufMutex))) - { - goto Exit; - } - - if( (m_Buf1.pBufferMgr = f_new F_IOBufferMgr) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - if( (m_Buf2.pBufferMgr = f_new F_IOBufferMgr) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - m_Buf1.pBufferMgr->enableKeepBuffer(); - m_Buf1.pBufferMgr->setMaxBuffers( m_uiRflWriteBufs); - m_Buf1.pBufferMgr->setMaxBytes( m_uiRflWriteBufs * m_uiBufferSize); - - if( RC_BAD( rc = m_Buf1.pBufferMgr->getBuffer( &m_Buf1.pIOBuffer, - m_uiBufferSize, m_uiBufferSize))) - { - goto Exit; - } - - m_Buf2.pBufferMgr->enableKeepBuffer(); - m_Buf2.pBufferMgr->setMaxBuffers( m_uiRflWriteBufs); - m_Buf2.pBufferMgr->setMaxBytes( m_uiRflWriteBufs * m_uiBufferSize); - - if( RC_BAD( rc = m_Buf2.pBufferMgr->getBuffer( &m_Buf2.pIOBuffer, - m_uiBufferSize, m_uiBufferSize))) - { - goto Exit; - } - - m_bLoggingOff = FALSE; - m_pCurrentBuf = &m_Buf1; - m_pCurrentBuf->uiRflBufBytes = 0; - - // Set the RFL directory and prefix if necessary. - - if (RC_BAD( rc = setRflDir( pszRflDir))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Wait for the writes of a buffer to finish. This routine assumes - that the m_hBufMutex is locked when coming in. It will ALWAYS - unlock the mutex before exiting. -*********************************************************************/ -RCODE F_Rfl::waitForWrites( - RFL_BUFFER * pBuffer, - FLMBOOL bIsWriter - ) -{ - RCODE rc = FERR_OK; - RCODE TempRc; - RFL_WAITER Waiter; - FLMBOOL bMutexLocked = TRUE; - - // Put self on the wait queue for the buffer. - - Waiter.uiThreadId = f_threadId(); - Waiter.bIsWriter = bIsWriter; - Waiter.hESem = F_SEM_NULL; - if (RC_BAD( rc = f_semCreate( &Waiter.hESem))) - { - goto Exit; - } - - // Note: rc better be changed to success or write error - // by the process that signals us. - - rc = RC_SET( FERR_FAILURE); - Waiter.pRc = &rc; - Waiter.pNext = NULL; - if (pBuffer->pLastWaiter) - { - pBuffer->pLastWaiter->pNext = &Waiter; - } - else - { - pBuffer->pFirstWaiter = &Waiter; - } - pBuffer->pLastWaiter = &Waiter; - f_mutexUnlock( m_hBufMutex); - bMutexLocked = FALSE; - - // Now just wait to be signaled. - - if (RC_BAD( TempRc = f_semWait( Waiter.hESem, F_SEM_WAITFOREVER))) - { -#ifdef FLM_NLM - EnterDebugger(); -#else - flmAssert( 0); -#endif - rc = TempRc; - } - else - { - - // Process that signaled us better set the rc to something - // besides FERR_FAILURE. - - if (rc == FERR_FAILURE) - { -#ifdef FLM_NLM - EnterDebugger(); -#else - flmAssert( 0); -#endif - } - } - -Exit: - - if( Waiter.hESem != F_SEM_NULL) - { - f_semDestroy( &Waiter.hESem); - } - - if (bMutexLocked) - { - f_mutexUnlock( m_hBufMutex); - } - return( rc); -} - -/******************************************************************** -Desc: If a commit is in progress, wait for it to finish. -*********************************************************************/ -RCODE F_Rfl::waitForCommit( void) -{ - RCODE rc = FERR_OK; - FLMBOOL bMutexLocked = FALSE; - - // NOTE: If m_pCommitBuf is NULL it cannot be set to something - // non-NULL except by this thread when this thread ends the - // transaction. So, there is no need to lock the mutex and - // re-check if it is NULL. - - if (m_pCommitBuf) - { - f_mutexLock( m_hBufMutex); - bMutexLocked = TRUE; - - // Check m_pCommitBuf again after locking mutex - may have - // finished. - - if (m_pCommitBuf) - { - - // waitForWrites will unlock the mutex. - - bMutexLocked = FALSE; - rc = waitForWrites( m_pCommitBuf, FALSE); - } - } - - if (bMutexLocked) - { - f_mutexUnlock( m_hBufMutex); - } - return( rc); -} - -/******************************************************************** -Desc: Write out the header information for an RFL file. -*********************************************************************/ -RCODE F_Rfl::writeHeader( - FLMUINT uiFileNum, - FLMUINT uiEof, - FLMBYTE * pucSerialNum, - FLMBYTE * pucNextSerialNum, - FLMBOOL bKeepSignature) -{ - RCODE rc = FERR_OK; - FLMBYTE ucBuf [512]; - FLMUINT uiBytesWritten; - - flmAssert( m_pFile); - flmAssert( m_pFileHdl); - - f_memset( ucBuf, 0, sizeof( ucBuf)); - f_memcpy( &ucBuf [RFL_NAME_POS], RFL_NAME, RFL_NAME_LEN); - f_memcpy( &ucBuf [RFL_VERSION_POS], RFL_VERSION, RFL_VERSION_LEN); - UD2FBA( (FLMUINT32)uiFileNum, &ucBuf [RFL_FILE_NUMBER_POS]); - UD2FBA( (FLMUINT32)uiEof, &ucBuf [RFL_EOF_POS]); - - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - f_memcpy( &ucBuf [RFL_DB_SERIAL_NUM_POS], - &m_pFile->ucLastCommittedLogHdr [LOG_DB_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - f_memcpy( &ucBuf [RFL_SERIAL_NUM_POS], pucSerialNum, - F_SERIAL_NUM_SIZE); - f_memcpy( &ucBuf [RFL_NEXT_FILE_SERIAL_NUM_POS], pucNextSerialNum, - F_SERIAL_NUM_SIZE); - f_strcpy( (char *)&ucBuf [RFL_KEEP_SIGNATURE_POS], - ((bKeepSignature) - ? RFL_KEEP_SIGNATURE - : RFL_NOKEEP_SIGNATURE)); - } - - // Write out the header - - if (RC_BAD( rc = m_pFileHdl->SectorWrite( 0L, 512, - ucBuf, sizeof( ucBuf), - NULL, &uiBytesWritten))) - { - // Remap disk full error - - if (rc == FERR_IO_DISK_FULL) - { - rc = RC_SET( FERR_RFL_DEVICE_FULL); - m_bRflVolumeFull = TRUE; - } - m_bRflVolumeOk = FALSE; - goto Exit; - } - - // Flush the file handle to ensure it is forced to disk. - - if (RC_BAD( rc = m_pFileHdl->Flush())) - { - - // Remap disk full error - - if (rc == FERR_IO_DISK_FULL) - { - rc = RC_SET( FERR_RFL_DEVICE_FULL); - m_bRflVolumeFull = TRUE; - } - m_bRflVolumeOk = FALSE; - goto Exit; - } - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Verifies the header of an RFL file. -*********************************************************************/ -RCODE F_Rfl::verifyHeader( - FLMBYTE * pucHeader, - FLMUINT uiFileNum, - FLMBYTE * pucSerialNum - ) -{ - RCODE rc = FERR_OK; - - flmAssert( m_pFile); - - - // Check the RFL name and version number - - if (f_memcmp( &pucHeader [RFL_NAME_POS], RFL_NAME, - RFL_NAME_LEN) != 0) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - if (f_memcmp( &pucHeader [RFL_VERSION_POS], RFL_VERSION, - RFL_VERSION_LEN) != 0) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - - // Verify the database serial number - - if (f_memcmp( &pucHeader [RFL_DB_SERIAL_NUM_POS], - &m_pFile->ucLastCommittedLogHdr [LOG_DB_SERIAL_NUM], - F_SERIAL_NUM_SIZE) != 0) - { - rc = RC_SET( FERR_BAD_RFL_DB_SERIAL_NUM); - goto Exit; - } - - // Verify the serial number that is expected to be on the - // RFL file. If pucSerialNum is NULL, we will not verify - // it. This is generally only done during recovery or restore - // when we are reading through multiple RFL files and we need - // to verify their serial numbers. - - if (pucSerialNum && - f_memcmp( &pucHeader [RFL_SERIAL_NUM_POS], - pucSerialNum, F_SERIAL_NUM_SIZE) != 0) - { - rc = RC_SET( FERR_BAD_RFL_SERIAL_NUM); - goto Exit; - } - - // Verify the file number. - - if (uiFileNum != (FLMUINT)FB2UD( &pucHeader [RFL_FILE_NUMBER_POS])) - { - rc = RC_SET( FERR_BAD_RFL_FILE_NUMBER); - goto Exit; - } - - // Save serial numbers from the header. - - f_memcpy( m_ucCurrSerialNum, &pucHeader [RFL_SERIAL_NUM_POS], - F_SERIAL_NUM_SIZE); - f_memcpy( m_ucNextSerialNum, &pucHeader [RFL_NEXT_FILE_SERIAL_NUM_POS], - F_SERIAL_NUM_SIZE); - } - - // Save some things from the header. - - m_uiFileEOF = (FLMUINT)FB2UD( &pucHeader [RFL_EOF_POS]); - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Opens an RFL file. Verifies the serial number for 4.3 dbs. -*********************************************************************/ -RCODE F_Rfl::openFile( - FLMUINT uiFileNum, - FLMBYTE * pucSerialNum - ) -{ - RCODE rc = FERR_OK; - char szRflFileName [F_PATH_MAX_SIZE]; - FLMBYTE ucBuf [512]; - FLMUINT uiBytesRead; - - flmAssert( m_pFile); - - // If we have a file open and it is not the file number - // passed in, close it. - - if (m_pFileHdl) - { - if (m_pCurrentBuf->uiCurrFileNum != uiFileNum) - { - if (RC_BAD( rc = waitForCommit())) - { - goto Exit; - } - closeFile(); - } - else - { - goto Exit; // Will return FERR_OK - } - } - else - { - - // Should not be able to be in the middle of a commit - // if we don't have a file open! - - flmAssert( !m_pCommitBuf); - } - - // Generate the log file name. - - if (RC_BAD( rc = getFullRflFileName( uiFileNum, szRflFileName))) - { - goto Exit; - } - - // Open the file. - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( szRflFileName, - F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, - 512, &m_pFileHdl))) - { - goto Exit; - } - - // Read the header. - - if (RC_BAD( rc = m_pFileHdl->SectorRead( 0, 512, ucBuf, - &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - rc = RC_SET( FERR_NOT_RFL); - } - else - { - m_bRflVolumeOk = FALSE; - } - goto Exit; - } - - // If there is not enough data in the buffer, it is not an - // RFL file. - - if (uiBytesRead < 512) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - - // Verify the header information - - if (RC_BAD( rc = verifyHeader( ucBuf, uiFileNum, pucSerialNum))) - { - goto Exit; - } - - m_pCurrentBuf->uiRflBufBytes = 0; - m_pCurrentBuf->uiRflFileOffset = 0; - m_pCurrentBuf->uiCurrFileNum = uiFileNum; -Exit: - if (RC_BAD( rc)) - { - waitForCommit(); - closeFile(); - } - return( rc); -} - -/******************************************************************** -Desc: Creates a new roll forward log file. -*********************************************************************/ -RCODE F_Rfl::createFile( - FLMUINT uiFileNum, - FLMBYTE * pucSerialNum, - FLMBYTE * pucNextSerialNum, - FLMBOOL bKeepSignature) -{ - RCODE rc = FERR_OK; - char szRflFileName [F_PATH_MAX_SIZE]; - - flmAssert( m_pFile); - - // Better not be trying to create the current file - - flmAssert( uiFileNum != m_pCurrentBuf->uiCurrFileNum); - - // If we have a file open close it. - - if (RC_BAD( rc = waitForCommit())) - { - goto Exit; - } - - closeFile(); - - // Generate the log file name. - - if (RC_BAD( rc = getFullRflFileName( uiFileNum, szRflFileName))) - { - goto Exit; - } - - // Delete the file if it already exists - don't care - // about return code here - - (void)gv_FlmSysData.pFileSystem->Delete( szRflFileName); - - // If DB is 4.3 or greater and we are in the same directory as - // our database files, see if we need to create the - // subdirectory. Otherwise, the RFL directory should already - // have been created. If the directory already exists, it is - // OK - we only try this the first time after setRflDir is - // called - to either verify that the directory exists, or if - // it doesn't, to create it. - - if (m_bCreateRflDir) - { - - // If it already exists, don't attempt to create it. - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->Exists( m_szRflDir))) - { - if (rc != FERR_IO_PATH_NOT_FOUND && rc != FERR_IO_INVALID_PATH) - { - goto Exit; - } - else - { - if (RC_BAD( rc = - gv_FlmSysData.pFileSystem->CreateDir( m_szRflDir))) - { - goto Exit; - } - } - } - m_bCreateRflDir = FALSE; - } - - // Create the file - - if (RC_BAD( rc = gv_FlmSysData.pFileSystem->CreateBlockFile( szRflFileName, - F_IO_RDWR | F_IO_EXCL | F_IO_SH_DENYNONE | F_IO_DIRECT, - 512, &m_pFileHdl))) - { - goto Exit; - } - - // Initialize the header. - - if (RC_BAD( rc = writeHeader( uiFileNum, 0, - pucSerialNum, pucNextSerialNum, bKeepSignature))) - { - goto Exit; - } - - m_pCurrentBuf->uiRflBufBytes = 0; - m_pCurrentBuf->uiRflFileOffset = 512; - m_pCurrentBuf->uiCurrFileNum = uiFileNum; -Exit: - - // Close the RFL log file AND delete it if we were not successful. - - if (RC_BAD( rc)) - { - closeFile(); - (void)gv_FlmSysData.pFileSystem->Delete( szRflFileName); - } - return( rc); -} - -/******************************************************************** -Desc: Copy last partial sector of last buffer written (or to be - written) into a new buffer. -*********************************************************************/ -void F_Rfl::copyLastSector( - RFL_BUFFER * pBuffer, - FLMBYTE * pucOldBuffer, - FLMBYTE * pucNewBuffer, - FLMUINT uiCurrPacketLen, - FLMBOOL bStartingNewFile) -{ - FLMUINT uiOldBufBytes = pBuffer->uiRflBufBytes; - - // If we will be starting a new file, no need to keep any of - // what is in the buffer. Only the current packet needs to - // be copied - at the beginning of the buffer. - - // OTHERWISE: - - // If there are fewer than 512 bytes in the buffer, we simply - // keep them and keep appending to the buffer the next time - // we output stuff. The beginning of the buffer must ALWAYS be - // a 512 byte boundary in the file, because we want to always - // do our writing on 512 byte boundaries - because of direct IO. - - // If the number of bytes in the buffer is over 512 and it is - // evenly divisible by 512, we can clear the buffer. Otherwise, - // we want to move the extra bytes over the last 512 byte boundary - // down to the beginning of the buffer and adjust the buffer bytes - // to reflect just these left-over bytes. - - if (bStartingNewFile) - { - pBuffer->uiRflBufBytes = 0; - pBuffer->uiRflFileOffset = 512; - } - else if (pBuffer->uiRflBufBytes >= 512) - { - - // See if the number of bytes in the buffer is an exact - // multiple of 512. - - if (pBuffer->uiRflBufBytes & 511) // Not exact multiple - { - - // Round m_uiRflBufBytes down to next 512 byte boundary - - FLMUINT ui512Offset = ROUND_DOWN_TO_NEAREST_512( - pBuffer->uiRflBufBytes); - - // Move all bytes above the nearest 512 byte boundary - // down to the beginning of the buffer and adjust - // pBuffer->uiRflBufBytes and - // pBuffer->uiRflFileOffset accordingly. - - f_memcpy( pucNewBuffer, &pucOldBuffer[ui512Offset], - pBuffer->uiRflBufBytes - ui512Offset); - pBuffer->uiRflBufBytes -= ui512Offset; - pBuffer->uiRflFileOffset += ui512Offset; - } - else - { - pBuffer->uiRflFileOffset += pBuffer->uiRflBufBytes; - pBuffer->uiRflBufBytes = 0; - } - } - else if (pucNewBuffer != pucOldBuffer) - { - f_memcpy( pucNewBuffer, pucOldBuffer, pBuffer->uiRflBufBytes); - } - if (uiCurrPacketLen) - { - flmAssert( uiOldBufBytes + uiCurrPacketLen <= m_uiBufferSize); - f_memmove( &pucNewBuffer [pBuffer->uiRflBufBytes], - &pucOldBuffer [uiOldBufBytes], - uiCurrPacketLen); - } -} - -/******************************************************************** -Desc: Flush the RFL data from the buffer to disk. -*********************************************************************/ -RCODE F_Rfl::flush( - RFL_BUFFER * pBuffer, - FLMBOOL bFinalWrite, - FLMUINT uiCurrPacketLen, - FLMBOOL bStartingNewFile - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesWritten; - F_IOBuffer * pNewBuffer; - F_IOBuffer * pAsyncBuf = NULL; - FLMBYTE * pucOldBuffer; - FLMUINT uiFileOffset; - FLMUINT uiBufBytes; - - if (m_pFileHdl && pBuffer->uiRflBufBytes) - { - - // Must wait for stuff in committing buffer, if any, before - // going ahead here. - - if (pBuffer != m_pCommitBuf) - { - if (RC_BAD( rc = waitForCommit())) - { - goto Exit; - } - } - - if (m_uiRflWriteBufs > 1 && m_pFileHdl->CanDoAsync()) - { - pAsyncBuf = pBuffer->pIOBuffer; - } - - if ((FLMUINT)(-1) - pBuffer->uiRflFileOffset <= - pBuffer->uiRflBufBytes) - { - rc = RC_SET( FERR_DB_FULL); - goto Exit; - } - - pucOldBuffer = pBuffer->pIOBuffer->m_pucBuffer; - uiFileOffset = pBuffer->uiRflFileOffset; - uiBufBytes = pBuffer->uiRflBufBytes; - if (m_uiRflWriteBufs > 1) - { - if( RC_BAD( rc = pBuffer->pBufferMgr->getBuffer( - &pNewBuffer, - m_uiBufferSize, m_uiBufferSize))) - { - goto Exit; - } - - // No need to copy data if it is the final write, - // because it won't be reused anyway - the data for - // the next transaction has already been copied to - // another buffer. - - if (!bFinalWrite) - { - copyLastSector( pBuffer, pucOldBuffer, pNewBuffer->m_pucBuffer, - uiCurrPacketLen, bStartingNewFile); - } - } - - rc = m_pFileHdl->SectorWrite( uiFileOffset, uiBufBytes, - pucOldBuffer, - m_uiBufferSize, pAsyncBuf, - &uiBytesWritten, FALSE); - if( m_uiRflWriteBufs == 1) - { - - // We are counting on the fact that the write completed. - // When we only have one buffer, we cannot do async - // writes. - - flmAssert( !pAsyncBuf); - if (RC_OK( rc) && !bFinalWrite) - { - copyLastSector( pBuffer, pucOldBuffer, pucOldBuffer, - uiCurrPacketLen, bStartingNewFile); - } - - // DO NOT call notifyComplete - that would put - // pBuffer->pIOBuffer into the avail list, and we - // don't want that. We simply want to keep - // reusing it. - - } - else - { - - // No need to call copyLastSector, because it was called - // above before calling SectorWrite. The part of the - // old buffer that needs to be transferred to the new - // buffer has already been transferred. - - if (!pAsyncBuf) - { - pBuffer->pIOBuffer->notifyComplete( rc); - } - pBuffer->pIOBuffer = pNewBuffer; - } - - if (RC_BAD( rc)) - { - // Remap disk full error - - if (rc == FERR_IO_DISK_FULL) - { - rc = RC_SET( FERR_RFL_DEVICE_FULL); - m_bRflVolumeFull = TRUE; - } - m_bRflVolumeOk = FALSE; - goto Exit; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Switch buffers. This routine assumes the m_hBufMutex is locked. -*********************************************************************/ -void F_Rfl::switchBuffers( void) -{ - RFL_BUFFER * pOldBuffer = m_pCurrentBuf; - - if (m_pCurrentBuf == &m_Buf1) - { - m_pCurrentBuf = &m_Buf2; - } - else - { - m_pCurrentBuf = &m_Buf1; - } - m_pCurrentBuf->bTransInProgress = pOldBuffer->bTransInProgress; - m_pCurrentBuf->uiCurrFileNum = pOldBuffer->uiCurrFileNum; - m_pCurrentBuf->uiRflBufBytes = pOldBuffer->uiRflBufBytes; - m_pCurrentBuf->uiRflFileOffset = pOldBuffer->uiRflFileOffset; - if (pOldBuffer->uiRflBufBytes) - { - copyLastSector( m_pCurrentBuf, pOldBuffer->pIOBuffer->m_pucBuffer, - m_pCurrentBuf->pIOBuffer->m_pucBuffer, 0, FALSE); - } -} - -/******************************************************************** -Desc: Wait for all RFL transaction writes to be finished. The caller - has the write lock on the database, which will prevent further - writes to the RFL. -*********************************************************************/ -FLMBOOL F_Rfl::seeIfRflWritesDone( - FLMBOOL bForceWait - ) -{ - FLMBOOL bWritesDone; - - f_mutexLock( m_hBufMutex); - - if (!bForceWait) - { - bWritesDone = (FLMBOOL)((m_pCurrentBuf->pFirstWaiter || m_pCommitBuf) - ? FALSE - : TRUE); - f_mutexUnlock( m_hBufMutex); - } - else - { - - // If the current buffer has a waiter, add self to that list - // to wait, because it will be notified after the commit buffer - // has been notified. Otherwise, if there is a commit in - // progress, add self to that list to wait. - - if (m_pCurrentBuf->pFirstWaiter) - { - - // If bTransInProgress is TRUE and m_pCommitBuf is NULL - // then this thread is the current transaction, and - // nobody is going to wake up the first waiter until we - // are done! Hence, we must wake him up. - - if (!m_pCommitBuf) - { - - // If m_pCommitBuf is NULL, this could only be possible if - // there is a transaction in progress. Otherwise, there - // would not have been a pFirstWaiter, because when - // the commit buffer finishes writing, if there is a - // waiter, it will set commitbuf=currentbuf if there - // is no transaction active. - - flmAssert( m_pCurrentBuf->bTransInProgress); - - m_pCommitBuf = m_pCurrentBuf; - switchBuffers(); - wakeUpWaiter( FERR_OK, TRUE); - (void)waitForWrites( m_pCommitBuf, FALSE); - } - else - { - FLMBOOL bSaveTransInProgress = m_pCurrentBuf->bTransInProgress; - - // Must set bTransInProgress to FALSE so that when the writer - // of m_pCommitBuf finishes, it will signal the first waiter - // on m_pCurrentBuf. If we don't do this, m_pCommitBuf will - // simply be set to NULL, and the first waiter will never - // be woke up. - - m_pCurrentBuf->bTransInProgress = FALSE; - (void)waitForWrites( m_pCurrentBuf, FALSE); - - // It is OK to restore the trans in progress flag to what it - // was before, because whoever called this routine has a lock - // on the database, and it is his trans-in-progress state - // that should be preserved. No other thread will have been - // able to change that state because the database is locked. - - f_mutexLock( m_hBufMutex); - m_pCurrentBuf->bTransInProgress = bSaveTransInProgress; - f_mutexUnlock( m_hBufMutex); - } - } - else if (m_pCommitBuf) - { - (void)waitForWrites( m_pCommitBuf, FALSE); - } - else - { - f_mutexUnlock( m_hBufMutex); - } - bWritesDone = TRUE; - } - return( bWritesDone); -} - -/******************************************************************** -Desc: Wake up the first thread that is waiting on the commit buffer. -*********************************************************************/ -void F_Rfl::wakeUpWaiter( - RCODE rc, - FLMBOOL bIsWriter // Only used for debug - ) -{ - F_SEM hESem; - -#ifndef FLM_DEBUG - F_UNREFERENCED_PARM( bIsWriter); -#else - if (bIsWriter) - { - flmAssert( m_pCommitBuf->pFirstWaiter->bIsWriter); - } - else - { - flmAssert( !m_pCommitBuf->pFirstWaiter->bIsWriter); - } -#endif - - *(m_pCommitBuf->pFirstWaiter->pRc) = rc; - hESem = m_pCommitBuf->pFirstWaiter->hESem; - if ((m_pCommitBuf->pFirstWaiter = - m_pCommitBuf->pFirstWaiter->pNext) == NULL) - { - m_pCommitBuf->pLastWaiter = NULL; - } - f_semSignal( hESem); -} - -/******************************************************************** -Desc: Wait for the transaction writes to be finished. -*********************************************************************/ -RCODE F_Rfl::completeTransWrites( - FDB * pDb, - FLMBOOL bCommitting, - FLMBOOL bOkToUnlock - ) -{ - RCODE rc = FERR_OK; - RCODE tmpRc; - FLMBOOL bMutexLocked = FALSE; - FLMBOOL bNotifyWaiters = FALSE; - FLMBOOL bDbUnlocked = FALSE; - DB_STATS * pDbStats = NULL; - F_TMSTAMP StartTime; - - f_mutexLock( m_hBufMutex); - bMutexLocked = TRUE; - m_pCurrentBuf->bTransInProgress = FALSE; - - flmAssert( pDb->uiFlags & FDB_HAS_WRITE_LOCK); - - // If we are not logging, we are probably recovering or restoring - // the database. All we need to do in this case is write out the - // log header. - - if (pDb->uiFlags & FDB_REPLAYING_RFL) - { - if (pDb->bHadUpdOper && m_pCurrentBuf->bOkToWriteHdrs) - { - f_mutexUnlock( m_hBufMutex); - bMutexLocked = FALSE; - if (RC_BAD( rc = flmWriteLogHdr( pDb->pDbStats, - pDb->pSFileHdl, pDb->pFile, - m_pCurrentBuf->ucLogHdr, - m_pCurrentBuf->ucCPHdr, FALSE))) - { - flmSetMustCloseFlags( pDb->pFile, rc, FALSE); - } - } - goto Exit; - } - - // Handle empty transactions differently. - // These transactions should not do any writing and do not need to - // wait for all writes to complete, unless the bOkToUnlock flag - // is set to FALSE. In that case they must wait for all writes - // to complete before unlocking. - - if (!pDb->bHadUpdOper) - { - - // If the current buffer has a waiter, add self to that list - // to wait, because it will be notified after the commit buffer - // has been notified. Otherwise, if there is a commit in - // progress, add self to that list to wait. - - if (m_pCurrentBuf->pFirstWaiter) - { - - // If m_pCommitBuf is NULL then nobody is going to wake up - // the first waiter - we must do it. - - if (!m_pCommitBuf) - { - if (bOkToUnlock) - { - flmUnlinkDbFromTrans( pDb, bCommitting); - bDbUnlocked = TRUE; - } - m_pCommitBuf = m_pCurrentBuf; - switchBuffers(); - wakeUpWaiter( FERR_OK, TRUE); - - if (!bOkToUnlock) - { - bMutexLocked = FALSE; - (void)waitForWrites( m_pCommitBuf, FALSE); - } - } - else if (!bOkToUnlock) - { - bMutexLocked = FALSE; - (void)waitForWrites( m_pCurrentBuf, FALSE); - } - } - else if (m_pCommitBuf) - { - if (!bOkToUnlock) - { - bMutexLocked = FALSE; - rc = waitForWrites( m_pCommitBuf, FALSE); - } - } - goto Exit; - } - - // If there is a transaction committing, put self into - // the wait list on the current buffer. When the committer - // finishes, he will wake up the first thread in the list - // and that thread will commit the buffer. - - if (m_pCommitBuf) - { - FLMBOOL bIsWriter; - - // Another thread has to be doing the writes to m_pCommitBuf, - // which means that m_pCurrentBuf better not be equal to - // m_pCommitBuf. - - flmAssert( m_pCommitBuf != m_pCurrentBuf); - - // If there are no waiters, we are the first one, so when - // we get signaled, we should proceed and do the write. - - bIsWriter = m_pCurrentBuf->pFirstWaiter ? FALSE : TRUE; - if (bOkToUnlock) - { - flmUnlinkDbFromTrans( pDb, bCommitting); - bDbUnlocked = TRUE; - } - bMutexLocked = FALSE; - rc = waitForWrites( m_pCurrentBuf, bIsWriter); - - // If we were the first one in the queue, we must now - // do the write. - - if (!bIsWriter) - { - goto Exit; - } - - // First one in the queue, fall through to do the write. - - // The thread that woke me up better have set m_pCommitBuf - // See below. - - flmAssert( m_pCommitBuf); - } - else if (m_pCurrentBuf->pFirstWaiter) - { - - // Another thread is ready to commit the next set of - // buffers, but just needs to be woke up. - - if (bOkToUnlock) - { - flmUnlinkDbFromTrans( pDb, bCommitting); - bDbUnlocked = TRUE; - } - - // Need to set things up for that first waiter and get him - // going. - - m_pCommitBuf = m_pCurrentBuf; - switchBuffers(); - wakeUpWaiter( rc, TRUE); - - // Wait for the write to be completed. - - bMutexLocked = FALSE; - rc = waitForWrites( m_pCommitBuf, FALSE); - goto Exit; - } - else - { - m_pCommitBuf = m_pCurrentBuf; - switchBuffers(); - if (bOkToUnlock) - { - flmUnlinkDbFromTrans( pDb, bCommitting); - bDbUnlocked = TRUE; - } - f_mutexUnlock( m_hBufMutex); - bMutexLocked = FALSE; - } - - // NOTE: From this point on we use tmpRc because we don't want to - // lose the rc that may have been set above in the call to - // waitForWrites - - // At this point the mutex better not be locked. - - flmAssert( !bMutexLocked); - bNotifyWaiters = TRUE; - - if( (pDbStats = pDb->pDbStats) != NULL) - { - f_timeGetTimeStamp( &StartTime); - } - - // Must write out whatever we have in the commit buffer before - // unlocking the database. - - if (RC_BAD( tmpRc = flush( m_pCommitBuf, TRUE))) - { - if (RC_OK( rc)) - { - rc = tmpRc; - } - goto Exit; - } - - // Wait for any pending IO off of the log buffer - - if (RC_BAD( tmpRc = m_pCommitBuf->pBufferMgr->waitForAllPendingIO())) - { - if (RC_OK( rc)) - { - rc = tmpRc; - } - goto Exit; - } - - // Force the RFL writes to disk if necessary. - // NOTE: It is possible for m_pFileHdl to be NULL at this point if - // there were no operations actually logged. This happens in - // FlmDbUpgrade (see flconvrt.cpp). Even though nothing was logged - // the transaction is not an empty transaction, because it still needs - // to write out the log header. - - if (m_pFileHdl) - { - if (RC_BAD( tmpRc = m_pFileHdl->Flush())) - { - - // Remap disk full error - - if (tmpRc == FERR_IO_DISK_FULL) - { - rc = RC_SET( FERR_RFL_DEVICE_FULL); - m_bRflVolumeFull = TRUE; - } - else if (RC_OK( rc)) - { - rc = tmpRc; - } - m_bRflVolumeOk = FALSE; - goto Exit; - } - } - - // Write the log header - - if (m_pCommitBuf->bOkToWriteHdrs) - { - if (RC_BAD( tmpRc = flmWriteLogHdr( pDb->pDbStats, - pDb->pSFileHdl, pDb->pFile, - m_pCommitBuf->ucLogHdr, - m_pCommitBuf->ucCPHdr, FALSE))) - { - if (RC_OK( rc)) - { - rc = tmpRc; - } - flmSetMustCloseFlags( pDb->pFile, tmpRc, FALSE); - goto Exit; - } - } - -Exit: - - if (!bDbUnlocked && bOkToUnlock) - { - flmUnlinkDbFromTrans( pDb, bCommitting); - } - - if (bNotifyWaiters) - { - FLMUINT uiNumFinished = 1; // For self - - flmAssert( !bMutexLocked); - f_mutexLock( m_hBufMutex); - bMutexLocked = TRUE; - - // Wake up any waiters - - while (m_pCommitBuf->pFirstWaiter) - { - uiNumFinished++; - wakeUpWaiter( rc, FALSE); - } - - // If there are waiters on the current buffer, the first one - // should be woke up so it can start the next set of writes. - - if (m_pCurrentBuf->pFirstWaiter && !m_pCurrentBuf->bTransInProgress) - { - flmAssert( m_pCurrentBuf != m_pCommitBuf); - m_pCommitBuf = m_pCurrentBuf; - switchBuffers(); - wakeUpWaiter( rc, TRUE); - } - else - { - m_pCommitBuf = NULL; - } - if (pDbStats) - { - flmAddElapTime( &StartTime, - &pDbStats->UpdateTransStats.GroupCompletes.ui64ElapMilli); - pDbStats->UpdateTransStats.GroupCompletes.ui64Count++; - pDbStats->bHaveStats = TRUE; - pDbStats->UpdateTransStats.ui64GroupFinished += uiNumFinished; - } - } - - if (bMutexLocked) - { - f_mutexUnlock( m_hBufMutex); - } - return( rc); -} - -/******************************************************************** -Desc: Calculate the checksum for a packet. -*********************************************************************/ -FLMBYTE RflCalcChecksum( - const FLMBYTE * pucPacket, - FLMUINT uiPacketBodyLen) -{ - FLMUINT uiBytesToChecksum; - FLMUINT uiChecksum = 0; - FLMBYTE ucTmp; - const FLMBYTE * pucStart; - const FLMBYTE * pucEnd; - const FLMBYTE * pucSectionEnd; - const FLMBYTE * pucCur; - - // Checksum is calculated for every byte in the packet that - // comes after the checksum byte. - - pucStart = &pucPacket[ RFL_PACKET_CHECKSUM_OFFSET + 1]; - uiBytesToChecksum = (FLMUINT)(uiPacketBodyLen + - RFL_PACKET_OVERHEAD - - (RFL_PACKET_CHECKSUM_OFFSET + 1)); - - pucCur = pucStart; - pucEnd = pucStart + uiBytesToChecksum; - -#ifdef FLM_64BIT - pucSectionEnd = pucStart + (sizeof( FLMUINT) - ((FLMUINT)pucStart & 0x7)); -#else - pucSectionEnd = pucStart + (sizeof( FLMUINT) - ((FLMUINT)pucStart & 0x3)); -#endif - - if( pucSectionEnd > pucEnd) - { - pucSectionEnd = pucEnd; - } - - while( pucCur < pucSectionEnd) - { - uiChecksum = (uiChecksum << 8) + *pucCur++; - } - -#ifdef FLM_64BIT - pucSectionEnd = (FLMBYTE *)((FLMUINT)pucEnd & 0xFFFFFFFFFFFFFFF8); -#else - pucSectionEnd = (FLMBYTE *)((FLMUINT)pucEnd & 0xFFFFFFFC); -#endif - - while( pucCur < pucSectionEnd) - { - uiChecksum ^= *((FLMUINT *)pucCur); - pucCur += sizeof( FLMUINT); - } - - while( pucCur < pucEnd) - { - uiChecksum ^= *pucCur++; - } - - ucTmp = (FLMBYTE)uiChecksum; - - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; - - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; - -#ifdef FLM_64BIT - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; - - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; - - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; - - uiChecksum >>= 8; - ucTmp ^= (FLMBYTE)uiChecksum; -#endif - - ucTmp ^= (FLMBYTE)(uiChecksum >> 8); - uiChecksum = ucTmp; - - if( (uiChecksum = ucTmp) == 0) - { - uiChecksum = 1; - } - - return( (FLMBYTE)uiChecksum); -} - -/******************************************************************** -Desc: Flush all completed packets out of the RFL buffer, and shift - the new partial packet down. This guarantees that there is - now room in the buffer for the maximum packet size. -*********************************************************************/ -RCODE F_Rfl::shiftPacketsDown( - FLMUINT uiCurrPacketLen, - FLMBOOL bStartingNewFile - ) -{ - RCODE rc = FERR_OK; - - // The call to flush will move whatever needs to be moved from - // the current buffer into a new buffer if multiple buffers are - // being used. If only one buffer is being used, it will move - // the part of the packet that needs to be moved down to the - // beginning of the buffer - AFTER writing out the buffer. - - if (RC_BAD( rc = flush( m_pCurrentBuf, FALSE, - uiCurrPacketLen, bStartingNewFile))) - { - goto Exit; - } - - // NOTE: If multiple buffers are being used, whatever was moved - // to the new buffer has not yet been written out - - if (bStartingNewFile) - { - if( RC_BAD( rc = waitPendingWrites())) - { - goto Exit; - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Determine if we should start a new file. If we are over the - low limit, and the bDoNewIfOverLowLimit flag is set, we - will start a new log file. Or, if this packet size would - put us over the upper limit, we will start a new log file. -*********************************************************************/ -RCODE F_Rfl::seeIfNeedNewFile( - FLMUINT uiPacketLen, - FLMBOOL bDoNewIfOverLowLimit - ) -{ - RCODE rc = FERR_OK; - FLMBYTE ucNextSerialNum [F_SERIAL_NUM_SIZE]; - - flmAssert( m_pFile); - - // If the keep files flag is FALSE, we won't start - // a new file. NOTE: This should ALWAYS be false - // for pre 4.3 databases. - - if (!m_bKeepRflFiles) - { - goto Exit; // Should return FERR_OK; - } - - // VERY IMPORTANT NOTE: It is preferrable that we keep transactions - // entirely contained in the same RFL file if at all possible. Note - // that it is NOT a hard and fast requirement. The system will work - // just fine if we don't. However, it would be nice if RFL files - // always ended with a commit or abort packet. This preferences is - // due to what happens after a restore operation. After a restore - // operation, we always need to start a new RFL file, but if possible, - // we would like that new RFL file to be the next one in the sequence - // after the last RFL file that was restored. We can only do this if - // we were able to restore EVERY transaction that was in the last - // restored RFL file - which we can only do if the last restored RFL - // file ended with a commit or abort packet. - // To accomplish this end, we try to roll to new files on the first - // transaction begin packet that occurs after we have exceeded our - // low threshold - which is why bDoNewIfOverLowLimit is only set to - // TRUE on transaction begin packets. It is set to FALSE on other - // packets so that we will continue logging the transaction in the - // same file that we started the transaction in - if possible. The - // only thing that will cause a non-transaction-begin packet to roll - // to a new file is if we would exceed the high limit. - - if ((bDoNewIfOverLowLimit && - m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes >= - m_uiRflMinFileSize) || - (m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes + - uiPacketLen >= m_uiRflMaxFileSize)) - { - FLMUINT uiCurrFileEOF = m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes; - - // Shift the current packet to the beginning of the buffer. - // Any packets in the buffer before that one will be written - // out to the current file. - - if (RC_BAD( rc = shiftPacketsDown( uiPacketLen, TRUE))) - { - goto Exit; - } - - // Update the header of the current file and close it. - - if (RC_BAD( rc = writeHeader( m_pCurrentBuf->uiCurrFileNum, - uiCurrFileEOF, - m_ucCurrSerialNum, m_ucNextSerialNum, TRUE))) - { - goto Exit; - } - - // Truncate the file. - - if (!ON_512_BYTE_BOUNDARY( uiCurrFileEOF)) - { - uiCurrFileEOF = ROUND_DOWN_TO_NEAREST_512( uiCurrFileEOF) + 512; - } - if (RC_BAD( rc = m_pFileHdl->Truncate( uiCurrFileEOF))) - { - goto Exit; - } - - // Close the file handle. - - m_pFileHdl->Close(); - m_pFileHdl->Release(); - m_pFileHdl = NULL; - - // Get the next serial number that will be used for the RFL - // file after this one. - - if (RC_BAD( rc = f_createSerialNumber( ucNextSerialNum))) - { - goto Exit; - } - - // Create next file in the sequence. - - // Use the next serial number stored in the FDB's log header - // for the serial number on this RFL file. Use the serial - // number we just generated as the next RFL serial number. - - if (RC_BAD( rc = createFile( m_pCurrentBuf->uiCurrFileNum + 1, - m_ucNextSerialNum, ucNextSerialNum, - TRUE))) - { - goto Exit; - } - - // Move the next serial number to the current serial number - // and the serial number we generated above into the next - // serial number. - - f_memcpy( m_ucCurrSerialNum, m_ucNextSerialNum, F_SERIAL_NUM_SIZE); - f_memcpy( m_ucNextSerialNum, ucNextSerialNum, F_SERIAL_NUM_SIZE); - } - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Finish the current RFL file - set up so that next - transaction will begin a new RFL file. -*********************************************************************/ -RCODE F_Rfl::finishCurrFile( - FDB * pDb, - FLMBOOL bNewKeepState - ) -{ - RCODE rc = FERR_OK; - FLMBOOL bDbLocked = FALSE; - FLMUINT uiTransFileNum; - FLMUINT uiTransOffset; - FLMUINT uiTruncateSize; - FLMBYTE * pucUncommittedLogHdr; - FLMBYTE ucCheckpointLogHdr[ LOG_HEADER_SIZE]; - - // Make sure we don't have a transaction going - - if (pDb->uiTransType != FLM_NO_TRANS) - { - rc = RC_SET( FERR_TRANS_ACTIVE); - goto Exit; - } - - // Make sure there is no active backup running - - f_mutexLock( gv_FlmSysData.hShareMutex); - if (m_pFile->bBackupActive) - { - f_mutexUnlock( gv_FlmSysData.hShareMutex); - rc = RC_SET( FERR_BACKUP_ACTIVE); - goto Exit; - } - f_mutexUnlock( gv_FlmSysData.hShareMutex); - - // Lock the database - need to prevent update - // transactions and checkpoint thread from running. - - if (RC_BAD( rc = dbLock( pDb, FLM_NO_TIMEOUT))) - { - goto Exit; - } - bDbLocked = TRUE; - - // Must wait for all RFL writes before switching files. - - (void)seeIfRflWritesDone( TRUE); - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better not be in the middle of a transaction. - - flmAssert( !m_uiCurrTransID); - - // If DB version is less than 4.3 we cannot do this. - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; // Will return FERR_OK - } - - pucUncommittedLogHdr = &m_pFile->ucUncommittedLogHdr [0]; - - // Don't want to copy last committed log header into - // uncommitted log header if bNewKeepState is TRUE because - // the caller has already done it, and has made modifications - // to the uncommitted log header that we don't want to lose. - - if (!bNewKeepState) - { - f_memcpy( pucUncommittedLogHdr, m_pFile->ucLastCommittedLogHdr, - LOG_HEADER_SIZE); - - // If we are in a no-keep state, but we were not told that - // we have a new keep state, we cannot roll to the next - // RFL file, because a checkpoint has not been done. This is - // not an error - it is just the case where FlmDbConfig was - // asked to roll to the next RFL file when the keep flag was - // still FALSE. - - if (!pucUncommittedLogHdr [LOG_KEEP_RFL_FILES]) - { - goto Exit; // Will return FERR_OK - } - } - - // Get the last committed serial numbers from the file's log header - // buffer. - - f_memcpy( m_ucCurrSerialNum, - &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - f_memcpy( m_ucNextSerialNum, - &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - uiTransFileNum = - (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_RFL_FILE_NUM]); - uiTransOffset = - (FLMUINT)FB2UD( &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - // If the LOG_RFL_LAST_TRANS_OFFSET is zero, there is no need to go set - // up to go to the next file, because we are already poised to do so at - // the beginning of the next transaction. Just return if this is the - // case. Same for if the file does not exist. - - if (!uiTransOffset) - { - if (!bNewKeepState) - { - goto Exit; // Will return FERR_OK - } - } - else if (RC_BAD( rc = openFile( uiTransFileNum, m_ucCurrSerialNum))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - if (!bNewKeepState) - { - goto Exit; - } - } - else - { - goto Exit; - } - } - else - { - - // At this point, we know the file exists, so we will update - // its header and then update the log header. Note that we - // use the keep RFL state from the last committed log header, - // not the uncommitted log header - because it will contain - // the correct keep-state for the current RFL file. - - if (RC_BAD( rc = writeHeader( m_pCurrentBuf->uiCurrFileNum, uiTransOffset, - m_ucCurrSerialNum, m_ucNextSerialNum, - m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] - ? TRUE - : FALSE))) - { - goto Exit; - } - - // Truncate the file down to its EOF size - the nearest 512 byte boundary. - - uiTruncateSize = uiTransOffset; - if (!ON_512_BYTE_BOUNDARY( uiTruncateSize)) - { - uiTruncateSize = ROUND_DOWN_TO_NEAREST_512( uiTruncateSize) + 512; - } - if (RC_BAD( rc = m_pFileHdl->Truncate( uiTruncateSize))) - { - goto Exit; - } - - // Close the file handle. - - m_pFileHdl->Close(); - m_pFileHdl->Release(); - m_pFileHdl = NULL; - - // Set things up in the log header to go to the next file when - // we begin the next transaction. NOTE: NO need to lock the - // mutex, because nobody but an update transaction looks at - // the uncommitted log header. - - uiTransFileNum++; - UD2FBA( (FLMUINT32)uiTransFileNum, - &pucUncommittedLogHdr [LOG_RFL_FILE_NUM]); - } - - // Generate a new current serial number if bNewKeepState is - // TRUE. Otherwise, move the next serial number into the current - // serial number. - - if (bNewKeepState) - { - if (RC_BAD( rc = f_createSerialNumber( m_ucCurrSerialNum))) - { - goto Exit; - } - } - else - { - f_memcpy( m_ucCurrSerialNum, m_ucNextSerialNum, F_SERIAL_NUM_SIZE); - } - - // Always generate a new next serial number. - - if (RC_BAD( rc = f_createSerialNumber( m_ucNextSerialNum))) - { - goto Exit; - } - - // Set transaction offset to zero. This will force the - // next RFL file to be created on the next transaction - // begin. It will be created even if it is already - // there. - - UD2FBA( (FLMUINT32)0, &pucUncommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - f_memcpy( &pucUncommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - m_ucCurrSerialNum, F_SERIAL_NUM_SIZE); - f_memcpy( &pucUncommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - m_ucNextSerialNum, F_SERIAL_NUM_SIZE); - - // Set the CP file number and CP offset to point into the new file. - // The outer code (FlmDbConfig) has done a checkpoint and the database - // is still locked. We need to set these values here, otherwise - // if we crash before the next checkpoint, recovery will start in the - // old RFL file, causing an FERR_BAD_RFL_SERIAL_NUM to be returned when - // traversing from the old RFL file to the new RFL file. - // NOTE: These changes must be made to the uncommitted log header AND - // the CP log header (so that they will be written out even - // though we are not forcing a checkpoint). - - if (bNewKeepState) - { -#ifdef FLM_DEBUG - // Do a quick check to see if it looks like we are in a - // checkpointed state - - if( !m_pFile->ucLastCommittedLogHdr[ LOG_KEEP_RFL_FILES] && - (FLMUINT)FB2UD( &m_pFile->ucLastCommittedLogHdr[ - LOG_RFL_LAST_TRANS_OFFSET]) > 512) - { - flmAssert( 0); - } -#endif - - f_memcpy( ucCheckpointLogHdr, - m_pFile->ucCheckpointLogHdr, LOG_HEADER_SIZE); - UD2FBA( (FLMUINT32)uiTransFileNum, - &ucCheckpointLogHdr [LOG_RFL_LAST_CP_FILE_NUM]); - UD2FBA( (FLMUINT32)uiTransFileNum, - &pucUncommittedLogHdr [LOG_RFL_LAST_CP_FILE_NUM]); - UD2FBA( (FLMUINT32)512, - &ucCheckpointLogHdr [LOG_RFL_LAST_CP_OFFSET]); - UD2FBA( (FLMUINT32)512, - &pucUncommittedLogHdr [LOG_RFL_LAST_CP_OFFSET]); - } - - // Write out the log header to disk. - - if (RC_BAD( rc = flmWriteLogHdr( pDb->pDbStats, pDb->pSFileHdl, - m_pFile, pucUncommittedLogHdr, - bNewKeepState - ? ucCheckpointLogHdr - : m_pFile->ucCheckpointLogHdr, FALSE))) - { - goto Exit; - } - - // Copy the uncommitted log header back to the committed log header and - // copy the CP log header (if changed above). - - f_mutexLock( gv_FlmSysData.hShareMutex); - f_memcpy( m_pFile->ucLastCommittedLogHdr, pucUncommittedLogHdr, - LOG_HEADER_SIZE); - - if( bNewKeepState) - { - f_memcpy( m_pFile->ucCheckpointLogHdr, - ucCheckpointLogHdr, LOG_HEADER_SIZE); - } - f_mutexUnlock( gv_FlmSysData.hShareMutex); - -Exit: - - if (bDbLocked) - { - (void)dbUnlock( pDb); - } - return( rc); -} - -/******************************************************************** -Desc: Finish packet by outputting header information for it. -*********************************************************************/ -RCODE F_Rfl::finishPacket( - FLMUINT uiPacketType, - FLMUINT uiPacketBodyLen, - FLMBOOL bDoNewIfOverLowLimit - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiEncryptPacketBodyLen; - FLMUINT uiPacketLen; - FLMBYTE * pucPacket; - - // Encrypt the packet body, if requested. - - uiEncryptPacketBodyLen = getEncryptPacketBodyLen( uiPacketType, - uiPacketBodyLen); - uiPacketLen = uiEncryptPacketBodyLen + RFL_PACKET_OVERHEAD; - - // See if this packet will cause us to overflow the limits on - // the current file. If so, create a new file. - - if (RC_BAD( rc = seeIfNeedNewFile( uiPacketLen, bDoNewIfOverLowLimit))) - { - goto Exit; - } - - // Get a pointer to packet header. - - pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[ - m_pCurrentBuf->uiRflBufBytes]); - - // Set the packet address in the packet header. - - m_uiPacketAddress = m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes; - UD2FBA( (FLMUINT32)m_uiPacketAddress, &pucPacket [RFL_PACKET_ADDRESS_OFFSET]); - - // Set the packet type and packet body length. - - pucPacket [RFL_PACKET_TYPE_OFFSET] = (FLMBYTE)uiPacketType; - UW2FBA( (FLMUINT16)uiPacketBodyLen, - &pucPacket [RFL_PACKET_BODY_LENGTH_OFFSET]); - - // Set the checksum for the packet. - - pucPacket [RFL_PACKET_CHECKSUM_OFFSET] = RflCalcChecksum( pucPacket, - uiEncryptPacketBodyLen); - - // Increment bytes in the buffer to reflect the fact that this packet - // is now complete. - - m_pCurrentBuf->uiRflBufBytes += uiPacketLen; -Exit: - return( rc); -} - -/******************************************************************** -Desc: Truncate roll-forward log file to a certain size - only - do if not keeping RFL files. -*********************************************************************/ -RCODE F_Rfl::truncate( - FLMUINT uiTruncateSize - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiFileNum; - - flmAssert( uiTruncateSize >= 512); - - // Keeping of log files better not be enabled. - - flmAssert( !m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES]); - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better not be in the middle of a transaction. - - flmAssert( !m_uiCurrTransID); - - // Open the current RFL file. If it does not exist, it is OK - there - // is nothing to truncate. - - uiFileNum = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_FILE_NUM]); - if (RC_BAD( rc = openFile( uiFileNum, - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM]))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) - { - rc = FERR_OK; - } - goto Exit; - } - if (RC_BAD( rc = m_pFileHdl->Truncate( uiTruncateSize))) - { - m_bRflVolumeOk = FALSE; - goto Exit; - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Setup to begin a transaction -*********************************************************************/ -RCODE F_Rfl::setupTransaction( void) -{ - RCODE rc = FERR_OK; - FLMUINT uiFileNum; - FLMUINT uiLastTransOffset; - FLMBOOL bCreateFile; - - f_mutexLock( m_hBufMutex); - m_pCurrentBuf->bTransInProgress = TRUE; - f_mutexUnlock( m_hBufMutex); - - // Get the last committed serial numbers from the file's log header - // buffer. - - f_memcpy( m_ucCurrSerialNum, - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - f_memcpy( m_ucNextSerialNum, - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - F_SERIAL_NUM_SIZE); - uiFileNum = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_FILE_NUM]); - uiLastTransOffset = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - // If the LOG_RFL_LAST_TRANS_OFFSET is zero, we need to create the - // next RFL file number no matter what. There are two cases where - // this happens: 1) when the database is first created, and 2) after - // a restore operation. - - if (!uiLastTransOffset) - { - bCreateFile = TRUE; - - // Close the current file, just in case we had opened it before. - // At this point, it doesn't matter because we are going to - // overwrite it. - - if (RC_BAD( rc = waitForCommit())) - { - goto Exit; - } - closeFile(); - } - else if (RC_BAD( rc = openFile( uiFileNum, m_ucCurrSerialNum))) - { - if (rc != FERR_IO_PATH_NOT_FOUND && rc != FERR_IO_INVALID_PATH) - { - goto Exit; - } - bCreateFile = TRUE; - } - else - { - bCreateFile = FALSE; - } - - if (bCreateFile) - { - - // If the log header indicates that data has already been logged - // to the file, we need to return the I/O error rather than just - // re-creating the file. This may mean that someone changed the - // RFL directory without moving the RFL files properly. - - if (uiLastTransOffset > 512) - { - rc = RC_SET( FERR_RFL_FILE_NOT_FOUND); - goto Exit; - } - - // Create the RFL file if not found. - - // Use the next serial number stored in the FDB's log header - // for the serial number on this RFL file. Use the serial - // number we just generated as the next RFL serial number. - - if (RC_BAD( rc = createFile( uiFileNum, - m_ucCurrSerialNum, m_ucNextSerialNum, - m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] - ? TRUE - : FALSE))) - { - goto Exit; - } - } - else - { - - // Read in enough of the buffer from the RFL file so that - // we are positioned on a 512 byte boundary. - - if (RC_BAD( positionTo( uiLastTransOffset))) - { - goto Exit; - } - } - - // These can only be changed when starting a transaction. - - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_3) - { - m_bKeepRflFiles = m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] - ? TRUE - : FALSE; - m_uiRflMaxFileSize = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_MAX_FILE_SIZE]); - - // Round maximum down to nearest 512 boundary. This is necessary - // because we always write a minimum of 512 byte units in direct IO - // mode. If we did not round the maximum down, our last packet could - // end at an offset that is less than the maximum, but greater than - // the nearest 512 byte boundary - technically within the user-specified - // size limit. However, because we always write a full 512 bytes of data - // to fill out the last sector when we are in direct IO mode, we would - // end up with a file that was slightly larger than the user-specified - // limit. The EOF in the header of the file would be below the limit, - // but the actual file size would not be. Thus, the need to round down. - - m_uiRflMaxFileSize = ROUND_DOWN_TO_NEAREST_512( m_uiRflMaxFileSize); - - // The maximum cannot go below a certain threshold - must have room for - // least one packet plus the header. - - if (m_uiRflMaxFileSize < RFL_MAX_PACKET_SIZE + 512) - { - m_uiRflMaxFileSize = RFL_MAX_PACKET_SIZE + 512; - } - else if (m_uiRflMaxFileSize > gv_FlmSysData.uiMaxFileSize) - { - m_uiRflMaxFileSize = gv_FlmSysData.uiMaxFileSize; - } - } - else - { - m_bKeepRflFiles = FALSE; - m_uiRflMaxFileSize = gv_FlmSysData.uiMaxFileSize; - } - - m_uiRflMinFileSize = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_MIN_FILE_SIZE]); - - // Minimum RFL file size should not be allowed to be larger than - // maximum! - - if (m_uiRflMinFileSize > m_uiRflMaxFileSize) - { - m_uiRflMinFileSize = m_uiRflMaxFileSize; - } - - // Set the operation count to zero. - - m_uiOperCount = 0; - - m_pFileHdl->setMaxAutoExtendSize( m_uiRflMaxFileSize); - m_pFileHdl->setExtendSize( m_pFile->uiFileExtendSize); -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Log transaction begin. This routine will also make sure - we have opened an RFL file. - NOTE: The prior version of FLAIM (before 4.3) would log - a time and set the RFL_TIME_LOGGED_FLAG bit in the packet - type. This is no longer done. Old code should be - compatible because it reads the flag. -*********************************************************************/ -RCODE F_Rfl::logBeginTransaction( - FDB * pDb - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiDbVersion = pDb->pFile->FileHdr.uiVersionNum; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - FLMUINT uiGMTTime; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better not be in the middle of a transaction. - - flmAssert( !m_uiCurrTransID); - - if( RC_BAD( rc = setupTransaction())) - { - goto Exit; - } - - uiPacketBodyLen = uiDbVersion >= FLM_VER_4_31 ? 12 : 8; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)pDb->LogHdr.uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // This used to be a FLM_GET_TIMER() value in pre-4.3 code, but - // it was never really used. Set it to GMT time now. - - f_timeGetSeconds( &uiGMTTime); - UD2FBA( (FLMUINT32)uiGMTTime, pucPacketBody); - pucPacketBody += 4; - - // NOTE: In the pre-4.3 code the next four bytes would be - // zero, but that is really unnecessary. We will simply - // no longer set the RFL_TIME_LOGGED_FLAG bit in the - // packet type. Pre-4.3 code should be compatible. - - if( uiDbVersion >= FLM_VER_4_31) - { - FLMUINT uiLastLoggedCommitID; - - uiLastLoggedCommitID = FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]); - - UD2FBA( (FLMUINT32)uiLastLoggedCommitID, pucPacketBody); - pucPacketBody += 4; - - if (RC_BAD( rc = finishPacket( - RFL_TRNS_BEGIN_EX_PACKET, uiPacketBodyLen, TRUE))) - { - goto Exit; - } - } - else - { - if (RC_BAD( rc = finishPacket( - RFL_TRNS_BEGIN_PACKET, uiPacketBodyLen, TRUE))) - { - goto Exit; - } - } - - // Save the file offset for the start transaction packet. - - m_uiTransStartFile = m_pCurrentBuf->uiCurrFileNum; - m_uiTransStartAddr = m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes - - uiPacketBodyLen - RFL_PACKET_OVERHEAD; - m_uiCurrTransID = pDb->LogHdr.uiCurrTransID; - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Flushes the RFL and sets some things in the log header. -*********************************************************************/ -void F_Rfl::finalizeTransaction( void) -{ - FLMUINT uiRflTransEndOffset; - FLMBYTE * pucLogHdr = &m_pFile->ucUncommittedLogHdr [0]; - - // Save the serial numbers and file numbers into the file's - // uncommitted log header. - - UD2FBA( (FLMUINT32)m_pCurrentBuf->uiCurrFileNum, - &pucLogHdr [LOG_RFL_FILE_NUM]); - - uiRflTransEndOffset = getCurrWriteOffset(); - UD2FBA( (FLMUINT32)uiRflTransEndOffset, - &pucLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); - - f_memcpy( &pucLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - m_ucCurrSerialNum, F_SERIAL_NUM_SIZE); - - f_memcpy( &pucLogHdr [LOG_RFL_NEXT_SERIAL_NUM], - m_ucNextSerialNum, F_SERIAL_NUM_SIZE); -} - -/******************************************************************** -Desc: Handles the commit and abort log operations. If aborting - the transaction, or if the transaction was empty, we will - simply throw away the entire transaction and not bother - to log it. In that case we will reset transaction pointers, - etc. back to the file and offset where the transaction began. - We will also delete RFL files that were created during the - transaction if necessary. NOTE: It is not essential that - the RFL files be deleted. If they are not successfully - deleted, they will be overwritten if need be when creating - new ones. - NOTE: The prior version of FLAIM (before 4.3) would log - a time and set the RFL_TIME_LOGGED_FLAG bit in the packet - type. This is no longer done. Old code should be - compatible because it reads the flag. -*********************************************************************/ -RCODE F_Rfl::logEndTransaction( - FLMUINT uiPacketType, - FLMBOOL bThrowLogAway, - FLMBOOL * pbLoggedTransEnd) -{ - RCODE rc = FERR_OK; - RCODE rc2 = FERR_OK; - FLMUINT uiLowFileNum; - FLMUINT uiHighFileNum; - char szRflFileName [F_PATH_MAX_SIZE]; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Initialize the "logged trans end" flag - - if( pbLoggedTransEnd) - { - *pbLoggedTransEnd = FALSE; - } - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - flmAssert( m_pFileHdl); - flmAssert( m_pFile); - - // If the transaction had no operations, throw it away - don't - // even log the packet. An abort operation may also - // elect to throw the log away even if there were - // operations. That is determined by the bThrowLogAway flag. - // The bThrowLogAway flag may be TRUE when doing a commit if - // the caller knows that nothing happened during the transction. - - if (bThrowLogAway || !m_uiOperCount) - { -Throw_Away_Transaction: - - // If we have switched files, delete all but the file we - // started in. - - if (m_pCurrentBuf->uiCurrFileNum != m_uiTransStartFile) - { - flmAssert( m_pCurrentBuf->uiCurrFileNum > m_uiTransStartFile); - - // File number in uncommitted log header better not - // have been changed yet. It is only supposed to - // be changed when the transaction finishes - i.e., in - // this routine. Up until this point, it should only - // be changed in m_pCurrentBuf->uiCurrFileNum. - - flmAssert( m_uiTransStartFile == - (FLMUINT)FB2UD( &m_pFile->ucUncommittedLogHdr [LOG_RFL_FILE_NUM])); - - uiLowFileNum = m_uiTransStartFile + 1; - uiHighFileNum = m_pCurrentBuf->uiCurrFileNum; - - // Close the current file so it can be deleted. - - if (RC_BAD( rc = waitForCommit())) - { - goto Exit; - } - closeFile(); - - // Delete as many of the files as possible. Don't worry - // about errors here. - - while (uiLowFileNum <= uiHighFileNum) - { - if (RC_OK( getFullRflFileName( uiLowFileNum, szRflFileName))) - { - (void)gv_FlmSysData.pFileSystem->Delete( szRflFileName); - } - uiLowFileNum++; - } - } - else - { - - // If we are in the file the transaction started in, simply - // reset to where the transaction started. - - if (RC_BAD( rc2 = positionTo( m_uiTransStartAddr))) - { - // If we got to this point because of a - // "goto Throw_Away_Transaction", we don't want to - // clobber the original error code. So, we use rc2 - // temporarily and then determine if its value should - // be set into rc. - - if( RC_OK( rc)) - { - rc = rc2; - } - rc2 = FERR_OK; - goto Exit; - } - } - } - else - { - - // Log a commit or abort packet. - - uiPacketBodyLen = 8; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Throw_Away_Transaction; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - UD2FBA( (FLMUINT32)m_uiTransStartAddr, pucPacketBody); - pucPacketBody += 4; - if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, - FALSE))) - { - goto Throw_Away_Transaction; - } - - finalizeTransaction(); - - if( pbLoggedTransEnd) - { - *pbLoggedTransEnd = TRUE; - } - } - -Exit: - - if (!m_bLoggingOff) - { - m_uiCurrTransID = 0; - } - - return( RC_BAD( rc) ? rc : rc2); -} - -/******************************************************************** -Desc: Log add, modify, delete, and reserve DRN packets -*********************************************************************/ -RCODE F_Rfl::logUpdatePacket( - FLMUINT uiPacketType, - FLMUINT uiContainer, - FLMUINT uiDrn, - FLMUINT uiAutoTrans) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be in the middle of a transaction. - - flmAssert( m_uiCurrTransID); - - m_uiOperCount++; - - if( uiPacketType == RFL_ADD_RECORD_PACKET_VER_2 || - uiPacketType == RFL_MODIFY_RECORD_PACKET_VER_2 || - uiPacketType == RFL_DELETE_RECORD_PACKET_VER_2) - { - uiPacketBodyLen = 11; - } - else - { - uiPacketBodyLen = 10; - } - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the container number. - - UW2FBA( (FLMUINT16)uiContainer, pucPacketBody); - pucPacketBody += 2; - - // Output the DRN. - - UD2FBA( (FLMUINT32)uiDrn, pucPacketBody); - pucPacketBody += 4; - - // Output the flags - - if( uiPacketType == RFL_ADD_RECORD_PACKET_VER_2 || - uiPacketType == RFL_MODIFY_RECORD_PACKET_VER_2 || - uiPacketType == RFL_DELETE_RECORD_PACKET_VER_2) - { - FLMUINT uiFlags = 0; - - // For now, these are the only flags we log - - if( uiAutoTrans & FLM_DO_IN_BACKGROUND) - { - uiFlags |= RFL_UPDATE_BACKGROUND; - } - - if( uiAutoTrans & FLM_SUSPENDED) - { - uiFlags |= RFL_UPDATE_SUSPENDED; - } - - *pucPacketBody++ = (FLMBYTE)uiFlags; - } - - // Finish the packet - - if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, - FALSE))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Log index suspend and resume packets -*********************************************************************/ -RCODE F_Rfl::logIndexSuspendOrResume( - FLMUINT uiIndexNum, - FLMUINT uiPacketType) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // This call is new with 4.51 databases - not supported in older - // versions, so don't log it. - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_51) - { - goto Exit; - } - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be in the middle of a transaction. - - flmAssert( m_uiCurrTransID); - - m_uiOperCount++; - uiPacketBodyLen = 6; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the index number. - - UW2FBA( (FLMUINT16)uiIndexNum, pucPacketBody); - pucPacketBody += 2; - - // Finish the packet - - if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, - FALSE))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Make room in the RFL buffer for the additional bytes. - This is done by flushing the log buffer and shifting down - the bytes already used in the current packet. If that doesn't - make room, the current packet will be finished and a new one - started. -*********************************************************************/ -RCODE F_Rfl::makeRoom( - FLMUINT uiAdditionalBytesNeeded, - FLMUINT * puiCurrPacketLenRV, - FLMUINT uiPacketType, - FLMUINT * puiBytesAvailableRV, - FLMUINT * puiPacketCountRV - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesNeeded; - - // Must account for encryption, so round bytes needed to nearest - // four byte boundary. - - uiBytesNeeded = *puiCurrPacketLenRV + uiAdditionalBytesNeeded; - if (uiBytesNeeded & 0x3) - { - uiBytesNeeded += (4 - (uiBytesNeeded & 0x3)); - } - - if (uiBytesNeeded <= (FLMUINT)RFL_MAX_PACKET_SIZE) - { - FLMUINT uiTmp = uiBytesNeeded; - - if (haveBuffSpace( uiTmp)) - { - if (puiBytesAvailableRV) - { - *puiBytesAvailableRV = uiAdditionalBytesNeeded; - } - } - else - { - - // Bytes requested will fit into a packet, but not the - // buffer, so we need to shift the packets in the buffer - // down. The shiftPacketsDown guarantees that there - // is room in the buffer for a full size packet. - - if (RC_BAD( rc = shiftPacketsDown( *puiCurrPacketLenRV, FALSE))) - { - goto Exit; - } - - // If a non-NULL puwBytesAvailableRV is passed in it means that we - // are to return the number of bytes that we can actually output. - // Since we know there is enough for the bytes needed, we simply return - // the number of bytes that were requested. - - if (puiBytesAvailableRV) - { - *puiBytesAvailableRV = uiAdditionalBytesNeeded; - } - } - } - else // (uiBytesNeeded > RFL_MAX_PACKET_SIZE) - { - - // This is the case where the bytes needed would overflow the - // maximum packet size. - // If puwBytesAvailableRV is NULL, it means that all of the - // requested additional bytes must fit into the packet. In that - // case, since the requested bytes would put us over the packet - // size limit, we must finish the current packet and then - // flush the packets out of the buffer so we can start a - // new packet. - - if (!puiBytesAvailableRV) - { - - // Finish the current packet and start a new one. - - if (puiPacketCountRV) - { - (*puiPacketCountRV)++; - } - if (RC_BAD( rc = finishPacket( uiPacketType, - *puiCurrPacketLenRV - RFL_PACKET_OVERHEAD, - FALSE))) - { - goto Exit; - } - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - *puiCurrPacketLenRV = RFL_PACKET_OVERHEAD; - } - else - { - - // When puiBytesAvailableRV is non-NULL, it means we can fill up - // the rest of the packet with part of the bytes. In this case - // we return the number of bytes available and then shift the - // packets down in the buffer to make sure there is room for - // a full-size packet. - - *puiBytesAvailableRV = RFL_MAX_PACKET_SIZE - *puiCurrPacketLenRV; - if (RC_BAD( rc = shiftPacketsDown( *puiCurrPacketLenRV, FALSE))) - { - goto Exit; - } - } - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Log a chunk of data to the RFL log - typically used to log - field data. Will spill over into multiple packets if - necessary. -*********************************************************************/ -RCODE F_Rfl::logData( - FLMUINT uiDataLen, - const FLMBYTE * pucData, - FLMUINT uiPacketType, - FLMUINT * puiPacketLenRV, - FLMUINT * puiPacketCountRV, - FLMUINT * puiMaxLogBytesNeededRV, - FLMUINT * puiTotalBytesLoggedRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiBytesAvail; - FLMBYTE * pucDest; - - while (uiDataLen) - { - if (RC_BAD( rc = makeRoom( uiDataLen, - puiPacketLenRV, uiPacketType, &uiBytesAvail, - puiPacketCountRV))) - { - goto Exit; - } - if (uiBytesAvail) - { - if (puiMaxLogBytesNeededRV) - { - if (RC_BAD( rc = RflCheckMaxLogged( - puiMaxLogBytesNeededRV, - *puiPacketCountRV, - puiTotalBytesLoggedRV, - uiBytesAvail))) - { - goto Exit; - } - } - pucDest = getPacketPtr() + (*puiPacketLenRV); - f_memcpy( pucDest, pucData, uiBytesAvail); - uiDataLen -= uiBytesAvail; - pucData += uiBytesAvail; - (*puiPacketLenRV) += uiBytesAvail; - } - - // If we didn't get all of the data into the RFL buffer, - // finish and flush the current packet. - - if (uiDataLen) - { - if (puiPacketCountRV) - { - (*puiPacketCountRV)++; - } - if (RC_BAD( rc = finishPacket( uiPacketType, - *puiPacketLenRV - RFL_PACKET_OVERHEAD, - FALSE))) - { - goto Exit; - } - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - *puiPacketLenRV = RFL_PACKET_OVERHEAD; - if (puiMaxLogBytesNeededRV) - { - if (RC_BAD( rc = RflCheckMaxLogged( - puiMaxLogBytesNeededRV, - *puiPacketCountRV, - puiTotalBytesLoggedRV, - RFL_PACKET_OVERHEAD))) - { - goto Exit; - } - } - } - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Check to see if by logging the requested number of bytes we - will end up exceeding the maximum bytes needed. If so, and - we have not yet actually logged a packet, return - FERR_FAILURE so that we will discard this packet that is - being built. If we have already logged a packet, it is - too late to discard what has been done. -*********************************************************************/ -FSTATIC RCODE RflCheckMaxLogged( - FLMUINT * puiMaxBytesNeededRV, - FLMUINT uiPacketsLogged, - FLMUINT * puiCurrTotalLoggedRV, - FLMUINT uiBytesToLog) -{ - RCODE rc = FERR_OK; - - *puiCurrTotalLoggedRV += uiBytesToLog; - - if ((!uiPacketsLogged) && - (*puiCurrTotalLoggedRV > *puiMaxBytesNeededRV)) - { - rc = RC_SET( FERR_FAILURE); - goto Exit; - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Callback function that captures the changes being logged by - the call to flmRecordDifference. -*********************************************************************/ -FSTATIC void RflChangeCallback( - GRD_DifferenceData & DiffData, - void * CallbackData - ) -{ - RFL_CHANGE_DATA * pRflChangeData = (RFL_CHANGE_DATA *)CallbackData; - F_Rfl * pRfl = pRflChangeData->pRfl; - void * pvField; - const FLMBYTE * pucExportPtr; - FLMBYTE * pucTmp; - FLMUINT uiOverhead = 0; - FLMUINT uiBytesToLog; - FLMUINT uiPos; - FLMUINT uiTagNum; - FLMUINT uiDataLen; - FLMBOOL bEncrypted = FALSE; - FLMUINT uiEncId; - - // If we had an error before this callback, do nothing. - - if (RC_BAD( pRflChangeData->rc)) - { - goto Exit; - } - - if ( DiffData.pvAfterField) - { - flmAssert( DiffData.pAfterRecord); - bEncrypted = DiffData.pAfterRecord->isEncryptedField( - DiffData.pvAfterField); - } - - switch (DiffData.type) - { - case GRD_Inserted: - uiOverhead = (bEncrypted ? 13 : 9); - break; - case GRD_Deleted: - // Ignore these for versions of the database >= 4.60 - if (pRflChangeData->uiVersionNum >= FLM_VER_4_60) - { - goto Exit; - } - uiOverhead = 3; - break; - case GRD_DeletedSubtree: - // Ignore these for versions of the database < 4.60 - if (pRflChangeData->uiVersionNum < FLM_VER_4_60) - { - goto Exit; - } - uiOverhead = 3; - break; - case GRD_Modified: - uiOverhead = (bEncrypted ? 10 : 6); - break; - default: - flmAssert( 0); - break; - } - - // Determine the number of bytes that will actually be logged with this - // overhead. If it won't fit in the current packet, we will have to - // create a new packet - hence, we add RFL_PACKET_OVERHEAD to the amount - // that will be logged. - - uiBytesToLog = uiOverhead; - if (RFL_MAX_PACKET_SIZE - uiOverhead < pRflChangeData->uiCurrPacketLen) - { - uiBytesToLog += RFL_PACKET_OVERHEAD; - } - - // See if the bytes we are going log will exceed the maximum bytes needed. - - if (RC_BAD( pRflChangeData->rc = RflCheckMaxLogged( - &pRflChangeData->uiMaxLogBytesNeeded, - pRflChangeData->uiPacketCount, - &pRflChangeData->uiTotalBytesLogged, - uiBytesToLog))) - { - goto Exit; - } - - // Make room to log the overhead - - if (RC_BAD( pRflChangeData->rc = pRfl->makeRoom( uiOverhead, - &pRflChangeData->uiCurrPacketLen, - RFL_CHANGE_FIELDS_PACKET, NULL, - &pRflChangeData->uiPacketCount))) - { - goto Exit; - } - pucTmp = pRfl->getPacketPtr() + pRflChangeData->uiCurrPacketLen; - uiPos = DiffData.uiAbsolutePosition; - UW2FBA( (FLMUINT16)uiPos, &pucTmp [1]); - pRflChangeData->uiCurrPacketLen += uiOverhead; - pvField = DiffData.pvAfterField; - - switch (DiffData.type) - { - case GRD_Inserted: - *pucTmp = (bEncrypted ? RFL_INSERT_ENC_FIELD : RFL_INSERT_FIELD); - pucTmp += 3; - uiTagNum = DiffData.pAfterRecord->getFieldID( pvField); - UW2FBA( (FLMUINT16)uiTagNum, pucTmp); - pucTmp += 2; - *pucTmp++ = (FLMBYTE)DiffData.pAfterRecord->getDataType( pvField); - *pucTmp++ = (FLMBYTE)DiffData.pAfterRecord->getLevel( pvField); - uiDataLen = DiffData.pAfterRecord->getDataLength( pvField); - UW2FBA( (FLMUINT16)uiDataLen, pucTmp); - pucTmp += 2; - - if (bEncrypted) - { - uiEncId = DiffData.pAfterRecord->getEncryptionID( pvField); - flmAssert( uiEncId); - UW2FBA( (FLMUINT16)uiEncId, pucTmp); - pucTmp += 2; - - uiDataLen = DiffData.pAfterRecord->getEncryptedDataLength(pvField); - UW2FBA( uiDataLen, pucTmp); - pucTmp += 2; - } - - // Log the data, if any. - - if (uiDataLen) - { - if (bEncrypted) - { - pucExportPtr = - DiffData.pAfterRecord->getEncryptionDataPtr(pvField); - } - else - { - pucExportPtr = DiffData.pAfterRecord->getDataPtr( pvField); - } - if( !pucExportPtr) - { - pRflChangeData->rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( pRflChangeData->rc = pRfl->logData( - uiDataLen, - pucExportPtr, - RFL_CHANGE_FIELDS_PACKET, - &pRflChangeData->uiCurrPacketLen, - &pRflChangeData->uiPacketCount, - &pRflChangeData->uiMaxLogBytesNeeded, - &pRflChangeData->uiTotalBytesLogged))) - { - goto Exit; - } - } - break; - case GRD_Deleted: - case GRD_DeletedSubtree: - *pucTmp = RFL_DELETE_FIELD; - break; - case GRD_Modified: - *pucTmp = (bEncrypted ? RFL_MODIFY_ENC_FIELD : RFL_MODIFY_FIELD); - pucTmp += 3; - - // For now, just log the new bytes using RFL_REPLACE_BYTES option - *pucTmp++ = RFL_REPLACE_BYTES; - uiDataLen = DiffData.pAfterRecord->getDataLength( pvField); - UW2FBA( (FLMUINT16)uiDataLen, pucTmp); - pucTmp += 2; - - if (bEncrypted) - { - uiEncId = DiffData.pAfterRecord->getEncryptionID( pvField); - flmAssert( uiEncId); - UW2FBA( (FLMUINT16)uiEncId, pucTmp); - pucTmp += 2; - - uiDataLen = DiffData.pAfterRecord->getEncryptedDataLength( pvField); - UW2FBA( uiDataLen, pucTmp); - pucTmp += 2; - } - - // Log the data, if any. - - if (uiDataLen) - { - if (bEncrypted) - { - pucExportPtr = - DiffData.pAfterRecord->getEncryptionDataPtr(pvField); - } - else - { - pucExportPtr = DiffData.pAfterRecord->getDataPtr( pvField); - } - if (pucExportPtr == NULL) - { - pRflChangeData->rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( pRflChangeData->rc = pRfl->logData( - uiDataLen, - pucExportPtr, - RFL_CHANGE_FIELDS_PACKET, - &pRflChangeData->uiCurrPacketLen, - &pRflChangeData->uiPacketCount, - &pRflChangeData->uiMaxLogBytesNeeded, - &pRflChangeData->uiTotalBytesLogged))) - { - goto Exit; - } - } - - break; - default: - flmAssert( 0); - break; - } -Exit: - return; -} - -/******************************************************************** -Desc: Log change fields for a record modify operation. -*********************************************************************/ -RCODE F_Rfl::logChangeFields( - FlmRecord * pOldRecord, - FlmRecord * pNewRecord - ) -{ - RFL_CHANGE_DATA RflChangeData; - FLMUINT uiTmpBodyLen; - FLMUINT uiDataLen; - void * pvNewField; - FLMBOOL bEncrypted; - FLMUINT uiOverhead; - - RflChangeData.rc = FERR_OK; - RflChangeData.pRfl = this; - RflChangeData.uiVersionNum = m_pFile->FileHdr.uiVersionNum; - - // Determine the total amount that would have to be logged if - // we just logged the new record. - - RflChangeData.uiMaxLogBytesNeeded = RFL_PACKET_OVERHEAD; - uiTmpBodyLen = 0; - pvNewField = pNewRecord->root(); - for (; pvNewField; pvNewField = pNewRecord->next( pvNewField) ) - { - bEncrypted = pNewRecord->isEncryptedField( pvNewField); - uiOverhead = (bEncrypted ? 10 : 6); - if (uiTmpBodyLen + uiOverhead <= RFL_MAX_PACKET_BODY_SIZE) - { - uiTmpBodyLen += uiOverhead; - } - else - { - uiTmpBodyLen = uiOverhead; - RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; - } - RflChangeData.uiMaxLogBytesNeeded += uiOverhead; - if (bEncrypted) - { - uiDataLen = pNewRecord->getEncryptedDataLength( pvNewField); - } - else - { - uiDataLen = pNewRecord->getDataLength( pvNewField); - } - while (uiDataLen) - { - FLMUINT uiTmp; - - uiTmp = RFL_MAX_PACKET_BODY_SIZE - uiTmpBodyLen; - if (uiTmp >= uiDataLen) - { - uiTmp = uiDataLen; - uiTmpBodyLen += uiDataLen; - } - else - { - uiTmpBodyLen = 0; - RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; - } - RflChangeData.uiMaxLogBytesNeeded += uiTmp; - uiDataLen -= uiTmp; - } - } - - // Account for terminating 0 at the end. - - if (uiTmpBodyLen + 2 > RFL_MAX_PACKET_BODY_SIZE) - { - RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; - } - RflChangeData.uiMaxLogBytesNeeded += 2; - - RflChangeData.uiPacketCount = 0; - RflChangeData.uiTotalBytesLogged = RFL_PACKET_OVERHEAD; - RflChangeData.uiCurrPacketLen = RFL_PACKET_OVERHEAD; - - if (!haveBuffSpace( RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( RflChangeData.rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - flmRecordDifference( pOldRecord, pNewRecord, RflChangeCallback, - (void *)&RflChangeData); - - // See if we exceeded the maximum log bytes. If so, just log - // the changed record in its entirety. - - if (RC_BAD( RflChangeData.rc)) - { - if (RflChangeData.rc == FERR_FAILURE) - { - RflChangeData.rc = logRecord( pNewRecord); - } - goto Exit; - } - else - { - FLMBYTE * pucTmp; - - // Make room to log the 3 bytes of terminator - - if (RC_BAD( RflChangeData.rc = makeRoom( 3, - &RflChangeData.uiCurrPacketLen, - RFL_CHANGE_FIELDS_PACKET, NULL, - &RflChangeData.uiPacketCount))) - { - if (RflChangeData.rc == FERR_FAILURE) - { - RflChangeData.rc = logRecord( pNewRecord); - } - goto Exit; - } - pucTmp = getPacketPtr() + RflChangeData.uiCurrPacketLen; - *pucTmp++ = RFL_END_FIELD_CHANGES; - UW2FBA( (FLMUINT16)0, pucTmp); - RflChangeData.uiCurrPacketLen += 3; - - if (RC_BAD( RflChangeData.rc = finishPacket( RFL_CHANGE_FIELDS_PACKET, - RflChangeData.uiCurrPacketLen - RFL_PACKET_OVERHEAD, - FALSE))) - { - goto Exit; - } - } - -Exit: - return( RflChangeData.rc); -} - -/******************************************************************** -Desc: Log a record for the record add or modify operations. -*********************************************************************/ -RCODE F_Rfl::logRecord( - FlmRecord * pRecord) -{ - RCODE rc = FERR_OK; - FLMUINT uiPacketLen = RFL_PACKET_OVERHEAD; - void * pvField; - FLMBYTE * pucTmp; - FLMUINT uiTagNum; - FLMUINT uiDataLen; - FLMBOOL bEncrypted; - FLMUINT uiEncId; - FLMUINT uiPacketType; - FLMUINT uiOverhead; - - if( !haveBuffSpace( RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_60) - { - uiPacketType = RFL_DATA_RECORD_PACKET; - } - else - { - uiPacketType = RFL_ENC_DATA_RECORD_PACKET; - } - - pvField = pRecord->root(); - for (; pvField; pvField = pRecord->next( pvField) ) - { - if (uiPacketType == RFL_DATA_RECORD_PACKET) - { - bEncrypted = FALSE; - uiOverhead = 6; - } - else - { - bEncrypted = pRecord->isEncryptedField( pvField); - uiOverhead = (bEncrypted ? 11 : 7); - } - - if (RC_BAD( rc = makeRoom( uiOverhead, &uiPacketLen, - uiPacketType, NULL, NULL))) - { - goto Exit; - } - - pucTmp = getPacketPtr() + uiPacketLen; - uiPacketLen += uiOverhead; - - uiTagNum = pRecord->getFieldID( pvField); - UW2FBA( (FLMUINT16)uiTagNum, pucTmp); - pucTmp += 2; - *pucTmp++ = (FLMBYTE)pRecord->getDataType( pvField); - *pucTmp++ = (FLMBYTE)pRecord->getLevel( pvField); - uiDataLen = pRecord->getDataLength( pvField); - UW2FBA( (FLMUINT16)uiDataLen, pucTmp); - pucTmp += 2; - // Record if this field is encrypted. If it is, then there will - // be more data to follow. - if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) - { - *pucTmp = (bEncrypted ? (FLMBYTE)1 : (FLMBYTE)0); - pucTmp++; - - // Check for encrypted field and add the results. - if (bEncrypted) - { - uiEncId = pRecord->getEncryptionID( pvField); - flmAssert( uiEncId); - UW2FBA( (FLMUINT16)uiEncId, pucTmp); - pucTmp += 2; - - uiDataLen = pRecord->getEncryptedDataLength(pvField); - UW2FBA( uiDataLen, pucTmp); - pucTmp += 2; - } - } - - - // Log the data, if any. - - if (uiDataLen) - { - const FLMBYTE * pucExportPtr; - - if (bEncrypted) - { - pucExportPtr = pRecord->getEncryptionDataPtr( pvField); - } - else - { - pucExportPtr = pRecord->getDataPtr( pvField); - } - if (pucExportPtr == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if( RC_BAD( rc = logData( uiDataLen, pucExportPtr, - uiPacketType, &uiPacketLen, NULL, NULL, NULL))) - { - goto Exit; - } - } - } - - // Add null to terminate the record. - - if (RC_BAD( rc = makeRoom( 2, &uiPacketLen, uiPacketType, - NULL, NULL))) - { - goto Exit; - } - - pucTmp = getPacketPtr() + uiPacketLen; - uiPacketLen += 2; - UW2FBA( 0, pucTmp); - pucTmp += 2; - - // Finish the packet. - - if (RC_BAD( rc = finishPacket( uiPacketType, - uiPacketLen - RFL_PACKET_OVERHEAD, FALSE))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Log record add, modify, or delete operation -*********************************************************************/ -RCODE F_Rfl::logUpdate( - FLMUINT uiContainer, - FLMUINT uiDrn, - FLMUINT uiAutoTrans, - FlmRecord * pOldRecord, - FlmRecord * pNewRecord) -{ - RCODE rc = FERR_OK; - FLMUINT uiPacketType; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be in the middle of a transaction. - - flmAssert( m_uiCurrTransID); - - if (pOldRecord && pNewRecord) - { - if( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_60) - { - uiPacketType = RFL_MODIFY_RECORD_PACKET_VER_2; - } - else - { - uiPacketType = RFL_MODIFY_RECORD_PACKET; - } - } - else if (pNewRecord) - { - if( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_60) - { - uiPacketType = RFL_ADD_RECORD_PACKET_VER_2; - } - else - { - uiPacketType = RFL_ADD_RECORD_PACKET; - } - } - else - { - if( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_60) - { - uiPacketType = RFL_DELETE_RECORD_PACKET_VER_2; - } - else - { - uiPacketType = RFL_DELETE_RECORD_PACKET; - } - } - - if (RC_BAD( rc = logUpdatePacket( uiPacketType, - uiContainer, uiDrn, uiAutoTrans))) - { - goto Exit; - } - - // If it is a record modify, log the change fields. - // If it is a record add, log the new record. - - if (pOldRecord && pNewRecord) - { - if (RC_BAD( rc = logChangeFields( pOldRecord, pNewRecord))) - { - goto Exit; - } - } - else if (pNewRecord) - { - if (RC_BAD( rc = logRecord( pNewRecord))) - { - goto Exit; - } - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Log a set of records that is indexed for a specific index. -*********************************************************************/ -RCODE F_Rfl::logIndexSet( - FLMUINT uiIndex, - FLMUINT uiContainerNum, - FLMUINT uiStartDrn, - FLMUINT uiEndDrn) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // This call is a new database version. Database better have - // been upgraded. - - flmAssert( m_pFile->FileHdr.uiVersionNum >= FLM_VER_3_02); - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be in the middle of a transaction. - - flmAssert( m_uiCurrTransID); - - m_uiOperCount++; - uiPacketBodyLen = (FLMUINT)((m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_50) - ? (FLMUINT)16 - : (FLMUINT)14); - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the container number, if db version is >= 4.50 - - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_50) - { - UW2FBA( (FLMUINT16)uiContainerNum, pucPacketBody); - pucPacketBody += 2; - } - - // Output the index number. - - UW2FBA( (FLMUINT16)uiIndex, pucPacketBody); - pucPacketBody += 2; - - // Output the starting DRN. - - UD2FBA( (FLMUINT32)(uiStartDrn), pucPacketBody); - pucPacketBody += 4; - - // Output the ending DRN. - - UD2FBA( (FLMUINT32)(uiEndDrn), pucPacketBody); - pucPacketBody += 4; - - // Finish the packet - - if (RC_BAD( rc = finishPacket( - (FLMUINT)((m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_50) - ? (FLMUINT)RFL_INDEX_SET_PACKET_VER_2 - : (FLMUINT)RFL_INDEX_SET_PACKET), uiPacketBodyLen, - FALSE))) - { - goto Exit; - } - -Exit: - return( rc); -} - -/******************************************************************** -Desc: Start logging unknown packets. -*********************************************************************/ -RCODE F_Rfl::startLoggingUnknown( void) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - flmAssert( m_pFile); - - // Do nothing if logging is disabled. Also, ignore - // these packets if we are operating on a pre-4.3 - // database. - - if (m_bLoggingOff || - m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; - } - - // Better not already be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be inside a transaction. - - flmAssert( m_uiCurrTransID); - - m_uiOperCount++; - uiPacketBodyLen = 4; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_START_UNKNOWN_PACKET, uiPacketBodyLen, - FALSE))) - { - goto Exit; - } - - m_bLoggingUnknown = TRUE; - m_uiUnknownPacketLen = RFL_PACKET_OVERHEAD; -Exit: - return( rc); -} - -/******************************************************************** -Desc: Log unknown data. -*********************************************************************/ -RCODE F_Rfl::logUnknown( - FLMBYTE * pucUnknown, - FLMUINT uiLen) -{ - RCODE rc = FERR_OK; - - // Do nothing if logging is disabled. Also, ignore - // these packets if we are operating on a pre-4.3 - // database. - - if (m_bLoggingOff || - m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; - } - - flmAssert( m_bLoggingUnknown); - if (RC_BAD( rc = logData( uiLen, pucUnknown, - RFL_UNKNOWN_PACKET, - &m_uiUnknownPacketLen, - NULL, NULL, NULL))) - { - goto Exit; - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: End logging unknown packets. -*********************************************************************/ -RCODE F_Rfl::endLoggingUnknown( void) -{ - RCODE rc = FERR_OK; - - flmAssert( m_pFile); - - // Do nothing if logging is disabled. Also, ignore - // these packets if we are operating on a pre-4.3 - // database. - - if (m_bLoggingOff || - m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; - } - - // Better be in the middle of logging unknown stuff - // for the application - - flmAssert( m_bLoggingUnknown); - if (m_uiUnknownPacketLen > RFL_PACKET_OVERHEAD) - { - if (RC_BAD( rc = finishPacket( RFL_UNKNOWN_PACKET, - m_uiUnknownPacketLen - RFL_PACKET_OVERHEAD, - FALSE))) - { - goto Exit; - } - } - -Exit: - m_bLoggingUnknown = FALSE; - m_uiUnknownPacketLen = RFL_PACKET_OVERHEAD; - return( rc); -} - -/******************************************************************** -Desc: Log a reduce packet -*********************************************************************/ -RCODE F_Rfl::logReduce( - FLMUINT uiTransID, - FLMUINT uiCount) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // This call is new with 4.3 databases - not supported in older - // versions, so don't log it. - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; - } - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // We need to set up to log this packet as if we - // were logging a transaction. The only difference - // is that we don't log the begin transaction packet. - - if( RC_BAD( rc = setupTransaction())) - { - goto Exit; - } - - uiPacketBodyLen = 8; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)uiTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the count - - UD2FBA( (FLMUINT32)uiCount, pucPacketBody); - pucPacketBody += 4; - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_REDUCE_PACKET, uiPacketBodyLen, - TRUE))) - { - goto Exit; - } - - // Finalize the transaction (as if we were committing a transaction) - - finalizeTransaction(); - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Log a database conversion packet -Note: This routine performs most of the setup for logging a full - transaction, but it does not cause begin and commit packets - to be logged. It is a "standalone" transaction. -*********************************************************************/ -RCODE F_Rfl::logUpgrade( - FLMUINT uiTransID, - FLMUINT uiOldVersion, - FLMBYTE * pucDBKey, - FLMUINT32 ui32DBKeyLen) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // We need to set up to log this packet as if we - // were logging a transaction. The only difference - // is that we don't log the begin transaction packet. - - if( RC_BAD( rc = setupTransaction())) - { - goto Exit; - } - - uiPacketBodyLen = 14 + ui32DBKeyLen; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID - - UD2FBA( (FLMUINT32)uiTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the old database version - - UD2FBA( (FLMUINT32)uiOldVersion, pucPacketBody); - pucPacketBody += 4; - - // Output the new database version - - UD2FBA( (FLMUINT32)FLM_CURRENT_VERSION_NUM, pucPacketBody); - pucPacketBody += 4; - - // For versions >= 4.60, the next two bytes will give the length of the DB Key. - - flmAssert( ui32DBKeyLen <= 0xFFFF); - UW2FBA( (FLMUINT16)ui32DBKeyLen, pucPacketBody); - pucPacketBody += 2; - - // If we were built without encryption, the key length will be zero, so no need to - // store the key. - - if (ui32DBKeyLen) - { - f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); - pucPacketBody += ui32DBKeyLen; - } - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_UPGRADE_PACKET, uiPacketBodyLen, - TRUE))) - { - goto Exit; - } - - // Finalize the transaction (as if we were committing a transaction) - - finalizeTransaction(); - -Exit: - - if( !m_bLoggingOff) - { - m_uiCurrTransID = 0; - } - - return( rc); -} - -/******************************************************************** -Public: logWrappedKey -Desc: Log the wrapped database key -*********************************************************************/ -RCODE F_Rfl::logWrappedKey( - FLMUINT uiTransID, - FLMBYTE * pucDBKey, - FLMUINT32 ui32DBKeyLen - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - if ( RC_BAD( rc = setupTransaction())) - { - goto Exit; - } - - uiPacketBodyLen = 6 + ui32DBKeyLen; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID - - UD2FBA( (FLMUINT32)uiTransID, pucPacketBody); - pucPacketBody += 4; - - // The next two bytes will give the length of the DB Key. - - flmAssert( ui32DBKeyLen <= 0xFFFF); - UW2FBA( (FLMUINT16)ui32DBKeyLen, pucPacketBody); - pucPacketBody += 2; - - // If we were built without encryption, the key length will be zero, so no need to - // store the key. - - if (ui32DBKeyLen) - { - f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); - pucPacketBody += ui32DBKeyLen; - } - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_WRAP_KEY_PACKET, - uiPacketBodyLen, - TRUE))) - { - goto Exit; - } - - finalizeTransaction(); - -Exit: - - return( rc); -} - -/******************************************************************** -Public: logEnableEncryption -Desc: Log that we have enabled encryption -*********************************************************************/ -RCODE F_Rfl::logEnableEncryption( - FLMUINT uiTransID, - FLMBYTE * pucDBKey, - FLMUINT32 ui32DBKeyLen - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - if ( RC_BAD( rc = setupTransaction())) - { - goto Exit; - } - - uiPacketBodyLen = 6 + ui32DBKeyLen; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID - - UD2FBA( (FLMUINT32)uiTransID, pucPacketBody); - pucPacketBody += 4; - - // The next two bytes will give the length of the DB Key. - - flmAssert( ui32DBKeyLen <= 0xFFFF); - UW2FBA( (FLMUINT16)ui32DBKeyLen, pucPacketBody); - pucPacketBody += 2; - - // If we were built without encryption, the key length will be zero, so no need to - // store the key. - - if (ui32DBKeyLen) - { - f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); - pucPacketBody += ui32DBKeyLen; - } - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_ENABLE_ENCRYPTION_PACKET, - uiPacketBodyLen, - TRUE))) - { - goto Exit; - } - - finalizeTransaction(); - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Reads a full packet, based on what file offset and read - offset are currently set to. -*********************************************************************/ -RCODE F_Rfl::readPacket( - FLMUINT uiMinBytesNeeded - ) -{ - RCODE rc = FERR_OK; - FLMUINT uiTmpOffset; - FLMUINT uiReadLen; - FLMUINT uiBytesRead; - - // If we have enough bytes in the buffer for the minimum bytes - // needed, we don't need to retrieve any more bytes. - - if (m_pCurrentBuf->uiRflBufBytes - m_uiRflReadOffset >= uiMinBytesNeeded) - { - goto Exit; - } - - // If we are doing restore, we have to do only sequential - // reads - cannot depend on doing reads on 512 byte boundaries. - // Otherwise, we read directly from disk on 512 byte boundaries. - - if (m_pRestore) - { - FLMUINT uiCurrFilePos = m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes; - - if (m_uiRflReadOffset > 0) - { - - // Move the bytes left in the buffer down to the beginning - // of the buffer. - - f_memmove( m_pCurrentBuf->pIOBuffer->m_pucBuffer, - &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[ m_uiRflReadOffset]), - m_pCurrentBuf->uiRflBufBytes - m_uiRflReadOffset); - m_pCurrentBuf->uiRflBufBytes -= m_uiRflReadOffset; - m_pCurrentBuf->uiRflFileOffset += m_uiRflReadOffset; - m_uiRflReadOffset = 0; - } - uiReadLen = m_uiBufferSize - m_pCurrentBuf->uiRflBufBytes; - - // Read enough to fill the rest of the buffer, which is - // guaranteed to hold at least one full packet. - - if (!m_uiFileEOF) - { - if (uiCurrFilePos > (FLMUINT)(-1) - uiReadLen) - { - uiReadLen = (FLMUINT)(-1) - uiCurrFilePos; - } - } - else - { - if (uiCurrFilePos + uiReadLen > m_uiFileEOF) - { - uiReadLen = m_uiFileEOF - uiCurrFilePos; - } - } - - // If reading will not give us the minimum bytes needed, - // we cannot satisfy this request from the current file. - - if (uiReadLen + m_pCurrentBuf->uiRflBufBytes < uiMinBytesNeeded) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Read enough to get the entire packet. - - if (RC_BAD( rc = m_pRestore->read( uiReadLen, - &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[ m_pCurrentBuf->uiRflBufBytes]), - &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - rc = FERR_OK; - } - else - { - goto Exit; - } - } - - // If we didn't read enough to satisfy the minimum bytes needed, - // we cannot satisfy this request from the current file. - - if (uiBytesRead + m_pCurrentBuf->uiRflBufBytes < uiMinBytesNeeded) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - m_pCurrentBuf->uiRflBufBytes += uiBytesRead; - } - else - { - - // Set offsets so we are on a 512 byte boundary for our - // next read. No need to move data, since we will be - // re-reading it anyway. - - if (m_uiRflReadOffset > 0) - { - uiTmpOffset = m_uiRflReadOffset - (m_uiRflReadOffset & 511); - m_pCurrentBuf->uiRflFileOffset += uiTmpOffset; - m_uiRflReadOffset -= uiTmpOffset; - } - else if (m_pCurrentBuf->uiRflFileOffset & 511) - { - m_uiRflReadOffset = m_pCurrentBuf->uiRflFileOffset & 511; - m_pCurrentBuf->uiRflFileOffset -= m_uiRflReadOffset; - } - m_pCurrentBuf->uiRflBufBytes = 0; - - // Read enough to fill the rest of the buffer, which is - // guaranteed to hold at least one full packet. - - uiReadLen = m_uiBufferSize; - - // m_uiFileEOF better not be zero at this point - we should - // always know precisely where the RFL file ends when we - // are doing recovery as opposed to doing a restore. - - flmAssert( m_uiFileEOF >= 512); - if (m_pCurrentBuf->uiRflFileOffset + uiReadLen > m_uiFileEOF) - { - uiReadLen = m_uiFileEOF - m_pCurrentBuf->uiRflFileOffset; - } - - // If reading will not give us the minimum number of bytes - // needed, we have a bad packet. - - if (uiReadLen < m_uiRflReadOffset || - uiReadLen - m_uiRflReadOffset < uiMinBytesNeeded) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Read to get the entire packet. - - if (RC_BAD( rc = m_pFileHdl->SectorRead( m_pCurrentBuf->uiRflFileOffset, - uiReadLen, m_pCurrentBuf->pIOBuffer->m_pucBuffer, - &uiBytesRead))) - { - if (rc == FERR_IO_END_OF_FILE) - { - rc = FERR_OK; - } - else - { - m_bRflVolumeOk = FALSE; - goto Exit; - } - } - if (uiBytesRead < uiReadLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - m_pCurrentBuf->uiRflBufBytes = uiReadLen; - } -Exit: - return( rc); -} - -/******************************************************************** -Desc: Gets and verifies the next packet from the roll-forward - log file. Packet checksum will be verified. -*********************************************************************/ -RCODE F_Rfl::getPacket( - FLMBOOL bForceNextFile, - FLMUINT * puiPacketTypeRV, - FLMBYTE ** ppucPacketBodyRV, - FLMUINT * puiPacketBodyLenRV, - FLMBOOL * pbLoggedTimes - ) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacket; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketType; - FLMUINT uiEncryptPacketBodyLen; - FLMBYTE ucHdr [512]; - FLMUINT uiBytesRead; - - // See if we need to go to the next file. Note that we only - // check for this exactly on packet boundaries. We do not expect - // packets to be split across files. If we are not at the end - // of processing what is in the buffer, we should be able to - // read the rest of the packet from the current file. - -Get_Next_File: - if (bForceNextFile || - (m_uiFileEOF && m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && - m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes == - m_uiFileEOF)) - { - if( m_bKeepRflFiles) - { - if (!m_pRestore) - { - - // Only doing recovery after a failure, see if we are at - // the last file already. - - if (m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) - { - rc = RC_SET( FERR_END); - goto Exit; - } - else if( (m_pCurrentBuf->uiCurrFileNum + 1 ) == - m_uiLastRecoverFileNum && - !(FLMUINT)FB2UD( &m_pFile->ucLastCommittedLogHdr[ - LOG_RFL_LAST_TRANS_OFFSET])) - { - // We are going to try to open the last file. Since the log header - // shows a current offset of 0, the file may have been created but - // nothing was logged to it. We don't want to try to open - // it here because it may not have been initialized fully - // at the time of the server crash. - - m_pCurrentBuf->uiCurrFileNum = m_uiLastRecoverFileNum; - rc = RC_SET( FERR_END); - goto Exit; - } - - // Open the next file in the sequence. - - if (RC_BAD( rc = openFile( m_pCurrentBuf->uiCurrFileNum + 1, - m_ucNextSerialNum))) - { - if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) - { - rc = RC_SET( FERR_END); - } - goto Exit; - } - - // If this is the last RFL file, the EOF is contained - // in the log header. Otherwise, it will be in the RFL - // file's header, and openFile will already have retrieved it. - - if (m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) - { - m_uiFileEOF = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - // Could be zero if RFL file wasn't created yet. - - if (!m_uiFileEOF) - { - m_uiFileEOF = 512; - } - } - - // By this point, the EOF better be greater than or equal to 512. - - flmAssert( m_uiFileEOF >= 512); - } - else - { - if( RC_BAD( rc = m_pRestore->close())) - { - goto Exit; - } - - // Ask the recovery object to open the file. - - if (RC_BAD( rc = m_pRestore->openRflFile( - m_pCurrentBuf->uiCurrFileNum + 1))) - { - if (rc == FERR_IO_PATH_NOT_FOUND) - { - rc = RC_SET( FERR_END); - } - goto Exit; - } - - // Get the first 512 bytes from the file and verify the header. - - if (RC_BAD( rc = m_pRestore->read( 512, ucHdr, &uiBytesRead))) - { - goto Exit; - } - if (uiBytesRead < 512) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - if (RC_BAD( rc = verifyHeader( ucHdr, - m_pCurrentBuf->uiCurrFileNum + 1, - m_ucNextSerialNum))) - { - goto Exit; - } - - // We may not know the actual EOF of files during restore operations. - // m_uiFileEOF could be zero here. - - m_uiFileEOF = (FLMUINT)FB2UD( &ucHdr [RFL_EOF_POS]); - - // File EOF may be zero or >= 512 at this point. - - flmAssert( !m_uiFileEOF || m_uiFileEOF >= 512); - - // Need to increment current file number. - - m_pCurrentBuf->uiCurrFileNum++; - } - m_pCurrentBuf->uiRflFileOffset = 512; - m_uiRflReadOffset = 0; - m_pCurrentBuf->uiRflBufBytes = 0; - - // Get the next packet from the new file. - - if (RC_BAD( rc = readPacket( RFL_PACKET_OVERHEAD))) - { - if (m_uiFileEOF == 512 && m_bKeepRflFiles) - { - - // File was empty, try to go to the next file. - - bForceNextFile = TRUE; - goto Get_Next_File; - } - goto Exit; - } - } - else - { - // This is the case where we are not keeping the RFL files. - // So, there is no next file to go to. If we get to this - // point, we had better not be doing a restore. - - flmAssert( m_pRestore == NULL && !bForceNextFile); - rc = RC_SET( FERR_END); - goto Exit; - } - } - - // Make sure we at least have a packet header in the buffer. - - if (RC_BAD( rc = readPacket( RFL_PACKET_OVERHEAD))) - { - goto Exit; - } - - // Verify the packet address. - - m_uiPacketAddress = m_pCurrentBuf->uiRflFileOffset + m_uiRflReadOffset; - pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[m_uiRflReadOffset]); - if ((FLMUINT)FB2UD( &pucPacket [RFL_PACKET_ADDRESS_OFFSET]) != - m_uiPacketAddress) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Get packet type, time flag, and packet body length - - *puiPacketTypeRV = - uiPacketType = RFL_GET_PACKET_TYPE( pucPacket [RFL_PACKET_TYPE_OFFSET]); - - if( pbLoggedTimes) - { - *pbLoggedTimes = - (pucPacket [RFL_PACKET_TYPE_OFFSET] & RFL_TIME_LOGGED_FLAG) - ? TRUE - : FALSE; - } - - *puiPacketBodyLenRV = - (FLMUINT)FB2UW( &pucPacket [RFL_PACKET_BODY_LENGTH_OFFSET]); - - // Adjust the packet body length for encryption if necessary. - // NOTE: This adjusted length is NOT returned to the caller. - // The actual body length is what will be returned. - - uiEncryptPacketBodyLen = getEncryptPacketBodyLen( uiPacketType, - *puiPacketBodyLenRV); - - // Make sure we have the entire packet in the buffer. - - if (RC_BAD( rc = readPacket( uiEncryptPacketBodyLen + RFL_PACKET_OVERHEAD))) - { - goto Exit; - } - pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[m_uiRflReadOffset]); - - // At this point, we are guaranteed to have the entire packet - // in the buffer. - - *ppucPacketBodyRV = - pucPacketBody = &pucPacket [RFL_PACKET_OVERHEAD]; - - // Validate the packet checksum - - if (RflCalcChecksum( pucPacket, uiEncryptPacketBodyLen) != - pucPacket [RFL_PACKET_CHECKSUM_OFFSET]) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if (uiPacketType == RFL_TRNS_BEGIN_PACKET || - uiPacketType == RFL_TRNS_BEGIN_EX_PACKET || - uiPacketType == RFL_UPGRADE_PACKET || - uiPacketType == RFL_REDUCE_PACKET || - uiPacketType == RFL_WRAP_KEY_PACKET || - uiPacketType == RFL_ENABLE_ENCRYPTION_PACKET) - { - // Current transaction ID better be zero, otherwise, we - // have two or more begin packets in a row. - - if (m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - m_uiCurrTransID = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - // Make sure the transaction numbers are ascending - - if (m_uiCurrTransID <= m_uiLastTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if( uiPacketType == RFL_TRNS_BEGIN_EX_PACKET) - { - FLMUINT uiLastLoggedCommitTransID; - - // Skip past seconds - - pucPacketBody += 4; - - uiLastLoggedCommitTransID = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - if( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_31 && - m_uiLastLoggedCommitTransID != uiLastLoggedCommitTransID) - { - rc = RC_SET( FERR_RFL_TRANS_GAP); - goto Exit; - } - } - } - else - { - - // If transaction ID is not zero, we are not inside a - // transaction, and it is likely that we have a corrupt - // packet. - - if (!m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Decrypt the packet if it is a packet type that was - // encrypted. - - if (uiPacketType == RFL_TRNS_COMMIT_PACKET || - uiPacketType == RFL_TRNS_ABORT_PACKET) - { - if( (FLMUINT)FB2UD( pucPacketBody) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - } - - // Set read offset to beginning of next packet. - - m_uiRflReadOffset += (RFL_PACKET_OVERHEAD + uiEncryptPacketBodyLen); -Exit: - return( rc); -} - -/******************************************************************** -Desc: Get a record from the packets in the roll-forward log. - This expects a series of RFL_DATA_RECORD_PACKETs. -*********************************************************************/ -RCODE F_Rfl::getRecord( - FDB * pDb, - FLMUINT uiPacketType, - FLMBYTE * pucPacketBody, - FLMUINT uiPacketBodyLen, - FlmRecord * pRecord) -{ - RCODE rc = FERR_OK; - FLMUINT uiTagNum; - FLMUINT uiDataType; - FLMUINT uiLevel; - FLMUINT uiDataLen; - FLMBYTE * pucFieldData = NULL; - void * pvField; - FLMBOOL bEncrypted = FALSE; - FLMUINT uiEncId = 0; - FLMUINT uiEncDataLen = 0; - POOL pool; - - - GedPoolInit( &pool, 512); - - // Go into a loop processing packets until we have retrieved - // all of the fields of the record. At that point, we - // had better be at the end of the record. - - for (;;) - { - - // If we don't currently have a packet, get one - // Packet type had better be RFL_DATA_RECORD_PACKET or - // RFL_ENC_DATA_RECORD_PACKET. - - if (!uiPacketBodyLen) - { - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - if (uiPacketType != RFL_DATA_RECORD_PACKET && - uiPacketType != RFL_ENC_DATA_RECORD_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - - // Packet body length better be at least two or we - // have an incomplete packet - we need to at least - // be able to get the tag number at this point. - - if (uiPacketBodyLen < 2) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - else if (uiPacketBodyLen == 2) - { - - // If the packet body length is only two, we - // had better be at the end of the record with - // a tag number of zero. Otherwise, we have - // an incomplete packet. - - if ((uiTagNum = (FLMUINT)FB2UW( pucPacketBody))!= 0) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - break; - } - else if (uiPacketType == RFL_DATA_RECORD_PACKET) - { - if (uiPacketBodyLen < 6) - { - // If we have a packet body length less than - // six (for RFL_DATA_RECORD_PACKETs), - // we have an incomplete field header. - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - else if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) - { - // This type of packet is only valid with versions of flaim >= 4.60 - flmAssert( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_60); - - if (uiPacketBodyLen < 7) - { - // If we have a packet body length less than - // seven we have an incomplete field header. - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - - // At this point, we have a packet body length that - // is greater than or equal to seven (or six), meaning we could - // not possibly be on the last field of the record. - // Hence, a zero tag number is invalid here. - - if ((uiTagNum = (FLMUINT)FB2UW( pucPacketBody)) == 0) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 2; - uiDataType = *pucPacketBody++; - uiLevel = *pucPacketBody++; - uiDataLen = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiPacketBodyLen -= 6; - - // If the database version supports encryption, - // we need to check for it. - if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) - { - bEncrypted = (FLMBOOL)*pucPacketBody++; - --uiPacketBodyLen; - - if (bEncrypted) - { - if (uiPacketBodyLen < 4) - { - flmAssert( 0); - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Extract the encryption ID and the encrypted length. - uiEncId = FB2UW( pucPacketBody); - pucPacketBody += 2; - - uiEncDataLen = FB2UW( pucPacketBody); - pucPacketBody += 2; - - uiPacketBodyLen -= 4; - } - } - - // Create a new field. - - if (RC_BAD( rc = pRecord->insertLast( uiLevel, uiTagNum, - uiDataType, &pvField))) - { - goto Exit; - } - - if (!bEncrypted && uiDataLen) - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - uiDataType, - uiDataLen, - 0, 0, 0, - &pucFieldData, - NULL))) - { - goto Exit; - } - - while (uiDataLen) - { - if (uiDataLen > uiPacketBodyLen) - { - f_memcpy( pucFieldData, pucPacketBody, uiPacketBodyLen); - pucFieldData += uiPacketBodyLen; - pucPacketBody += uiPacketBodyLen; - uiDataLen -= uiPacketBodyLen; - - uiPacketBodyLen = 0; - - // Get the next packet. Packet type had better - // be RFL_DATA_RECORD_PACKET or RFL_ENC_DATA_RECORD_PACKET - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - if (uiPacketType != RFL_DATA_RECORD_PACKET && - uiPacketType != RFL_ENC_DATA_RECORD_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - else - { - f_memcpy( pucFieldData, pucPacketBody, uiDataLen); - pucFieldData += uiDataLen; - uiPacketBodyLen -= uiDataLen; - pucPacketBody += uiDataLen; - uiDataLen = 0; - } - } - pucFieldData = NULL; - } - else if (bEncrypted) - { - FLMBYTE * pucEncFieldData; - - if (uiEncDataLen) - { - if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, - uiDataType, - uiDataLen, - uiEncDataLen, - uiEncId, - FLD_HAVE_ENCRYPTED_DATA, - &pucFieldData, - &pucEncFieldData))) - { - goto Exit; - } - } - - while (uiEncDataLen) - { - if (uiEncDataLen > uiPacketBodyLen) - { - f_memcpy( pucEncFieldData, pucPacketBody, uiPacketBodyLen); - pucEncFieldData += uiPacketBodyLen; - pucPacketBody += uiPacketBodyLen; - uiEncDataLen -= uiPacketBodyLen; - - uiPacketBodyLen = 0; - - // Get the next packet. Packet type had better - // be RFL_ENC_DATA_RECORD_PACKET. - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - if (uiPacketType != RFL_ENC_DATA_RECORD_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - else - { - f_memcpy( pucEncFieldData, pucPacketBody, uiEncDataLen); - pucEncFieldData += uiEncDataLen; - uiPacketBodyLen -= uiEncDataLen; - pucPacketBody += uiEncDataLen; - uiEncDataLen = 0; - } - } - pucEncFieldData = NULL; - - if (!m_pFile->bInLimitedMode) - { - if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, - pvField, uiEncId, &pool))) - { - goto Exit; - } - } - } - } - -Exit: - - GedPoolFree( &pool); - - return( rc); -} - -/******************************************************************** -Desc: Modify a record using RFL_DATA_RECORD_PACKETs or - RFL_CHANGE_FIELD_PACKETs. -*********************************************************************/ -RCODE F_Rfl::modifyRecord( - HFDB hDb, - FlmRecord * pRecord) -{ - RCODE rc = FERR_OK; - FLMUINT uiPacketType; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - FLMUINT uiChangeType; - FLMUINT uiPosition; - FLMUINT uiTagNum = 0; - FLMUINT uiDataType = 0; - FLMUINT uiLevel = 0; - FLMUINT uiDataLen = 0; - FLMBYTE * pucData; - FLMBYTE * pucEncData; - FDB * pDb = (FDB *)hDb; - FLMBOOL bEncrypted = FALSE; - FLMUINT uiEncDataLen; - FLMUINT uiEncId; - FLMUINT uiFlags; - FlmField * pField; - FLMUINT uiCurPos = 1; - void * pvField; - - // Get the first packet and see what it is. - // If it is an RFL_DATA_RECORD_PACKET, just - // call Rfl3GetRecord to get the entire new - // record. - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - if (uiPacketType == RFL_DATA_RECORD_PACKET || - uiPacketType == RFL_ENC_DATA_RECORD_PACKET) - { - pRecord->clear(); - rc = getRecord( pDb, uiPacketType, pucPacketBody, - uiPacketBodyLen, pRecord); - goto Exit; - } - else if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Go into a loop processing packets until we have processed - // all of the changed fields for the record. - - pField = pRecord->getFieldPointer( pRecord->root()); - - flmAssert( pField); - - for (;;) - { - - uiEncDataLen = 0; - uiEncId = 0; - - // If we don't currently have a packet, get one - // Packet type had better be RFL_CHANGE_FIELDS_PACKET. - - if (!uiPacketBodyLen) - { - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - - // Packet body length better be at least three or we - // have an incomplete packet - we need to at least - // be able to get the type of change and the absolute - // position of the change. - - if (uiPacketBodyLen < 3) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // Get the change type and the absolute position where - // the change is to be put. A position of zero is - // illegal. - - uiChangeType = *pucPacketBody++; - uiPosition = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiPacketBodyLen -= 3; - - if (uiChangeType == RFL_END_FIELD_CHANGES) - { - - // If we are not at the end of the packet, it must - // be a bad packet. Also, uiPosition should be - // a zero for this packet. - - if (uiPacketBodyLen || uiPosition) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - break; - } - - // If not RFL_END_FIELD_CHANGES, a position of - // zero is illegal. - - if (!uiPosition) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - switch (uiChangeType) - { - case RFL_INSERT_FIELD: - case RFL_INSERT_ENC_FIELD: - { - if (uiPacketBodyLen < 6) - { - - // If the change type is insert field and there are - // not at least six bytes in the packet, we have - // a problem. - - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - uiTagNum = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiDataType = *pucPacketBody++; - uiLevel = *pucPacketBody++; - uiDataLen = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiPacketBodyLen -= 6; - bEncrypted = (uiChangeType == RFL_INSERT_FIELD ? FALSE : TRUE); - if (bEncrypted) - { - if (uiPacketBodyLen < 4) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiEncId = FB2UW(pucPacketBody); - pucPacketBody += 2; - - uiEncDataLen = FB2UW( pucPacketBody); - pucPacketBody += 2; - - uiPacketBodyLen -= 4; - } - break; - } - - case RFL_MODIFY_FIELD: - case RFL_MODIFY_ENC_FIELD: - { - // Packet better have at least three bytes and the first - // byte had better be RFL_REPLACE_BYTES. - - if (uiPacketBodyLen < 3 || - *pucPacketBody != RFL_REPLACE_BYTES) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody++; - uiDataLen = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - - bEncrypted = (uiChangeType == RFL_MODIFY_FIELD ? FALSE : TRUE); - uiPacketBodyLen -= 3; - - if (bEncrypted) - { - if (uiPacketBodyLen < 4) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiEncId = FB2UW(pucPacketBody); - pucPacketBody += 2; - - uiEncDataLen = FB2UW( pucPacketBody); - pucPacketBody += 2; - - uiPacketBodyLen -= 4; - } - - break; - } - - case RFL_DELETE_FIELD: - { - break; - } - - default: - { - // Bad change type in packet. - - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } // Switch - - // Now position to the target field. - - switch (uiChangeType) - { - case RFL_DELETE_FIELD: - case RFL_MODIFY_FIELD: - case RFL_MODIFY_ENC_FIELD: - { - while ( uiCurPos != uiPosition) - { - if (uiPosition < uiCurPos) - { - flmAssert( pField->uiPrev); - pField = pRecord->prevField( pField); - --uiCurPos; - } - else - { - flmAssert( pField->uiNext); - pField = pRecord->nextField( pField); - uiCurPos++; - } - } - - if (uiChangeType != RFL_DELETE_FIELD) - { - // Get the data type ... not supplied in the modify field packet. - uiDataType = pRecord->getFieldDataType( pField); - uiTagNum = pField->ui16FieldID; - } - - break; - } - - case RFL_INSERT_FIELD: - case RFL_INSERT_ENC_FIELD: - { - FlmField * pNewField; - - // On insert, we may be trying to position to a field that does not exist yet. - // Therefore we need to position to the field prior to the field position we want to insert. - - flmAssert( uiPosition > 1); // cannot insert at the root position. - - while ( uiCurPos != uiPosition - 1) - { - if (uiPosition - 1 < uiCurPos) - { - flmAssert( pField->uiPrev); - pField = pRecord->prevField( pField); - --uiCurPos; - } - else - { - flmAssert( pField->uiNext); - pField = pRecord->nextField( pField); - uiCurPos++; - } - } - - // Insert the new field at the specified position and - // get back a new field to use later. - - if( RC_BAD( rc = pRecord->createField( pField, &pNewField))) - { - goto Exit; - } - - if( RC_BAD( rc = pRecord->setFieldLevel( pNewField, uiLevel))) - { - goto Exit; - } - - pField = pNewField; - pField->ui16FieldID = (FLMUINT16)uiTagNum; - uiCurPos++; // Bump the position as we have just added a new field and - // we are positioned on it. - - break; - } - } - - if (uiChangeType == RFL_DELETE_FIELD) - { - // Remove the specified field or subtree - pvField = (void *)((FLMUINT)(pField->uiPrev)); - --uiCurPos; - if (!pvField) - { - pvField = pRecord->root(); - uiCurPos = 1; - } - - // For versions 4.60 and greater, the interpretation for - // RFL_DELETE_FIELD is to delete the entire sub-tree. - // Prior to that, it is to delete only a single field. - - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_60) - { - if (RC_BAD( rc = pRecord->remove( pField))) - { - goto Exit; - } - } - else - { - - // Passing in the same pointer to removeFields will effectively - // delete just pField. - - if (RC_BAD( rc = pRecord->removeFields( pField, pField))) - { - goto Exit; - } - } - - // We need to reset our pField. - pField = pRecord->getFieldPointer( pvField); - - continue; // Next field... - } - - // Both insert & modify need to have space allocated. - - if (bEncrypted) - { - uiFlags = FLD_HAVE_ENCRYPTED_DATA; - } - else - { - uiFlags = 0; - } - - flmAssert( pField); - - // Allocate space for the data. We call this even if uiDataLen is - // zero so that the appropriate data type will be set in the node - // as well. - - // Before we allocate storage space, save the field offset. The - // field buffer may get reallocated, resulting in a nwe address - // for pField. - pvField = pRecord->getFieldVoid( pField); - if (RC_BAD( rc = pRecord->getNewDataPtr( - pField, - uiDataType, - uiDataLen, - uiEncDataLen, - uiEncId, - uiFlags, - &pucData, - &pucEncData))) - { - goto Exit; - } - pField = pRecord->getFieldPointer( pvField); - - // Get the data for insert or modify, if any - - if (bEncrypted) - { - while (uiEncDataLen) - { - if (uiEncDataLen > uiPacketBodyLen) - { - f_memcpy( pucEncData, pucPacketBody, uiPacketBodyLen); - pucEncData += uiPacketBodyLen; - uiEncDataLen -= uiPacketBodyLen; - uiPacketBodyLen = 0; - - // Get the next packet. Packet type had better - // be RFL_CHANGE_FIELDS_PACKET. - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - - if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - else - { - f_memcpy( pucEncData, pucPacketBody, uiEncDataLen); - pucEncData += uiEncDataLen; - uiPacketBodyLen -= uiEncDataLen; - pucPacketBody += uiEncDataLen; - uiEncDataLen = 0; - } - } - } - else // Not encrypted - { - while (uiDataLen) - { - if (uiDataLen > uiPacketBodyLen) - { - f_memcpy( pucData, pucPacketBody, uiPacketBodyLen); - pucData += uiPacketBodyLen; - uiDataLen -= uiPacketBodyLen; - uiPacketBodyLen = 0; - - // Get the next packet. Packet type had better - // be RFL_CHANGE_FIELDS_PACKET. - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, NULL))) - { - goto Exit; - } - - if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - } - else - { - f_memcpy( pucData, pucPacketBody, uiDataLen); - pucData += uiDataLen; - uiPacketBodyLen -= uiDataLen; - pucPacketBody += uiDataLen; - uiDataLen = 0; - } - } - } - - - // If this field is involved in an index, and it is encrypted, we need to - // make sure we decrypt it too. - // If it is not encrypted, we don't care if it involved in an index. - - if (bEncrypted && !(pDb->pFile->bInLimitedMode)) - { - IFD * pIfd; - - if( RC_BAD( rc = fdictGetField( pDb->pDict, uiTagNum, NULL, - &pIfd, NULL))) - { - goto Exit; - } - - if( pIfd) - { - if( RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, - pRecord->getFieldVoid(pField), uiEncId, &pDb->TempPool))) - { - goto Exit; - } - } - } - } - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Read the next operation from the roll-forward log. -*********************************************************************/ -RCODE F_Rfl::readOp( - FDB * pDb, - FLMBOOL bForceNextFile, - FLMUINT * puiOpRV, - FLMUINT * puiContainerRV, - FLMUINT * puiDrnRV, - FLMUINT * puiIndexRV, - FLMUINT * puiEndDrnRV, - FlmRecord * pRecord, - FLMUINT * puiTransIDRV, - FLMUINT * puiStartTimeRV, - FLMUINT * puiLastLoggedCommitTransIDRV, - FLMUINT * puiFlagsRV) -{ - RCODE rc = FERR_OK; - FLMUINT uiPacketType; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - FLMUINT uiExpectedBodyLen; - FLMUINT uiLastLoggedCommitTransID = 0; - FLMUINT uiTransId; - FLMUINT uiStartTime; - FLMUINT uiContainer; - FLMUINT uiDrn; - FLMUINT uiIndex; - FLMUINT uiEndDrn; - FLMUINT uiFlags = 0; - FLMBOOL bLoggedTimes; - - // Get the next packet. - - if (RC_BAD( rc = getPacket( bForceNextFile, &uiPacketType, &pucPacketBody, - &uiPacketBodyLen, &bLoggedTimes))) - { - goto Exit; - } - - // Must be one of our packet types that represents - // an operation. - - uiTransId = 0; - uiStartTime = 0; - uiContainer = 0; - uiDrn = 0; - uiIndex = 0; - uiEndDrn = 0; - switch (uiPacketType) - { - case RFL_TRNS_BEGIN_PACKET: - { - uiExpectedBodyLen = 8; - if( bLoggedTimes) - { - uiExpectedBodyLen += 4; - } - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiStartTime = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - break; - } - - case RFL_TRNS_BEGIN_EX_PACKET: - { - uiExpectedBodyLen = 12; - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiStartTime = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiLastLoggedCommitTransID = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - break; - } - - case RFL_TRNS_COMMIT_PACKET: - case RFL_TRNS_ABORT_PACKET: - { - uiExpectedBodyLen = 8; - if( bLoggedTimes) - { - uiExpectedBodyLen += 8; - } - - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 8; - break; - } - - case RFL_ADD_RECORD_PACKET: - case RFL_MODIFY_RECORD_PACKET: - case RFL_DELETE_RECORD_PACKET: - case RFL_RESERVE_DRN_PACKET: - { - uiExpectedBodyLen = 10; - if( bLoggedTimes) - { - uiExpectedBodyLen += 16; - } - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - if ((uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - uiContainer = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - if( uiPacketType == RFL_ADD_RECORD_PACKET) - { - if (RC_BAD( rc = getRecord( pDb, 0, NULL, 0, pRecord))) - { - goto Exit; - } - } - break; - } - - case RFL_ADD_RECORD_PACKET_VER_2: - case RFL_MODIFY_RECORD_PACKET_VER_2: - case RFL_DELETE_RECORD_PACKET_VER_2: - { - uiExpectedBodyLen = 11; - if( bLoggedTimes) - { - uiExpectedBodyLen += 16; - } - - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if ((uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - - uiContainer = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - uiFlags = *pucPacketBody; - pucPacketBody++; - - // Translate the flags - - if( uiFlags) - { - FLMUINT uiTmp = 0; - - if( uiFlags & RFL_UPDATE_BACKGROUND) - { - uiTmp |= FLM_DO_IN_BACKGROUND; - } - - if( uiFlags & RFL_UPDATE_SUSPENDED) - { - uiTmp |= FLM_SUSPENDED; - } - - uiFlags = uiTmp; - } - - if( uiPacketType == RFL_ADD_RECORD_PACKET_VER_2) - { - if (RC_BAD( rc = getRecord( pDb, 0, NULL, 0, pRecord))) - { - goto Exit; - } - } - break; - } - - case RFL_INDEX_SET_PACKET: - case RFL_INDEX_SET_PACKET_VER_2: - { - uiExpectedBodyLen = - (FLMUINT)((uiPacketType == RFL_INDEX_SET_PACKET_VER_2) - ? (FLMUINT)16 - : (FLMUINT)14); - - if( bLoggedTimes) - { - uiExpectedBodyLen += 16; - } - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - if ((uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - if (uiPacketType == RFL_INDEX_SET_PACKET_VER_2) - { - uiContainer = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - } - uiIndex = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiEndDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - break; - } - - case RFL_START_UNKNOWN_PACKET: - { - uiExpectedBodyLen = 4; - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - if ((uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - break; - } - - case RFL_REDUCE_PACKET: - { - uiExpectedBodyLen = 8; - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - uiLastLoggedCommitTransID = uiTransId; - pucPacketBody += 4; - - // We will return the count in the uiDrn parameter - - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - break; - } - - case RFL_BLK_CHAIN_FREE_PACKET: - { - uiExpectedBodyLen = 16; - - if( bLoggedTimes) - { - uiExpectedBodyLen += 16; - } - - if( uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if( (uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - - // Tracker record ID - - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - // Count - - uiFlags = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - // Ending block address - - uiEndDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - - break; - } - - case RFL_INDEX_SUSPEND_PACKET: - case RFL_INDEX_RESUME_PACKET: - { - uiExpectedBodyLen = 6; - if (uiExpectedBodyLen != uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if ((uiTransId = (FLMUINT)FB2UD( pucPacketBody)) != m_uiCurrTransID) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - pucPacketBody += 4; - - uiIndex = (FLMUINT)FB2UW( pucPacketBody); - pucPacketBody += 2; - break; - } - - case RFL_UPGRADE_PACKET: - { - FLMUINT uiDBKeyLen; - - uiExpectedBodyLen = 12; - if (uiExpectedBodyLen > uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // We will return the current DB version in the uiDrn parameter - // and the new DB version will be returned in the uiEndDrn parameter - - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiPacketBodyLen -= 4; - uiDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiPacketBodyLen -= 4; - uiEndDrn = (FLMUINT)FB2UD( pucPacketBody); - pucPacketBody += 4; - uiPacketBodyLen -= 4; - - // Only look for the wrapping key if the new database version - // is greater than 4.60 and there isn't already a key. - if (uiEndDrn >= FLM_VER_4_60 && !m_pFile->pDbWrappingKey) - { - if (uiPacketBodyLen < 2) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiDBKeyLen = FB2UW( pucPacketBody); - pucPacketBody += 2; - uiPacketBodyLen -= 2; - if ( uiDBKeyLen) - { - if ( uiPacketBodyLen != uiDBKeyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - if ((m_pFile->pDbWrappingKey = f_new F_CCS) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - if (RC_BAD( rc = m_pFile->pDbWrappingKey->init( TRUE, - FLM_NICI_AES))) - { - goto Exit; - } - - if( RC_BAD( rc = m_pFile->pDbWrappingKey->setKeyFromStore( - pucPacketBody, (FLMUINT32)uiDBKeyLen, NULL, NULL, FALSE))) - { - goto Exit; - } - pucPacketBody += uiDBKeyLen; - uiPacketBodyLen -= uiDBKeyLen; - flmAssert( !uiPacketBodyLen); - } - } - break; - } - - case RFL_WRAP_KEY_PACKET: - case RFL_ENABLE_ENCRYPTION_PACKET: - { - FLMUINT uiDBKeyLen; - FLMBYTE * pucUncommittedLogHdr = &m_pFile->ucUncommittedLogHdr [0]; - eRestoreActionType eRestoreAction; - - uiExpectedBodyLen = 6; - if (uiExpectedBodyLen >= uiPacketBodyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - uiTransId = (FLMUINT)FB2UD( pucPacketBody); - uiLastLoggedCommitTransID = uiTransId; - pucPacketBody += 4; - uiPacketBodyLen -= 4; - - if (uiPacketBodyLen < 2) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - uiDBKeyLen = FB2UW( pucPacketBody); - pucPacketBody += 2; - uiPacketBodyLen -= 2; - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - uiPacketType == RFL_WRAP_KEY_PACKET - ? RESTORE_WRAP_KEY - : RESTORE_ENABLE_ENCRYPTION, - uiTransId, - (void *)uiDBKeyLen, - (void *)0, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - m_uiCurrTransID = 0; - break; - } - } - - if ( uiDBKeyLen) - { - if ( uiPacketBodyLen != uiDBKeyLen) - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - goto Exit; - } - - // We cannot directly set the key at this point as it may be - // encrypted using a password, which we do not have here. We will - // write the key out to the log header and trust the user to know whether - // or not a password is needed to open the database. - - if (RC_BAD(rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, - 0, 0))) - { - goto Exit; - } - - f_memcpy( &pucUncommittedLogHdr[ LOG_DATABASE_KEY], pucPacketBody, uiDBKeyLen); - UW2FBA( uiDBKeyLen, &pucUncommittedLogHdr[ LOG_DATABASE_KEY_LEN]); - - if ( RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE))) - { - goto Exit; - } - - - pucPacketBody += uiDBKeyLen; - uiPacketBodyLen -= uiDBKeyLen; - flmAssert( !uiPacketBodyLen); - } - m_uiCurrTransID = 0; - - break; - } - - default: - { - flmAssert( 0); - rc = RC_SET( FERR_BAD_RFL_PACKET); - break; - } - } - - *puiOpRV = uiPacketType; - *puiContainerRV = uiContainer; - *puiDrnRV = uiDrn; - *puiIndexRV = uiIndex; - *puiEndDrnRV = uiEndDrn; - *puiTransIDRV = uiTransId; - *puiStartTimeRV = uiStartTime; - *puiLastLoggedCommitTransIDRV = uiLastLoggedCommitTransID; - *puiFlagsRV = uiFlags; - -Exit: - - return( rc); -} - -/******************************************************************** -Desc: Reads through unknown packets. -*********************************************************************/ -RCODE F_Rfl::readUnknown( - FLMUINT uiLenToRead, - FLMBYTE * pucBuffer, - FLMUINT * puiBytesRead) -{ - RCODE rc = FERR_OK; - FLMUINT uiPacketType; - FLMUINT uiBytesRead = 0; - FLMUINT uiBytesToCopy; - - // If we have read through all of the unknown packets, - // return FERR_EOF_HIT. - - if (!m_bReadingUnknown) - { - rc = RC_SET( FERR_EOF_HIT); - goto Exit; - } - - // Process packets until we have satisfied the read request or - // until we run out of unknown packets. - - while (uiLenToRead) - { - - // Get a packet, if we don't have one. - - if (!m_uiUnknownPacketBodyLen) - { - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, - &m_pucUnknownPacketBody, - &m_uiUnknownPacketBodyLen, NULL))) - { - m_bReadingUnknown = FALSE; - m_uiUnknownPacketRc = rc; - goto Exit; - } - if (uiPacketType != RFL_UNKNOWN_PACKET) - { - if (!uiBytesRead) - { - rc = RC_SET( FERR_EOF_HIT); - } - m_bReadingUnknown = FALSE; - - // At this point, we know that the entire packet is - // inside our memory buffer, so it is safe to reset - // m_uiRflReadOffset back to the beginning of the - // packet. The call to readOp() will call - // getPacket again, which will get this exact same - // packet for processing. - - m_uiRflReadOffset -= (RFL_PACKET_OVERHEAD + - m_uiUnknownPacketBodyLen); - goto Exit; - } - m_uiUnknownBodyLenProcessed = 0; - } - - uiBytesToCopy = uiLenToRead; - if (uiBytesToCopy > m_uiUnknownPacketBodyLen - m_uiUnknownBodyLenProcessed) - { - uiBytesToCopy = m_uiUnknownPacketBodyLen - m_uiUnknownBodyLenProcessed; - } - f_memcpy( pucBuffer, - m_pucUnknownPacketBody + m_uiUnknownBodyLenProcessed, - uiBytesToCopy); - pucBuffer += uiBytesToCopy; - uiLenToRead -= uiBytesToCopy; - uiBytesRead += uiBytesToCopy; - m_uiUnknownBodyLenProcessed += uiBytesToCopy; - - // If we have exhausted the current packet, reset things so that - // we will get a new packet the next time around. - - if (m_uiUnknownBodyLenProcessed == m_uiUnknownPacketBodyLen) - { - m_uiUnknownPacketBodyLen = 0; - m_uiUnknownBodyLenProcessed = 0; - m_pucUnknownPacketBody = NULL; - } - } - -Exit: - - *puiBytesRead = uiBytesRead; - return( rc); -} - -/******************************************************************** -Desc: Restore transactions from the roll-forward log to the - database. -*********************************************************************/ -RCODE F_Rfl::recover( - FDB * pDb, - F_Restore * pRestore) -{ - RCODE rc = FERR_OK; - FLMUINT uiStartFileNum; - FLMUINT uiStartOffset; - FLMUINT uiOffset; - FLMUINT uiReadLen; - FLMUINT uiBytesRead; - FLMBYTE ucHdr [512]; - FLMUINT uiOp; - FLMUINT uiContainer; - FLMUINT uiDrn; - FLMUINT uiIndex; - FLMUINT uiEndDrn; - FLMUINT uiStartTime; - FLMUINT uiCount; - FlmRecord * pRecord = NULL; - FlmRecord * pTmpRecord = NULL; - HFDB hDb = (HFDB)pDb; - FLMUINT uiTransId; - eRestoreActionType eRestoreAction; - FLMUINT uiLastLoggedCommitTransID; - FLMBOOL bTransActive = FALSE; - FLMBOOL bHadOperations = FALSE; - FLMBOOL bLastTransEndedAtFileEOF = FALSE; - FLMBOOL bForceNextFile; - FLMUINT uiOpFlags; - - flmAssert( m_pFile); - - m_pCurrentBuf = &m_Buf1; - m_uiLastLoggedCommitTransID = 0; - - // We need to allow all updates logged in the RFL - // (including dictionary updates). - pDb->bFldStateUpdOk = TRUE; - - // If we are less than version 4.3, we cannot do restore. - - if (pRestore && m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - goto Exit; - } - - // Turn off logging. - - m_bLoggingOff = TRUE; - - // Set the replay flag on the database. - - pDb->uiFlags |= FDB_REPLAYING_RFL; - - // Set the flag as to whether or not we are using multiple RFL files. - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_3) - { - m_bKeepRflFiles = FALSE; - } - else - { - m_bKeepRflFiles = m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] - ? TRUE - : FALSE; - } - - // If pRestore is NULL, we are doing a database recovery after - // open. In that case, we start from the last checkpoint offset - // and only run until the last transaction offset. - // - - if ((m_pRestore = pRestore) == NULL) - { - FLMBYTE * pucCheckSerialNum; - FLMUINT uiEndOffset; - - uiStartFileNum = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_CP_FILE_NUM]); - m_uiLastRecoverFileNum = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_FILE_NUM]); - uiStartOffset = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_CP_OFFSET]); - uiEndOffset = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - // Could be zero if the file was created, but no transactions were - // ever committed to it. - - if (!uiEndOffset) - { - uiEndOffset = 512; - } - - // Start offset better not be less than 512. - - flmAssert( uiStartOffset >= 512); - flmAssert( uiEndOffset >= 512); - - // If start and end are at the same place, there is nothing - // to recover. - - if (uiStartFileNum == m_uiLastRecoverFileNum && - uiStartOffset == uiEndOffset) - { - goto Finish_Recovery; - } - - // We have not recorded the serial number of the last checkpoint file - // number, so we pass in NULL, unless it happens to be the same as the - // last transaction file number, in which case we can pass in the - // serial number we have stored in the log header. - - pucCheckSerialNum = - (uiStartFileNum == m_uiLastRecoverFileNum) - ? &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM] - : NULL; - if (RC_BAD( rc = openFile( uiStartFileNum, pucCheckSerialNum))) - { - goto Exit; - } - - // If this is the last RFL file, the EOF is contained - // in the log header. Otherwise, it will be in the RFL - // file's header, and openFile will already have retrieved it. - - if (uiStartFileNum == m_uiLastRecoverFileNum) - { - m_uiFileEOF = uiEndOffset; - } - - // At this point, file EOF better be greater than or equal to 512. - - flmAssert( m_uiFileEOF >= 512); - } - else if (!m_bKeepRflFiles) - { - // FlmDbRestore should be checking the "keep" flag and not - // attempting to do a restore of the RFL. - - flmAssert( 0); - rc = RC_SET( FERR_CANNOT_RESTORE_RFL_FILES); - goto Exit; - } - else - { - uiStartFileNum = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_FILE_NUM]); - uiStartOffset = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - // Could be zero if the RFL file had never been created. - - if (!uiStartOffset) - { - uiStartOffset = 512; - } - - // Ask the recovery object to open the file. - -Retry_Open: - - flmAssert( uiStartFileNum); - if (RC_BAD( rc = m_pRestore->openRflFile( uiStartFileNum))) - { - if( rc == FERR_IO_PATH_NOT_FOUND) - { - // Need to set m_pCurrentBuf->uiCurrFileNum in case the first - // call to openRflFile fails. This will cause the code at the - // Finish_Recovery label to correctly set up the log - // header. - - if( !uiStartOffset) - { - m_pCurrentBuf->uiCurrFileNum = uiStartFileNum - 1; - } - else - { - m_pCurrentBuf->uiCurrFileNum = uiStartFileNum; - } - - rc = FERR_OK; - goto Finish_Recovery; - } - else - { - goto Exit; - } - } - - // Get the first 512 bytes from the file and verify the header. - - if (RC_BAD( rc = m_pRestore->read( 512, ucHdr, &uiBytesRead))) - { - goto Exit; - } - - if (uiBytesRead < 512) - { - rc = RC_SET( FERR_NOT_RFL); - goto Exit; - } - - if (RC_BAD( rc = verifyHeader( ucHdr, uiStartFileNum, - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM]))) - { - RCODE tmpRc; - - if (RC_BAD( tmpRc = m_pRestore->status( - RESTORE_ERROR, - 0, - (void *)((FLMUINT)rc), - (void *)0, - (void *)0, &eRestoreAction))) - { - rc = tmpRc; - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_RETRY) - { - if( RC_BAD( rc = m_pRestore->close())) - { - goto Exit; - } - goto Retry_Open; - } - goto Exit; - } - - // We may not know the actual EOF of files during restore operations. - - if ((m_uiFileEOF = (FLMUINT)FB2UD( &ucHdr [RFL_EOF_POS])) == 0) - { - bLastTransEndedAtFileEOF = TRUE; - } - else - { - bLastTransEndedAtFileEOF = (m_uiFileEOF == uiStartOffset) - ? TRUE - : FALSE; - } - - // Position to the start offset. Unfortunately, this means reading - // through the data and discarding it. - - uiOffset = 512; - while (uiOffset < uiStartOffset) - { - uiReadLen = (uiStartOffset - uiOffset); - if (uiReadLen > m_uiBufferSize) - { - uiReadLen = m_uiBufferSize; - } - if (RC_BAD( rc = m_pRestore->read( uiReadLen, - m_pCurrentBuf->pIOBuffer->m_pucBuffer, &uiBytesRead))) - { - goto Exit; - } - - // RFL file is incomplete if we could not read up to the last - // committed transaction. - - if (uiBytesRead < uiReadLen) - { - rc = RC_SET( FERR_RFL_INCOMPLETE); - goto Exit; - } - - uiOffset += uiBytesRead; - } - - // Need to set current file number - - m_pCurrentBuf->uiCurrFileNum = uiStartFileNum; - - // Better not be any transactions to recover - last database - // state needs to be a completed checkpoint. - - flmAssert( - FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_LAST_CP_TRANS_ID]) == - FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_CURR_TRANS_ID])); - - // Use uiStartOffset here instead of LOG_RFL_LAST_TRANS_OFFSET, - // because LOG_RFL_LAST_TRANS_OFFSET may be zero, but we in that - // case we should be comparing to 512, and uiStartOffset will have - // been adjusted to 512 if that is the case. - - flmAssert( - FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_CP_OFFSET]) == - uiStartOffset); - - flmAssert( - FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_CP_FILE_NUM]) == - uiStartFileNum); - } - - // Set last transaction ID to the last transaction - // that was checkpointed - transaction numbers should ascend - // from here. - - m_uiLastTransID = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_CP_TRANS_ID]); - - // Set the last committed trans ID if this is a 4.31+ database - - if( m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_31) - { - m_uiLastLoggedCommitTransID = (FLMUINT)FB2UD( - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]); - } - - m_pCurrentBuf->uiRflFileOffset = uiStartOffset; - m_uiRflReadOffset = 0; - m_pCurrentBuf->uiRflBufBytes = 0; - - - // Now, read until we are done. - - bForceNextFile = FALSE; - for (;;) - { - - if (!pRecord) - { - if( (pRecord = f_new FlmRecord) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - } - - // Get the next operation from the file. - - rc = readOp( pDb, bForceNextFile, - &uiOp, &uiContainer, &uiDrn, &uiIndex, - &uiEndDrn, pRecord, &uiTransId, - &uiStartTime, &uiLastLoggedCommitTransID, - &uiOpFlags); - bForceNextFile = FALSE; - - if (RC_BAD( rc)) - { -Handle_Packet_Error: - if (rc == FERR_END) - { - if (!m_pRestore) - { - - // If we didn't end exactly where we should have, we have - // an incomplete log. The same is true if we are in the - // middle of a transaction. - - if (m_pCurrentBuf->uiCurrFileNum != m_uiLastRecoverFileNum || - bTransActive) - { - rc = RC_SET( FERR_RFL_INCOMPLETE); - } - else - { - rc = FERR_OK; - goto Finish_Recovery; - } - } - else - { - - // If we are doing a restore, and we get to the end of the - // log, it is OK - even if we are in the middle of a - // transaction - the transaction will simply be aborted. - - rc = FERR_OK; - goto Finish_Recovery; - } - } - else if (rc == FERR_BAD_RFL_PACKET) - { - // If we don't know the current file size, and we - // are doing a restore, it is OK to end on a bad - // packet - we will simply abort the current - // transaction, if any. Then, try to go to the - // next file, because we really don't know where - // this file ends. - - if (m_pRestore && !m_uiFileEOF) - { - if (bTransActive) - { - FlmDbTransAbort( hDb); - bTransActive = FALSE; - } - - // Set current transaction ID to zero - as if we had encountered - // an abort packet. - - m_uiCurrTransID = 0; - bLastTransEndedAtFileEOF = TRUE; - - // Force to go to the next file - - bForceNextFile = TRUE; - rc = FERR_OK; - continue; - } - } - goto Exit; - } - - // At this point, we know we have a good packet, see what it - // is and handle it. - - bHadOperations = TRUE; - switch (uiOp) - { - case RFL_TRNS_BEGIN_EX_PACKET: - case RFL_TRNS_BEGIN_PACKET: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_BEGIN_TRANS, - uiTransId, - (void *)uiStartTime, - (void *)0, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - // Need to set m_uiCurrTransID to 0 since it was - // set by getPacket(). We are not going to - // start a transaction because of the user's request - // to exit. - - m_uiCurrTransID = 0; - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - // If we already have a transaction active, we have - // a problem. - - flmAssert( !bTransActive); - - if( RC_BAD( rc = FlmDbTransBegin( hDb, - FLM_UPDATE_TRANS, 0))) - { - goto Exit; - } - - bTransActive = TRUE; - break; - } - - case RFL_TRNS_COMMIT_PACKET: - { - // Commit the current transaction. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_COMMIT_TRANS, - uiTransId, - (void *)0, - (void *)0, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - flmAssert( bTransActive); - pDb->uiFlags |= FDB_REPLAYING_COMMIT; - rc = FlmDbTransCommit( hDb); - pDb->uiFlags &= ~FDB_REPLAYING_COMMIT; - bTransActive = FALSE; - - if (RC_BAD( rc)) - { - goto Exit; - } - - m_uiLastLoggedCommitTransID = uiTransId; -Finish_Transaction: - if (!m_uiFileEOF) - { - bLastTransEndedAtFileEOF = TRUE; - } - else - { - bLastTransEndedAtFileEOF = - (m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && - m_pCurrentBuf->uiRflFileOffset + - m_pCurrentBuf->uiRflBufBytes == m_uiFileEOF) - ? TRUE - : FALSE; - } - m_uiLastTransID = uiTransId; - m_uiCurrTransID = 0; - break; - } - - case RFL_TRNS_ABORT_PACKET: - { - // Abort the current transaction. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_ABORT_TRANS, - uiTransId, - (void *)0, - (void *)0, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - flmAssert( bTransActive); - rc = FlmDbTransAbort( hDb); - bTransActive = FALSE; - - if (RC_BAD( rc)) - { - goto Exit; - } - goto Finish_Transaction; - } - - case RFL_ADD_RECORD_PACKET: - case RFL_ADD_RECORD_PACKET_VER_2: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_ADD_REC, - uiTransId, - (void *)uiContainer, - (void *)uiDrn, - (void *)pRecord, - &eRestoreAction))) - { - goto Exit; - } - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - rc = FlmRecordAdd( hDb, uiContainer, &uiDrn, - pRecord, uiOpFlags); - pRecord->Release(); - pRecord = NULL; - if (RC_BAD( rc)) - { - goto Exit; - } - break; - } - - case RFL_MODIFY_RECORD_PACKET: - case RFL_MODIFY_RECORD_PACKET_VER_2: - { - // Must retrieve the record and then get the - // modify packet(s) to alter it. - - if (RC_BAD( rc = FlmRecordRetrieve( hDb, uiContainer, - uiDrn, FO_EXACT, &pRecord, NULL))) - { - goto Exit; - } - - if ((pTmpRecord = pRecord->copy()) == NULL) - { - rc = RC_SET( FERR_MEM); - goto Exit; - } - - pRecord->Release(); - pRecord = NULL; - - if (RC_BAD( rc = modifyRecord( hDb, pTmpRecord))) - { - goto Handle_Packet_Error; - } - - // Finally, modify the record in the database. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_MOD_REC, - uiTransId, - (void *)uiContainer, - (void *)uiDrn, - (void *)pTmpRecord, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - rc = FlmRecordModify( hDb, uiContainer, uiDrn, - pTmpRecord, uiOpFlags); - - pTmpRecord->Release(); - pTmpRecord = NULL; - - if (RC_BAD( rc)) - { - goto Exit; - } - break; - } - - case RFL_DELETE_RECORD_PACKET: - case RFL_DELETE_RECORD_PACKET_VER_2: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_DEL_REC, - uiTransId, - (void *)uiContainer, - (void *)uiDrn, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = FlmRecordDelete( hDb, uiContainer, - uiDrn, uiOpFlags))) - { - goto Exit; - } - break; - } - - case RFL_RESERVE_DRN_PACKET: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_RESERVE_DRN, - uiTransId, - (void *)uiContainer, - (void *)uiDrn, - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = FlmReserveNextDrn( hDb, uiContainer, &uiDrn))) - { - goto Exit; - } - break; - } - - case RFL_INDEX_SUSPEND_PACKET: - { - // NOTE: The index number is returned in the uiDrn parameter of - // the readOp function. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_INDEX_SUSPEND, - uiTransId, - (void *)uiIndex, - (void *)0, - (void *)0, &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = FlmIndexSuspend( hDb, uiIndex))) - { - goto Exit; - } - break; - } - - case RFL_INDEX_RESUME_PACKET: - { - // NOTE: The index number is returned in the uiDrn parameter of - // the readOp function. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_INDEX_RESUME, - uiTransId, - (void *)uiIndex, - (void *)0, - (void *)0, &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = FlmIndexResume( hDb, uiIndex))) - { - goto Exit; - } - break; - } - - case RFL_INDEX_SET_PACKET: - case RFL_INDEX_SET_PACKET_VER_2: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_INDEX_SET, - uiTransId, - (void *)uiIndex, - (void *)uiDrn, - (void *)uiEndDrn, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } -#ifdef FLM_DEBUG - if( m_pFile->FileHdr.uiVersionNum < FLM_VER_4_50) - { - flmAssert( uiOp == RFL_INDEX_SET_PACKET); - } -#endif - - if( RC_BAD( rc = flmDbIndexSetOfRecords( hDb, uiIndex, - uiContainer, uiDrn, uiEndDrn))) - { - goto Exit; - } - break; - } - - case RFL_BLK_CHAIN_FREE_PACKET: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_BLK_CHAIN_DELETE, - uiTransId, - (void *)uiDrn, - (void *)uiOpFlags, - (void *)uiEndDrn, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = flmMaintFreeBlockChain( - pDb, uiDrn, uiOpFlags, uiEndDrn, NULL))) - { - goto Exit; - } - - break; - } - - case RFL_START_UNKNOWN_PACKET: - { - if (m_pRestore) - { - F_RflUnknownStream unkStrm; - - unkStrm.setup( this, TRUE); - m_bReadingUnknown = TRUE; - m_uiUnknownPacketBodyLen = 0; - m_pucUnknownPacketBody = NULL; - m_uiUnknownBodyLenProcessed = 0; - m_uiUnknownPacketRc = FERR_OK; - - if (RC_BAD( rc = m_pRestore->processUnknown( - (F_UnknownStream *)&unkStrm))) - { - if (m_uiUnknownPacketRc != FERR_OK) - { - rc = m_uiUnknownPacketRc; - goto Handle_Packet_Error; - } - goto Exit; - } - - // If we did not read through all of the unknown - // packets, skip them at this time. - - if (m_bReadingUnknown) - { - goto Skip_Unknown_Packets; - } - } - else - { -Skip_Unknown_Packets: - - // Skip all unknown packets. - - for (;;) - { - FLMUINT uiPacketType; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, - &pucPacketBody, &uiPacketBodyLen, NULL))) - { - goto Handle_Packet_Error; - } - - // If we hit something other than an unknown packet, - // "push" it back into the pipe so it will be processed - // by readOp() up above. - - if (uiPacketType != RFL_UNKNOWN_PACKET) - { - - // At this point, we know that the entire packet is - // inside our memory buffer, so it is safe to reset - // m_uiRflReadOffset back to the beginning of the - // packet. The call to readOp() above will call - // getPacket again, which will get this exact same - // packet for processing. - - m_uiRflReadOffset -= (RFL_PACKET_OVERHEAD + - uiPacketBodyLen); - break; - } - } - } - break; - } - - case RFL_REDUCE_PACKET: - { - // NOTE: The count is returned in the uiDrn parameter of - // the readOp function. - - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_REDUCE, - uiTransId, - (void *)uiDrn, // count - (void *)0, - (void *)0, &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - - // Need to set m_uiCurrTransID to 0 since it was - // set by getPacket(). We are not going to - // start a transaction because of the user's request - // to exit. - - m_uiCurrTransID = 0; - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - if( RC_BAD( rc = FlmDbReduceSize( hDb, uiDrn, &uiCount))) - { - goto Exit; - } - - goto Finish_Transaction; - } - - case RFL_UPGRADE_PACKET: - { - if (m_pRestore) - { - if (RC_BAD( rc = m_pRestore->status( - RESTORE_UPGRADE, - uiTransId, - (void *)uiDrn, // Old DB Version - (void *)uiEndDrn, // New DB Version - (void *)0, - &eRestoreAction))) - { - goto Exit; - } - - if (eRestoreAction == RESTORE_ACTION_STOP) - { - // Need to set m_uiCurrTransID to 0 since it was - // set by getPacket(). We are not going to - // start a transaction because of the user's request - // to exit. - - m_uiCurrTransID = 0; - bLastTransEndedAtFileEOF = FALSE; - goto Finish_Recovery; - } - } - - // Attempt the conversion if the current version is less - // than the target version and the target version is - // less than or equal to the highest version supported - // by this code. - - if( uiEndDrn > FLM_CURRENT_VERSION_NUM) - { - rc = RC_SET( FERR_UNALLOWED_UPGRADE); - goto Exit; - } - else - { - flmAssert( m_pFile->FileHdr.uiVersionNum < uiEndDrn); - - // The logged "new" version may be a lesser version - // than FLM_CURRENT_VERSION_NUM, which is what FlmDbUpgrade - // upgrades to. This is O.K. because the current version - // should support all packets in the RFL for versions - // that are less than it. Otherwise, the RFL chain - // would have been broken by the original upgrade and it - // would not have logged an upgrade packet. - - if( RC_BAD( rc = FlmDbUpgrade( hDb, uiEndDrn, NULL, NULL))) - { - goto Exit; - } - } - goto Finish_Transaction; - } - - case RFL_WRAP_KEY_PACKET: - case RFL_ENABLE_ENCRYPTION_PACKET: - { - goto Finish_Transaction; - } - - default: - { - // Should not be getting other packet types at this - // point. - - // If we don't know the current file size, and we - // are doing a restore, it is OK to end on a bad - // packet - we will simply abort the current - // transaction, if any. - - if (m_pRestore && !m_uiFileEOF) - { - rc = FERR_OK; - goto Finish_Recovery; - } - else - { - rc = RC_SET( FERR_BAD_RFL_PACKET); - } - - goto Exit; - } - } - } - -Finish_Recovery: - - if (bTransActive) - { - FlmDbTransAbort( hDb); - bTransActive = FALSE; - } - - if (m_pRestore) - { - FLMUINT uiNextRflFileNum = m_pCurrentBuf->uiCurrFileNum + 1; - - // At the end of the restore operation, we need to set things - // up so that the next transaction will begin a new RFL file. - // If we ended the restore in the middle of an RFL file, we - // need to set it up so that the new RFL file will have a new - // serial number. If we ended at the end of an RFL file, we - // can set it up so that the new RFL file will have the next - // serial number. - - // Set up the next RFL file number and offset. - - UD2FBA( uiNextRflFileNum, - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_FILE_NUM]); - - // Set a zero into the offset, this is a special case which tells - // us that we should create the file no matter what - even if - // it already exists - it should be overwritten. - - UD2FBA( 0, - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_LAST_TRANS_OFFSET]); - - if (bLastTransEndedAtFileEOF) - { - // Move the next serial number of the last RFL file processed into - // into the current RFL serial number so that the log header - // will be correct - - f_memcpy( - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM], - m_ucNextSerialNum, F_SERIAL_NUM_SIZE); - } - else - { - - // Must create a new serial number so that when the new RFL - // file is created, it will have that next serial number. - - if (RC_BAD( rc = f_createSerialNumber( - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_TRANS_RFL_SERIAL_NUM]))) - { - goto Exit; - } - } - - // Save the last logged commit transaction ID. - - if (m_pFile->FileHdr.uiVersionNum >= FLM_VER_4_31 && - m_uiLastLoggedCommitTransID) - { - UD2FBA(m_uiLastLoggedCommitTransID, - &m_pFile->ucLastCommittedLogHdr [LOG_LAST_RFL_COMMIT_ID]); - } - - // No matter what, we must generate a new next serial number. This - // is what will be written to the new RFL file's header when it is - // created. - - if (RC_BAD( rc = f_createSerialNumber( - &m_pFile->ucLastCommittedLogHdr [LOG_RFL_NEXT_SERIAL_NUM]))) - { - goto Exit; - } - } - - if (!bHadOperations) - { - - // No transactions were recovered, but still need to - // setup a few things. - - m_pFile->uiFirstLogCPBlkAddress = 0; - m_pFile->uiLastCheckpointTime = (FLMUINT)FLM_GET_TIMER(); - - // Save the state of the log header into the ucCheckpointLogHdr buffer. - - f_memcpy( m_pFile->ucCheckpointLogHdr, - m_pFile->ucLastCommittedLogHdr, - LOG_HEADER_SIZE); - } - - // Force a checkpoint to force the log files to be truncated and - // everything to be reset. This is done because during recovery - // the checkpoints that are executed do NOT truncate the RFL file - - // because it is using the log file to recover! - - closeFile(); - m_pRestore = NULL; - m_bLoggingOff = FALSE; - pDb->uiFlags &= ~FDB_REPLAYING_RFL; - if (RC_BAD( rc = FlmDbCheckpoint( hDb, 0))) - { - goto Exit; - } - -Exit: - - if (pRecord) - { - pRecord->Release(); - } - - if (pTmpRecord) - { - pTmpRecord->Release(); - } - - if (bTransActive) - { - FlmDbTransAbort( hDb); - } - - pDb->bFldStateUpdOk = FALSE; - pDb->uiFlags &= ~FDB_REPLAYING_RFL; - - return( rc); -} - -/*API~*********************************************************************** -Desc: Returns the name of an RFL file given its number -*END************************************************************************/ -FLMEXP RCODE FLMAPI FlmDbGetRflFileName( - HFDB hDb, - FLMUINT uiFileNum, - char * pszFileName) -{ - ((FDB *)hDb)->pFile->pRfl->getBaseRflFileName( - uiFileNum, pszFileName); - - return( FERR_OK); -} - -/******************************************************************** -Desc: Log a block chain free operation -*********************************************************************/ -RCODE F_Rfl::logBlockChainFree( - FLMUINT uiTrackerDrn, - FLMUINT uiCount, - FLMUINT uiEndAddr) -{ - RCODE rc = FERR_OK; - FLMBYTE * pucPacketBody; - FLMUINT uiPacketBodyLen; - - // This call is new with 4.52 databases - not supported in older - // versions, so don't log it. - - if (m_pFile->FileHdr.uiVersionNum < FLM_VER_4_60) - { - flmAssert( 0); - goto Exit; - } - - // Do nothing if logging is disabled. - - if (m_bLoggingOff) - { - goto Exit; - } - - // Better not be in the middle of logging unknown stuff - // for the application - - flmAssert( !m_bLoggingUnknown); - - // Better be in the middle of a transaction. - - flmAssert( m_uiCurrTransID); - m_uiOperCount++; - - uiPacketBodyLen = 16; - - // Make sure we have space in the RFL buffer for a complete packet. - - if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) - { - if (RC_BAD( rc = flush( m_pCurrentBuf))) - { - goto Exit; - } - } - - // Get a pointer to where we will be laying down the packet body. - - pucPacketBody = getPacketBodyPtr(); - - // Output the transaction ID. - - UD2FBA( (FLMUINT32)m_uiCurrTransID, pucPacketBody); - pucPacketBody += 4; - - // Output the tracker record number - - UD2FBA( (FLMUINT32)uiTrackerDrn, pucPacketBody); - pucPacketBody += 4; - - // Output the count - - UD2FBA( (FLMUINT32)uiCount, pucPacketBody); - pucPacketBody += 4; - - // Output the ending block address - - UD2FBA( (FLMUINT32)uiEndAddr, pucPacketBody); - pucPacketBody += 4; - - // Finish the packet - - if (RC_BAD( rc = finishPacket( RFL_BLK_CHAIN_FREE_PACKET, - uiPacketBodyLen, TRUE))) - { - goto Exit; - } - -Exit: - - return( rc); -} +//------------------------------------------------------------------------- +// Desc: Routines for roll-forward logging. +// Tabs: 3 +// +// Copyright (c) 1998-2006 Novell, Inc. All Rights Reserved. +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of version 2 of the GNU General Public +// License as published by the Free Software Foundation. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, contact Novell, Inc. +// +// To contact Novell about this file by physical or electronic mail, +// you may find current contact information at www.novell.com +// +// $Id: rfl.cpp 12334 2006-01-23 12:45:35 -0700 (Mon, 23 Jan 2006) dsanders $ +//------------------------------------------------------------------------- + +#include "flaimsys.h" + +#define MOD_512(uiNum) \ + (FLMUINT) ((uiNum) & 511) + +#define ON_512_BYTE_BOUNDARY(uiNum) \ + (!MOD_512( uiNum)) + +#define ROUND_DOWN_TO_NEAREST_512(uiNum) \ + (FLMUINT) ((uiNum) & (~((FLMUINT) 511))) + +FSTATIC RCODE RflCheckMaxLogged( + FLMUINT * puiMaxBytesNeededRV, + FLMUINT uiPacketsLogged, + FLMUINT * puiCurrTotalLoggedRV, + FLMUINT uiBytesToLog); + +FSTATIC void RflChangeCallback( + GRD_DifferenceData & DiffData, + void * CallbackData); + +/******************************************************************** +Desc: +*********************************************************************/ +F_Rfl::F_Rfl() +{ + m_pFile = NULL; + m_hBufMutex = F_MUTEX_NULL; + m_pCommitBuf = NULL; + m_pCurrentBuf = NULL; + m_uiRflWriteBufs = DEFAULT_RFL_WRITE_BUFFERS; + m_uiBufferSize = DEFAULT_RFL_BUFFER_SIZE; + f_memset( &m_Buf1, 0, sizeof(m_Buf1)); + f_memset( &m_Buf2, 0, sizeof(m_Buf2)); + m_bKeepRflFiles = FALSE; + m_uiRflMinFileSize = DEFAULT_MIN_RFL_FILE_SIZE; + m_uiRflMaxFileSize = DEFAULT_MAX_RFL_FILE_SIZE; + m_pFileHdl = NULL; + m_uiLastRecoverFileNum = 0; + f_memset( m_ucCurrSerialNum, 0, sizeof(m_ucCurrSerialNum)); + m_bLoggingOff = FALSE; + m_bLoggingUnknown = FALSE; + m_uiUnknownPacketLen = 0; + m_bReadingUnknown = FALSE; + m_uiUnknownPacketBodyLen = 0; + m_pucUnknownPacketBody = NULL; + m_uiUnknownBodyLenProcessed = 0; + m_uiUnknownPacketRc = FERR_OK; + m_uiTransStartFile = 0; + m_uiTransStartAddr = 0; + m_uiCurrTransID = 0; + m_uiLastTransID = 0; + m_uiLastLoggedCommitTransID = 0; + m_uiOperCount = 0; + m_uiRflReadOffset = 0; + m_uiFileEOF = 0; + m_pRestore = NULL; + f_memset( m_szDbPrefix, 0, sizeof(m_szDbPrefix)); + f_memset( m_szRflDir, 0, sizeof(m_szRflDir)); + m_bRflDirSameAsDb = FALSE; + m_bCreateRflDir = FALSE; + f_memset( m_ucNextSerialNum, 0, sizeof(m_ucNextSerialNum)); + m_bRflVolumeOk = TRUE; + m_bRflVolumeFull = FALSE; +} + +/******************************************************************** +Desc: +*********************************************************************/ +F_Rfl::~F_Rfl() +{ + + // Better not be in the middle of logging unknown packets for the + // application. + + flmAssert( !m_bLoggingUnknown); + + if (m_Buf1.pIOBuffer) + { + m_Buf1.pIOBuffer->Release(); + m_Buf1.pIOBuffer = NULL; + } + + if (m_Buf2.pIOBuffer) + { + m_Buf2.pIOBuffer->Release(); + m_Buf2.pIOBuffer = NULL; + } + + if (m_Buf1.pBufferMgr) + { + flmAssert( !m_Buf1.pBufferMgr->havePendingIO() && + !m_Buf1.pBufferMgr->haveUsed()); + + m_Buf1.pBufferMgr->Release(); + m_Buf1.pBufferMgr = NULL; + } + + if (m_Buf2.pBufferMgr) + { + flmAssert( !m_Buf2.pBufferMgr->havePendingIO() && + !m_Buf2.pBufferMgr->haveUsed()); + + m_Buf2.pBufferMgr->Release(); + m_Buf2.pBufferMgr = NULL; + } + + if (m_hBufMutex != F_MUTEX_NULL) + { + f_mutexDestroy( &m_hBufMutex); + } + + if (m_pFileHdl) + { + m_pFileHdl->Close(); + m_pFileHdl->Release(); + m_pFileHdl = NULL; + m_pFile = NULL; + } +} + +/******************************************************************** +Desc: Returns a boolean indicating whether or not we are at + the end of the RFL log - will only be TRUE when we are + doing recovery. +*********************************************************************/ +FLMBOOL F_Rfl::atEndOfLog(void) +{ + return( (!m_pRestore && m_uiFileEOF && + m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes >= m_uiFileEOF && + m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && + m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) + ? TRUE + : FALSE); +} + +/******************************************************************** +Desc: Gets the base RFL file name - does not have directory part. + This needs to be separate from the F_Rfl object so it can + be called without having to instantiate and set up an F_Rfl + object. +*********************************************************************/ +void rflGetBaseFileName( + FLMUINT uiDbVersion, + const char * pszDbPrefix, + FLMUINT uiFileNum, + char * pszBaseNameOut) +{ + FLMINT iCnt = 0; + FLMUINT uiDigit; + char * pszTmp = pszBaseNameOut; + + if (uiDbVersion < FLM_FILE_FORMAT_VER_4_3) + { + + // Output the database name prefix (up to three characters). + + f_strcpy( pszTmp, pszDbPrefix); + while (*pszTmp) + { + pszTmp++; + } + + // Output as five digit base 36 number. + + pszTmp += 4; + while (iCnt < 5) + { + uiDigit = (FLMUINT) (uiFileNum % 36); + uiFileNum /= 36; + if (uiDigit <= 9) + { + uiDigit += NATIVE_ZERO; + } + else + { + uiDigit += (NATIVE_LOWER_A - 10); + } + + *pszTmp = (FLMBYTE) uiDigit; + pszTmp--; + iCnt++; + } + + // Skip to end of digits and append ".log" to name + + pszTmp += 6; + f_strcpy( pszTmp, ".log"); + } + else + { + + // Output as eight digit hex number. + + pszTmp += 7; + while (iCnt < 8) + { + uiDigit = (FLMUINT) (uiFileNum & 0xF); + uiFileNum >>= 4; + if (uiDigit <= 9) + { + uiDigit += NATIVE_ZERO; + } + else + { + uiDigit += (NATIVE_LOWER_A - 10); + } + + *pszTmp = (FLMBYTE) uiDigit; + pszTmp--; + iCnt++; + } + + // Skip to end of digits and append ".log" to name + + pszTmp += 9; + f_strcpy( pszTmp, ".log"); + } +} + +/******************************************************************** +Desc: Gets the base RFL file name - does not have directory part. +*********************************************************************/ +void F_Rfl::getBaseRflFileName( + FLMUINT uiFileNum, + char * pszBaseName) +{ + rflGetBaseFileName( m_pFile->FileHdr.uiVersionNum, + m_szDbPrefix, uiFileNum, pszBaseName); +} + +/******************************************************************** +Desc: Generates the full roll forward log file name. Name is based + on the sequence number and the first three characters of the + database if the DB is less than version 4.3. + Otherwise, it is a hex number. +*********************************************************************/ +RCODE F_Rfl::getFullRflFileName( + FLMUINT uiFileNum, + char * pszRflFileName) +{ + RCODE rc = FERR_OK; + char szBaseName[F_FILENAME_SIZE]; + + // Get the directory name. + + f_strcpy( pszRflFileName, m_szRflDir); + + // Get the base RFL file name. + + getBaseRflFileName( uiFileNum, szBaseName); + + // Append the two together. + + if (RC_BAD( rc = f_pathAppend( pszRflFileName, szBaseName))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Positions to the offset specified in the RFL file. +*********************************************************************/ +RCODE F_Rfl::positionTo( + FLMUINT uiFileOffset) +{ + RCODE rc = FERR_OK; + FLMUINT uiBytesToRead; + FLMUINT uiBytesRead; + + // Should never be attempting to position to something less than 512 - + // the header is stored in the first 512 bytes. + + flmAssert( uiFileOffset >= 512); + + // If the position is within our current buffer, see if we can adjust + // things without having to go back and re-read the buffer from disk. + + if (m_pCurrentBuf->uiRflBufBytes && + uiFileOffset >= m_pCurrentBuf->uiRflFileOffset && + uiFileOffset <= m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes) + { + + // Whatever is in the buffer beyond uiFileOffset is irrelevant and + // can be discarded. + + m_pCurrentBuf->uiRflBufBytes = uiFileOffset - + m_pCurrentBuf->uiRflFileOffset; + } + else + { + + // Populate the buffer from the 512 byte boundary that is just + // before the offset we are trying to position to. + + uiBytesToRead = MOD_512( uiFileOffset); + m_pCurrentBuf->uiRflFileOffset = ROUND_DOWN_TO_NEAREST_512( uiFileOffset); + m_pCurrentBuf->uiRflBufBytes = MOD_512( uiFileOffset); + if (m_pCurrentBuf->uiRflBufBytes) + { + if (RC_BAD( rc = m_pFileHdl->SectorRead( + m_pCurrentBuf->uiRflFileOffset, + m_pCurrentBuf->uiRflBufBytes, + m_pCurrentBuf->pIOBuffer->m_pucBuffer, &uiBytesRead))) + { + if (rc == FERR_IO_END_OF_FILE) + { + rc = RC_SET( FERR_NOT_RFL); + } + else + { + m_bRflVolumeOk = FALSE; + } + + goto Exit; + } + else if (uiBytesRead < m_pCurrentBuf->uiRflBufBytes) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Get the ACTUAL RFL directory, using as input parameters the + database version, the name of the database, and the + user specified RFL directory. Also return the database + prefix. +*********************************************************************/ +RCODE rflGetDirAndPrefix( + FLMUINT uiDbVersionNum, + const char * pszDbFileName, + const char * pszRflDirIn, + char * pszRflDirOut, + char * pszDbPrefixOut) +{ + RCODE rc = FERR_OK; + char szDbPath[F_PATH_MAX_SIZE]; + char szBaseName[F_FILENAME_SIZE]; + + // Parse the database name into directory and base name + + if (RC_BAD( rc = f_pathReduce( pszDbFileName, szDbPath, szBaseName))) + { + goto Exit; + } + + // Get the base path + + flmGetDbBasePath( pszDbPrefixOut, szBaseName, NULL); + + if (uiDbVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + + // Determine the RFL directory. If one was specified, it is + // whatever was specified. Otherwise, it is relative to the database + // directory. + + if (pszRflDirIn && *pszRflDirIn) + { + f_strcpy( pszRflDirOut, pszRflDirIn); + } + else + { + f_strcpy( pszRflDirOut, szDbPath); + } + + // For 4.3 and above, the RFL files go in a subdirectory underneath + // the directory where the database is located or the specified + // directory. + + f_strcpy( szBaseName, pszDbPrefixOut); + f_strcat( szBaseName, ".rfl"); + f_pathAppend( pszRflDirOut, szBaseName); + } + else + { + f_strcpy( pszRflDirOut, szDbPath); + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Set the RFL directory. If pszRflDir is NULL or empty string, + the RFL directory is set to the same directory as the + database. +*********************************************************************/ +RCODE F_Rfl::setRflDir( + const char * pszRflDir) +{ + + // Better have set up the FFILE pointer. + + flmAssert( m_pFile != NULL); + + m_bRflDirSameAsDb = (!pszRflDir || !(*pszRflDir)) ? TRUE : FALSE; + + flmAssert( m_pFile->FileHdr.uiVersionNum); + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + + // Don't allow RFL directory to be specified for versions less than + // 4.3 + + pszRflDir = NULL; + m_bRflDirSameAsDb = TRUE; + } + + m_bCreateRflDir = + (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + ? TRUE + : FALSE; + return( rflGetDirAndPrefix( + m_pFile->FileHdr.uiVersionNum, m_pFile->pszDbPath, + pszRflDir, m_szRflDir, m_szDbPrefix)); +} + +/******************************************************************** +Desc: Gets an RFL file name - based on DB name and RFL directory. +*********************************************************************/ +RCODE rflGetFileName( + FLMUINT uiDbVersion, + const char * pszDbName, + const char * pszRflDir, + FLMUINT uiFileNum, + char * pszRflFileName) +{ + RCODE rc = FERR_OK; + char szDbPrefix[ F_FILENAME_SIZE]; + char szBaseName[ F_FILENAME_SIZE]; + + // Get the full RFL file name. + + if (RC_BAD( rc = rflGetDirAndPrefix( uiDbVersion, pszDbName, pszRflDir, + pszRflFileName, szDbPrefix))) + { + goto Exit; + } + + rflGetBaseFileName( uiDbVersion, szDbPrefix, uiFileNum, szBaseName); + if (RC_BAD( rc = f_pathAppend( pszRflFileName, szBaseName))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Gets an RFL file number from the RFL file name. +*********************************************************************/ +FLMBOOL rflGetFileNum( + FLMUINT uiDbVersion, + const char * pszDbPrefix, + const char * pszRflFileName, + FLMUINT * puiFileNum) +{ + FLMBOOL bGotNum = FALSE; + char szDir[F_PATH_MAX_SIZE]; + char szBaseName[F_FILENAME_SIZE]; + char * pszTmp; + FLMUINT uiCharCnt; + + if (RC_BAD( f_pathReduce( pszRflFileName, szDir, szBaseName))) + { + goto Exit; + } + + // See if it has a .log extension. + + pszTmp = &szBaseName[0]; + while (*pszTmp && *pszTmp != '.') + { + pszTmp++; + } + + // If we do not have a .log extension, it is not a legitimate RFL file. + + if (f_stricmp( pszTmp, ".log") != 0) + { + goto Exit; + } + + // Parse out the name according to the rules for this DB version. + + *pszTmp = 0; // Set period to zero + pszTmp = &szBaseName[0]; + *puiFileNum = 0; + uiCharCnt = 0; + if (uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) + { + + // Name up to the period should be a hex number + + while (*pszTmp) + { + (*puiFileNum) <<= 4; + if (*pszTmp >= NATIVE_ZERO && *pszTmp <= NATIVE_NINE) + { + *puiFileNum += (FLMUINT) (*pszTmp - NATIVE_ZERO); + } + else if (*pszTmp >= NATIVE_LOWER_A && *pszTmp <= NATIVE_LOWER_F) + { + *puiFileNum += ((FLMUINT) (*pszTmp - NATIVE_LOWER_A) + 10); + } + else if (*pszTmp >= NATIVE_UPPER_A && *pszTmp <= NATIVE_UPPER_F) + { + *puiFileNum += ((FLMUINT) (*pszTmp - NATIVE_UPPER_A) + 10); + } + else + { + goto Exit; // Not a hex number + } + + uiCharCnt++; + pszTmp++; + } + + // Better have been exactly 8 hex digits. + + bGotNum = (FLMBOOL) ((uiCharCnt == 8) ? TRUE : FALSE); + } + else + { + FLMUINT uiLen = f_strlen( pszTmp); + FLMUINT uiPrefixLen = f_strlen( pszDbPrefix); + + // Length of base name without the .log extension better be exactly + // 5 more characters than the length of the prefix. + + if (uiLen != uiPrefixLen + 5) + { + flmAssert( 0); + goto Exit; + } + + // Prefix better match. + + while (uiPrefixLen) + { + if (f_toupper( *pszTmp) != f_toupper( *pszDbPrefix)) + { + goto Exit; + } + + uiPrefixLen--; + pszTmp++; + pszDbPrefix++; + } + + // Rest of the name is the five digits that are a base 36 number. + + while (*pszTmp) + { + (*puiFileNum) *= 36; + if (*pszTmp >= NATIVE_ZERO && *pszTmp <= NATIVE_NINE) + { + *puiFileNum += (FLMUINT) (*pszTmp - NATIVE_ZERO); + } + else if (*pszTmp >= NATIVE_LOWER_A && *pszTmp <= NATIVE_LOWER_Z) + { + *puiFileNum += ((FLMUINT) (*pszTmp - NATIVE_LOWER_A) + 10); + } + else if (*pszTmp >= NATIVE_UPPER_A && *pszTmp <= NATIVE_UPPER_Z) + { + *puiFileNum += ((FLMUINT) (*pszTmp - NATIVE_UPPER_A) + 10); + } + else + { + goto Exit; // Not a base 36 number + } + + pszTmp++; + } + + bGotNum = TRUE; + } + +Exit: + + return (bGotNum); +} + +/******************************************************************** +Desc: Sets up the RFL object - associating with a file, etc. +*********************************************************************/ +RCODE F_Rfl::setup( + FFILE * pFile, + const char * pszRflDir) +{ + RCODE rc = FERR_OK; + + // Better not already be associated with an FFILE + + flmAssert( m_pFile == NULL); + m_pFile = pFile; + + // Allocate memory for the RFL buffers + + if (!gv_FlmSysData.bOkToDoAsyncWrites) + { + m_uiRflWriteBufs = 1; + m_uiBufferSize = DEFAULT_RFL_WRITE_BUFFERS * DEFAULT_RFL_BUFFER_SIZE; + } + + if (RC_BAD( rc = f_mutexCreate( &m_hBufMutex))) + { + goto Exit; + } + + if ((m_Buf1.pBufferMgr = f_new F_IOBufferMgr) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if ((m_Buf2.pBufferMgr = f_new F_IOBufferMgr) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + m_Buf1.pBufferMgr->enableKeepBuffer(); + m_Buf1.pBufferMgr->setMaxBuffers( m_uiRflWriteBufs); + m_Buf1.pBufferMgr->setMaxBytes( m_uiRflWriteBufs * m_uiBufferSize); + + if (RC_BAD( rc = m_Buf1.pBufferMgr->getBuffer( &m_Buf1.pIOBuffer, + m_uiBufferSize, m_uiBufferSize))) + { + goto Exit; + } + + m_Buf2.pBufferMgr->enableKeepBuffer(); + m_Buf2.pBufferMgr->setMaxBuffers( m_uiRflWriteBufs); + m_Buf2.pBufferMgr->setMaxBytes( m_uiRflWriteBufs * m_uiBufferSize); + + if (RC_BAD( rc = m_Buf2.pBufferMgr->getBuffer( &m_Buf2.pIOBuffer, + m_uiBufferSize, m_uiBufferSize))) + { + goto Exit; + } + + m_bLoggingOff = FALSE; + m_pCurrentBuf = &m_Buf1; + m_pCurrentBuf->uiRflBufBytes = 0; + + // Set the RFL directory and prefix if necessary. + + if (RC_BAD( rc = setRflDir( pszRflDir))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Wait for the writes of a buffer to finish. This routine assumes + that the m_hBufMutex is locked when coming in. It will ALWAYS + unlock the mutex before exiting. +*********************************************************************/ +RCODE F_Rfl::waitForWrites( + RFL_BUFFER * pBuffer, + FLMBOOL bIsWriter) +{ + RCODE rc = FERR_OK; + RCODE TempRc; + RFL_WAITER Waiter; + FLMBOOL bMutexLocked = TRUE; + + // Put self on the wait queue for the buffer. + + Waiter.uiThreadId = f_threadId(); + Waiter.bIsWriter = bIsWriter; + Waiter.hESem = F_SEM_NULL; + if (RC_BAD( rc = f_semCreate( &Waiter.hESem))) + { + goto Exit; + } + + // Note: rc better be changed to success or write error by the process + // that signals us. + + rc = RC_SET( FERR_FAILURE); + Waiter.pRc = &rc; + Waiter.pNext = NULL; + if (pBuffer->pLastWaiter) + { + pBuffer->pLastWaiter->pNext = &Waiter; + } + else + { + pBuffer->pFirstWaiter = &Waiter; + } + + pBuffer->pLastWaiter = &Waiter; + f_mutexUnlock( m_hBufMutex); + bMutexLocked = FALSE; + + // Now just wait to be signaled. + + if (RC_BAD( TempRc = f_semWait( Waiter.hESem, F_SEM_WAITFOREVER))) + { +#ifdef FLM_NLM + EnterDebugger(); +#else + flmAssert( 0); +#endif + rc = TempRc; + } + else + { + + // Process that signaled us better set the rc to something besides + // FERR_FAILURE. + + if (rc == FERR_FAILURE) + { +#ifdef FLM_NLM + EnterDebugger(); +#else + flmAssert( 0); +#endif + } + } + +Exit: + + if (Waiter.hESem != F_SEM_NULL) + { + f_semDestroy( &Waiter.hESem); + } + + if (bMutexLocked) + { + f_mutexUnlock( m_hBufMutex); + } + + return (rc); +} + +/******************************************************************** +Desc: If a commit is in progress, wait for it to finish. +*********************************************************************/ +RCODE F_Rfl::waitForCommit(void) +{ + RCODE rc = FERR_OK; + FLMBOOL bMutexLocked = FALSE; + + // NOTE: If m_pCommitBuf is NULL it cannot be set to something + // non-NULL except by this thread when this thread ends the + // transaction. So, there is no need to lock the mutex and re-check if + // it is NULL. + + if (m_pCommitBuf) + { + f_mutexLock( m_hBufMutex); + bMutexLocked = TRUE; + + // Check m_pCommitBuf again after locking mutex - may have finished. + + if (m_pCommitBuf) + { + + // waitForWrites will unlock the mutex. + + bMutexLocked = FALSE; + rc = waitForWrites( m_pCommitBuf, FALSE); + } + } + + if (bMutexLocked) + { + f_mutexUnlock( m_hBufMutex); + } + + return (rc); +} + +/******************************************************************** +Desc: Write out the header information for an RFL file. +*********************************************************************/ +RCODE F_Rfl::writeHeader( + FLMUINT uiFileNum, + FLMUINT uiEof, + FLMBYTE * pucSerialNum, + FLMBYTE * pucNextSerialNum, + FLMBOOL bKeepSignature) +{ + RCODE rc = FERR_OK; + FLMBYTE ucBuf [512]; + FLMUINT uiBytesWritten; + + flmAssert( m_pFile); + flmAssert( m_pFileHdl); + + f_memset( ucBuf, 0, sizeof(ucBuf)); + f_memcpy( &ucBuf[RFL_NAME_POS], RFL_NAME, RFL_NAME_LEN); + f_memcpy( &ucBuf[RFL_VERSION_POS], RFL_VERSION, RFL_VERSION_LEN); + UD2FBA( (FLMUINT32) uiFileNum, &ucBuf[RFL_FILE_NUMBER_POS]); + UD2FBA( (FLMUINT32) uiEof, &ucBuf[RFL_EOF_POS]); + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + f_memcpy( &ucBuf[RFL_DB_SERIAL_NUM_POS], + &m_pFile->ucLastCommittedLogHdr[LOG_DB_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + f_memcpy( &ucBuf[RFL_SERIAL_NUM_POS], pucSerialNum, F_SERIAL_NUM_SIZE); + f_memcpy( &ucBuf[RFL_NEXT_FILE_SERIAL_NUM_POS], pucNextSerialNum, + F_SERIAL_NUM_SIZE); + f_strcpy( (char *) &ucBuf[RFL_KEEP_SIGNATURE_POS], + ((bKeepSignature) ? RFL_KEEP_SIGNATURE : RFL_NOKEEP_SIGNATURE)); + } + + // Write out the header + + if (RC_BAD( rc = m_pFileHdl->SectorWrite( 0L, 512, ucBuf, sizeof(ucBuf), + NULL, &uiBytesWritten))) + { + + // Remap disk full error + + if (rc == FERR_IO_DISK_FULL) + { + rc = RC_SET( FERR_RFL_DEVICE_FULL); + m_bRflVolumeFull = TRUE; + } + + m_bRflVolumeOk = FALSE; + goto Exit; + } + + // Flush the file handle to ensure it is forced to disk. + + if (RC_BAD( rc = m_pFileHdl->Flush())) + { + + // Remap disk full error + + if (rc == FERR_IO_DISK_FULL) + { + rc = RC_SET( FERR_RFL_DEVICE_FULL); + m_bRflVolumeFull = TRUE; + } + + m_bRflVolumeOk = FALSE; + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Verifies the header of an RFL file. +*********************************************************************/ +RCODE F_Rfl::verifyHeader( + FLMBYTE * pucHeader, + FLMUINT uiFileNum, + FLMBYTE * pucSerialNum) +{ + RCODE rc = FERR_OK; + + flmAssert( m_pFile); + + // Check the RFL name and version number + + if (f_memcmp( &pucHeader[RFL_NAME_POS], RFL_NAME, RFL_NAME_LEN) != 0) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + + if (f_memcmp( &pucHeader[RFL_VERSION_POS], + RFL_VERSION, RFL_VERSION_LEN) != 0) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + + // Verify the database serial number + + if (f_memcmp( &pucHeader[RFL_DB_SERIAL_NUM_POS], + &m_pFile->ucLastCommittedLogHdr[LOG_DB_SERIAL_NUM], + F_SERIAL_NUM_SIZE) != 0) + { + rc = RC_SET( FERR_BAD_RFL_DB_SERIAL_NUM); + goto Exit; + } + + // Verify the serial number that is expected to be on the RFL file. + // If pucSerialNum is NULL, we will not verify it. This is generally + // only done during recovery or restore when we are reading through + // multiple RFL files and we need to verify their serial numbers. + + if (pucSerialNum && + f_memcmp( &pucHeader[RFL_SERIAL_NUM_POS], pucSerialNum, + F_SERIAL_NUM_SIZE) != 0) + { + rc = RC_SET( FERR_BAD_RFL_SERIAL_NUM); + goto Exit; + } + + // Verify the file number. + + if (uiFileNum != (FLMUINT) FB2UD( &pucHeader[RFL_FILE_NUMBER_POS])) + { + rc = RC_SET( FERR_BAD_RFL_FILE_NUMBER); + goto Exit; + } + + // Save serial numbers from the header. + + f_memcpy( m_ucCurrSerialNum, &pucHeader[RFL_SERIAL_NUM_POS], + F_SERIAL_NUM_SIZE); + f_memcpy( m_ucNextSerialNum, &pucHeader[RFL_NEXT_FILE_SERIAL_NUM_POS], + F_SERIAL_NUM_SIZE); + } + + // Save some things from the header. + + m_uiFileEOF = (FLMUINT) FB2UD( &pucHeader[RFL_EOF_POS]); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Opens an RFL file. Verifies the serial number for 4.3 dbs. +*********************************************************************/ +RCODE F_Rfl::openFile( + FLMUINT uiFileNum, + FLMBYTE * pucSerialNum) +{ + RCODE rc = FERR_OK; + char szRflFileName [F_PATH_MAX_SIZE]; + FLMBYTE ucBuf [512]; + FLMUINT uiBytesRead; + + flmAssert( m_pFile); + + // If we have a file open and it is not the file number passed in, + // close it. + + if (m_pFileHdl) + { + if (m_pCurrentBuf->uiCurrFileNum != uiFileNum) + { + if (RC_BAD( rc = waitForCommit())) + { + goto Exit; + } + + closeFile(); + } + else + { + goto Exit; // Will return FERR_OK + } + } + else + { + + // Should not be able to be in the middle of a commit if we don't + // have a file open! + + flmAssert( !m_pCommitBuf); + } + + // Generate the log file name. + + if (RC_BAD( rc = getFullRflFileName( uiFileNum, szRflFileName))) + { + goto Exit; + } + + // Open the file. + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenBlockFile( szRflFileName, + F_IO_RDWR | F_IO_SH_DENYNONE | F_IO_DIRECT, 512, &m_pFileHdl))) + { + goto Exit; + } + + m_pFileHdl->setMaxAutoExtendSize( m_uiRflMaxFileSize); + m_pFileHdl->setExtendSize( m_pFile->uiFileExtendSize); + + // Read the header. + + if (RC_BAD( rc = m_pFileHdl->SectorRead( 0, 512, ucBuf, &uiBytesRead))) + { + if (rc == FERR_IO_END_OF_FILE) + { + rc = RC_SET( FERR_NOT_RFL); + } + else + { + m_bRflVolumeOk = FALSE; + } + + goto Exit; + } + + // If there is not enough data in the buffer, it is not an RFL file. + + if (uiBytesRead < 512) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + + // Verify the header information + + if (RC_BAD( rc = verifyHeader( ucBuf, uiFileNum, pucSerialNum))) + { + goto Exit; + } + + m_pCurrentBuf->uiRflBufBytes = 0; + m_pCurrentBuf->uiRflFileOffset = 0; + m_pCurrentBuf->uiCurrFileNum = uiFileNum; + +Exit: + + if (RC_BAD( rc)) + { + waitForCommit(); + closeFile(); + } + + return (rc); +} + +/******************************************************************** +Desc: Creates a new roll forward log file. +*********************************************************************/ +RCODE F_Rfl::createFile( + FLMUINT uiFileNum, + FLMBYTE * pucSerialNum, + FLMBYTE * pucNextSerialNum, + FLMBOOL bKeepSignature) +{ + RCODE rc = FERR_OK; + char szRflFileName [F_PATH_MAX_SIZE]; + + flmAssert( m_pFile); + + // Better not be trying to create the current file + + flmAssert( uiFileNum != m_pCurrentBuf->uiCurrFileNum); + + // If we have a file open close it. + + if (RC_BAD( rc = waitForCommit())) + { + goto Exit; + } + + closeFile(); + + // Generate the log file name. + + if (RC_BAD( rc = getFullRflFileName( uiFileNum, szRflFileName))) + { + goto Exit; + } + + // Delete the file if it already exists - don't care about return code + // here + + (void) gv_FlmSysData.pFileSystem->Delete( szRflFileName); + + // If DB is 4.3 or greater and we are in the same directory as our + // database files, see if we need to create the subdirectory. + // Otherwise, the RFL directory should already have been created. If + // the directory already exists, it is OK - we only try this the first + // time after setRflDir is called - to either verify that the directory + // exists, or if it doesn't, to create it. + + if (m_bCreateRflDir) + { + + // If it already exists, don't attempt to create it. + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->Exists( m_szRflDir))) + { + if (rc != FERR_IO_PATH_NOT_FOUND && rc != FERR_IO_INVALID_PATH) + { + goto Exit; + } + else + { + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->CreateDir( m_szRflDir))) + { + goto Exit; + } + } + } + + m_bCreateRflDir = FALSE; + } + + // Create the file + + if (RC_BAD( rc = gv_FlmSysData.pFileSystem->CreateBlockFile( szRflFileName, + F_IO_RDWR | F_IO_EXCL | F_IO_SH_DENYNONE | F_IO_DIRECT, 512, + &m_pFileHdl))) + { + goto Exit; + } + + m_pFileHdl->setMaxAutoExtendSize( m_uiRflMaxFileSize); + m_pFileHdl->setExtendSize( m_pFile->uiFileExtendSize); + + // Initialize the header. + + if (RC_BAD( rc = writeHeader( uiFileNum, 0, pucSerialNum, pucNextSerialNum, + bKeepSignature))) + { + goto Exit; + } + + m_pCurrentBuf->uiRflBufBytes = 0; + m_pCurrentBuf->uiRflFileOffset = 512; + m_pCurrentBuf->uiCurrFileNum = uiFileNum; + + // Update the size of the RFL + + if( m_bKeepRflFiles) + { + FLMUINT64 ui64RflDiskUsage; + + if( RC_BAD( rc = flmRflCalcDiskUsage( m_szRflDir, m_szDbPrefix, + m_pFile->FileHdr.uiVersionNum, &ui64RflDiskUsage))) + { + goto Exit; + } + + f_mutexLock( gv_FlmSysData.hShareMutex); + m_pFile->ui64RflDiskUsage = ui64RflDiskUsage; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + } + + +Exit: + + // Close the RFL log file AND delete it if we were not successful. + + if (RC_BAD( rc)) + { + closeFile(); + (void) gv_FlmSysData.pFileSystem->Delete( szRflFileName); + } + + return (rc); +} + +/******************************************************************** +Desc: Copy last partial sector of last buffer written (or to be + written) into a new buffer. +*********************************************************************/ +void F_Rfl::copyLastSector( + RFL_BUFFER * pBuffer, + FLMBYTE * pucOldBuffer, + FLMBYTE * pucNewBuffer, + FLMUINT uiCurrPacketLen, + FLMBOOL bStartingNewFile) +{ + FLMUINT uiOldBufBytes = pBuffer->uiRflBufBytes; + + // If we will be starting a new file, no need to keep any of + // what is in the buffer. Only the current packet needs to + // be copied - at the beginning of the buffer. + + // OTHERWISE: + + // If there are fewer than 512 bytes in the buffer, we simply + // keep them and keep appending to the buffer the next time + // we output stuff. The beginning of the buffer must ALWAYS be + // a 512 byte boundary in the file, because we want to always + // do our writing on 512 byte boundaries - because of direct IO. + + // If the number of bytes in the buffer is over 512 and it is + // evenly divisible by 512, we can clear the buffer. Otherwise, + // we want to move the extra bytes over the last 512 byte boundary + // down to the beginning of the buffer and adjust the buffer bytes + // to reflect just these left-over bytes. + + if (bStartingNewFile) + { + pBuffer->uiRflBufBytes = 0; + pBuffer->uiRflFileOffset = 512; + } + else if (pBuffer->uiRflBufBytes >= 512) + { + + // See if the number of bytes in the buffer is an exact multiple of + // 512. + + if (pBuffer->uiRflBufBytes & 511) // Not exact multiple + { + + // Round m_uiRflBufBytes down to next 512 byte boundary + + FLMUINT ui512Offset = ROUND_DOWN_TO_NEAREST_512( + pBuffer->uiRflBufBytes); + + // Move all bytes above the nearest 512 byte boundary down to + // the beginning of the buffer and adjust pBuffer->uiRflBufBytes + // and pBuffer->uiRflFileOffset accordingly. + + f_memcpy( pucNewBuffer, &pucOldBuffer[ui512Offset], + pBuffer->uiRflBufBytes - ui512Offset); + pBuffer->uiRflBufBytes -= ui512Offset; + pBuffer->uiRflFileOffset += ui512Offset; + } + else + { + pBuffer->uiRflFileOffset += pBuffer->uiRflBufBytes; + pBuffer->uiRflBufBytes = 0; + } + } + else if (pucNewBuffer != pucOldBuffer) + { + f_memcpy( pucNewBuffer, pucOldBuffer, pBuffer->uiRflBufBytes); + } + + if (uiCurrPacketLen) + { + flmAssert( uiOldBufBytes + uiCurrPacketLen <= m_uiBufferSize); + f_memmove( &pucNewBuffer[pBuffer->uiRflBufBytes], + &pucOldBuffer[uiOldBufBytes], uiCurrPacketLen); + } +} + +/******************************************************************** +Desc: Flush the RFL data from the buffer to disk. +*********************************************************************/ +RCODE F_Rfl::flush( + RFL_BUFFER * pBuffer, + FLMBOOL bFinalWrite, + FLMUINT uiCurrPacketLen, + FLMBOOL bStartingNewFile) +{ + RCODE rc = FERR_OK; + FLMUINT uiBytesWritten; + F_IOBuffer * pNewBuffer; + F_IOBuffer * pAsyncBuf = NULL; + FLMBYTE * pucOldBuffer; + FLMUINT uiFileOffset; + FLMUINT uiBufBytes; + + if (m_pFileHdl && pBuffer->uiRflBufBytes) + { + + // Must wait for stuff in committing buffer, if any, before going + // ahead here. + + if (pBuffer != m_pCommitBuf) + { + if (RC_BAD( rc = waitForCommit())) + { + goto Exit; + } + } + + if (m_uiRflWriteBufs > 1 && m_pFileHdl->CanDoAsync()) + { + pAsyncBuf = pBuffer->pIOBuffer; + } + + if ((FLMUINT) (-1) - pBuffer->uiRflFileOffset <= pBuffer->uiRflBufBytes) + { + rc = RC_SET( FERR_DB_FULL); + goto Exit; + } + + pucOldBuffer = pBuffer->pIOBuffer->m_pucBuffer; + uiFileOffset = pBuffer->uiRflFileOffset; + uiBufBytes = pBuffer->uiRflBufBytes; + if (m_uiRflWriteBufs > 1) + { + if (RC_BAD( rc = pBuffer->pBufferMgr->getBuffer( &pNewBuffer, + m_uiBufferSize, m_uiBufferSize))) + { + goto Exit; + } + + // No need to copy data if it is the final write, because it + // won't be reused anyway - the data for the next transaction has + // already been copied to another buffer. + + if (!bFinalWrite) + { + copyLastSector( pBuffer, pucOldBuffer, pNewBuffer->m_pucBuffer, + uiCurrPacketLen, bStartingNewFile); + } + } + + if( RC_OK( rc = m_pFileHdl->SectorWrite( uiFileOffset, uiBufBytes, + pucOldBuffer, + m_uiBufferSize, pAsyncBuf, &uiBytesWritten, + FALSE))) + { + if( m_bKeepRflFiles) + { + f_mutexLock( gv_FlmSysData.hShareMutex); + + if( m_pFile->uiFileExtendSize) + { + FLMUINT uiTmpSize; + + uiTmpSize = (uiFileOffset % m_pFile->uiFileExtendSize) + + (FLMUINT)flmRoundUp( uiBufBytes, + m_pFileHdl->GetSectorSize()); + + if( uiTmpSize > m_pFile->uiFileExtendSize) + { + m_pFile->ui64RflDiskUsage += m_pFile->uiFileExtendSize; + } + } + else + { + m_pFile->ui64RflDiskUsage += uiBytesWritten; + } + + f_mutexUnlock( gv_FlmSysData.hShareMutex); + } + } + + if (m_uiRflWriteBufs == 1) + { + + // We are counting on the fact that the write completed. When we + // only have one buffer, we cannot do async writes. + + flmAssert( !pAsyncBuf); + if (RC_OK( rc) && !bFinalWrite) + { + copyLastSector( pBuffer, pucOldBuffer, pucOldBuffer, + uiCurrPacketLen, bStartingNewFile); + } + + // DO NOT call notifyComplete - that would put + // pBuffer->pIOBuffer into the avail list, and we don't want + // that. We simply want to keep reusing it. + + } + else + { + + // No need to call copyLastSector, because it was called above + // before calling SectorWrite. The part of the old buffer that + // needs to be transferred to the new buffer has already been + // transferred. + + if (!pAsyncBuf) + { + pBuffer->pIOBuffer->notifyComplete( rc); + } + + pBuffer->pIOBuffer = pNewBuffer; + } + + if (RC_BAD( rc)) + { + + // Remap disk full error + + if (rc == FERR_IO_DISK_FULL) + { + rc = RC_SET( FERR_RFL_DEVICE_FULL); + m_bRflVolumeFull = TRUE; + } + + m_bRflVolumeOk = FALSE; + goto Exit; + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Switch buffers. This routine assumes the m_hBufMutex is locked. +*********************************************************************/ +void F_Rfl::switchBuffers(void) +{ + RFL_BUFFER * pOldBuffer = m_pCurrentBuf; + + if (m_pCurrentBuf == &m_Buf1) + { + m_pCurrentBuf = &m_Buf2; + } + else + { + m_pCurrentBuf = &m_Buf1; + } + + m_pCurrentBuf->bTransInProgress = pOldBuffer->bTransInProgress; + m_pCurrentBuf->uiCurrFileNum = pOldBuffer->uiCurrFileNum; + m_pCurrentBuf->uiRflBufBytes = pOldBuffer->uiRflBufBytes; + m_pCurrentBuf->uiRflFileOffset = pOldBuffer->uiRflFileOffset; + if (pOldBuffer->uiRflBufBytes) + { + copyLastSector( m_pCurrentBuf, pOldBuffer->pIOBuffer->m_pucBuffer, + m_pCurrentBuf->pIOBuffer->m_pucBuffer, 0, FALSE); + } +} + +/******************************************************************** +Desc: Wait for all RFL transaction writes to be finished. The caller + has the write lock on the database, which will prevent further + writes to the RFL. +*********************************************************************/ +FLMBOOL F_Rfl::seeIfRflWritesDone( + FLMBOOL bForceWait) +{ + FLMBOOL bWritesDone; + + f_mutexLock( m_hBufMutex); + + if (!bForceWait) + { + bWritesDone = (FLMBOOL) ((m_pCurrentBuf->pFirstWaiter || m_pCommitBuf) + ? FALSE + : TRUE); + f_mutexUnlock( m_hBufMutex); + } + else + { + + // If the current buffer has a waiter, add self to that list to + // wait, because it will be notified after the commit buffer has + // been notified. Otherwise, if there is a commit in progress, add + // self to that list to wait. + + if (m_pCurrentBuf->pFirstWaiter) + { + + // If bTransInProgress is TRUE and m_pCommitBuf is NULL then + // this thread is the current transaction, and nobody is going to + // wake up the first waiter until we are done! Hence, we must + // wake him up. + + if (!m_pCommitBuf) + { + + // If m_pCommitBuf is NULL, this could only be possible if + // there is a transaction in progress. Otherwise, there would + // not have been a pFirstWaiter, because when the commit + // buffer finishes writing, if there is a waiter, it will set + // commitbuf=currentbuf if there is no transaction active. + + flmAssert( m_pCurrentBuf->bTransInProgress); + + m_pCommitBuf = m_pCurrentBuf; + switchBuffers(); + wakeUpWaiter( FERR_OK, TRUE); + (void) waitForWrites( m_pCommitBuf, FALSE); + } + else + { + FLMBOOL bSaveTransInProgress = m_pCurrentBuf->bTransInProgress; + + // Must set bTransInProgress to FALSE so that when the writer + // of m_pCommitBuf finishes, it will signal the first waiter + // on m_pCurrentBuf. If we don't do this, m_pCommitBuf will + // simply be set to NULL, and the first waiter will never be + // woke up. + + m_pCurrentBuf->bTransInProgress = FALSE; + (void) waitForWrites( m_pCurrentBuf, FALSE); + + // It is OK to restore the trans in progress flag to what it + // was before, because whoever called this routine has a lock + // on the database, and it is his trans-in-progress state that + // should be preserved. No other thread will have been able to + // change that state because the database is locked. + + f_mutexLock( m_hBufMutex); + m_pCurrentBuf->bTransInProgress = bSaveTransInProgress; + f_mutexUnlock( m_hBufMutex); + } + } + else if (m_pCommitBuf) + { + (void) waitForWrites( m_pCommitBuf, FALSE); + } + else + { + f_mutexUnlock( m_hBufMutex); + } + + bWritesDone = TRUE; + } + + return (bWritesDone); +} + +/******************************************************************** +Desc: Wake up the first thread that is waiting on the commit buffer. +*********************************************************************/ +void F_Rfl::wakeUpWaiter( + RCODE rc, + FLMBOOL bIsWriter // Only used for debug + ) +{ + F_SEM hESem; + +#ifndef FLM_DEBUG + F_UNREFERENCED_PARM( bIsWriter); +#else + if (bIsWriter) + { + flmAssert( m_pCommitBuf->pFirstWaiter->bIsWriter); + } + else + { + flmAssert( !m_pCommitBuf->pFirstWaiter->bIsWriter); + } +#endif + + *(m_pCommitBuf->pFirstWaiter->pRc) = rc; + hESem = m_pCommitBuf->pFirstWaiter->hESem; + if ((m_pCommitBuf->pFirstWaiter = m_pCommitBuf->pFirstWaiter->pNext) == NULL) + { + m_pCommitBuf->pLastWaiter = NULL; + } + + f_semSignal( hESem); +} + +/******************************************************************** +Desc: Wait for the transaction writes to be finished. +*********************************************************************/ +RCODE F_Rfl::completeTransWrites( + FDB * pDb, + FLMBOOL bCommitting, + FLMBOOL bOkToUnlock + ) +{ + RCODE rc = FERR_OK; + RCODE tmpRc; + FLMBOOL bMutexLocked = FALSE; + FLMBOOL bNotifyWaiters = FALSE; + FLMBOOL bDbUnlocked = FALSE; + DB_STATS * pDbStats = NULL; + F_TMSTAMP StartTime; + + f_mutexLock( m_hBufMutex); + bMutexLocked = TRUE; + m_pCurrentBuf->bTransInProgress = FALSE; + + flmAssert( pDb->uiFlags & FDB_HAS_WRITE_LOCK); + + // If we are not logging, we are probably recovering or restoring the + // database. All we need to do in this case is write out the log + // header. + + if (pDb->uiFlags & FDB_REPLAYING_RFL) + { + if (pDb->bHadUpdOper && m_pCurrentBuf->bOkToWriteHdrs) + { + f_mutexUnlock( m_hBufMutex); + bMutexLocked = FALSE; + if (RC_BAD( rc = flmWriteLogHdr( pDb->pDbStats, pDb->pSFileHdl, + pDb->pFile, m_pCurrentBuf->ucLogHdr, m_pCurrentBuf->ucCPHdr, + FALSE))) + { + flmSetMustCloseFlags( pDb->pFile, rc, FALSE); + } + } + + goto Exit; + } + + // Handle empty transactions differently. These transactions should + // not do any writing and do not need to wait for all writes to + // complete, unless the bOkToUnlock flag is set to FALSE. In that case + // they must wait for all writes to complete before unlocking. + + if (!pDb->bHadUpdOper) + { + + // If the current buffer has a waiter, add self to that list to + // wait, because it will be notified after the commit buffer has + // been notified. Otherwise, if there is a commit in progress, add + // self to that list to wait. + + if (m_pCurrentBuf->pFirstWaiter) + { + + // If m_pCommitBuf is NULL then nobody is going to wake up the + // first waiter - we must do it. + + if (!m_pCommitBuf) + { + if (bOkToUnlock) + { + flmUnlinkDbFromTrans( pDb, bCommitting); + bDbUnlocked = TRUE; + } + + m_pCommitBuf = m_pCurrentBuf; + switchBuffers(); + wakeUpWaiter( FERR_OK, TRUE); + + if (!bOkToUnlock) + { + bMutexLocked = FALSE; + (void) waitForWrites( m_pCommitBuf, FALSE); + } + } + else if (!bOkToUnlock) + { + bMutexLocked = FALSE; + (void) waitForWrites( m_pCurrentBuf, FALSE); + } + } + else if (m_pCommitBuf) + { + if (!bOkToUnlock) + { + bMutexLocked = FALSE; + rc = waitForWrites( m_pCommitBuf, FALSE); + } + } + + goto Exit; + } + + // If there is a transaction committing, put self into the wait list + // on the current buffer. When the committer finishes, he will wake up + // the first thread in the list and that thread will commit the buffer. + + if (m_pCommitBuf) + { + FLMBOOL bIsWriter; + + // Another thread has to be doing the writes to m_pCommitBuf, which + // means that m_pCurrentBuf better not be equal to m_pCommitBuf. + + flmAssert( m_pCommitBuf != m_pCurrentBuf); + + // If there are no waiters, we are the first one, so when we get + // signaled, we should proceed and do the write. + + bIsWriter = m_pCurrentBuf->pFirstWaiter ? FALSE : TRUE; + if (bOkToUnlock) + { + flmUnlinkDbFromTrans( pDb, bCommitting); + bDbUnlocked = TRUE; + } + + bMutexLocked = FALSE; + rc = waitForWrites( m_pCurrentBuf, bIsWriter); + + // If we were the first one in the queue, we must now do the write. + + if (!bIsWriter) + { + goto Exit; + } + + // First one in the queue, fall through to do the write. The thread + // that woke me up better have set m_pCommitBuf See below. + + flmAssert( m_pCommitBuf); + } + else if (m_pCurrentBuf->pFirstWaiter) + { + + // Another thread is ready to commit the next set of buffers, but + // just needs to be woke up. + + if (bOkToUnlock) + { + flmUnlinkDbFromTrans( pDb, bCommitting); + bDbUnlocked = TRUE; + } + + // Need to set things up for that first waiter and get him going. + + m_pCommitBuf = m_pCurrentBuf; + switchBuffers(); + wakeUpWaiter( rc, TRUE); + + // Wait for the write to be completed. + + bMutexLocked = FALSE; + rc = waitForWrites( m_pCommitBuf, FALSE); + goto Exit; + } + else + { + m_pCommitBuf = m_pCurrentBuf; + switchBuffers(); + if (bOkToUnlock) + { + flmUnlinkDbFromTrans( pDb, bCommitting); + bDbUnlocked = TRUE; + } + + f_mutexUnlock( m_hBufMutex); + bMutexLocked = FALSE; + } + + // NOTE: From this point on we use tmpRc because we don't want to lose + // the rc that may have been set above in the call to waitForWrites; + // At this point the mutex better not be locked. + flmAssert( !bMutexLocked); + bNotifyWaiters = TRUE; + + if ((pDbStats = pDb->pDbStats) != NULL) + { + f_timeGetTimeStamp( &StartTime); + } + + // Must write out whatever we have in the commit buffer before + // unlocking the database. + + if (RC_BAD( tmpRc = flush( m_pCommitBuf, TRUE))) + { + if (RC_OK( rc)) + { + rc = tmpRc; + } + + goto Exit; + } + + // Wait for any pending IO off of the log buffer + + if (RC_BAD( tmpRc = m_pCommitBuf->pBufferMgr->waitForAllPendingIO())) + { + if (RC_OK( rc)) + { + rc = tmpRc; + } + + goto Exit; + } + + // Force the RFL writes to disk if necessary. NOTE: It is possible for + // m_pFileHdl to be NULL at this point if there were no operations + // actually logged. This happens in FlmDbUpgrade (see flconvrt.cpp). + // Even though nothing was logged the transaction is not an empty + // transaction, because it still needs to write out the log header. + + if (m_pFileHdl) + { + if (RC_BAD( tmpRc = m_pFileHdl->Flush())) + { + + // Remap disk full error + + if (tmpRc == FERR_IO_DISK_FULL) + { + rc = RC_SET( FERR_RFL_DEVICE_FULL); + m_bRflVolumeFull = TRUE; + } + else if (RC_OK( rc)) + { + rc = tmpRc; + } + + m_bRflVolumeOk = FALSE; + goto Exit; + } + } + + // Write the log header + + if (m_pCommitBuf->bOkToWriteHdrs) + { + if (RC_BAD( tmpRc = flmWriteLogHdr( pDb->pDbStats, pDb->pSFileHdl, + pDb->pFile, m_pCommitBuf->ucLogHdr, m_pCommitBuf->ucCPHdr, + FALSE))) + { + if (RC_OK( rc)) + { + rc = tmpRc; + } + + flmSetMustCloseFlags( pDb->pFile, tmpRc, FALSE); + goto Exit; + } + } + +Exit: + + if (!bDbUnlocked && bOkToUnlock) + { + flmUnlinkDbFromTrans( pDb, bCommitting); + } + + if (bNotifyWaiters) + { + FLMUINT uiNumFinished = 1; // For self + + flmAssert( !bMutexLocked); + f_mutexLock( m_hBufMutex); + bMutexLocked = TRUE; + + // Wake up any waiters + + while (m_pCommitBuf->pFirstWaiter) + { + uiNumFinished++; + wakeUpWaiter( rc, FALSE); + } + + // If there are waiters on the current buffer, the first one should + // be woke up so it can start the next set of writes. + + if (m_pCurrentBuf->pFirstWaiter && !m_pCurrentBuf->bTransInProgress) + { + flmAssert( m_pCurrentBuf != m_pCommitBuf); + m_pCommitBuf = m_pCurrentBuf; + switchBuffers(); + wakeUpWaiter( rc, TRUE); + } + else + { + m_pCommitBuf = NULL; + } + + if (pDbStats) + { + flmAddElapTime( &StartTime, + &pDbStats->UpdateTransStats.GroupCompletes.ui64ElapMilli); + pDbStats->UpdateTransStats.GroupCompletes.ui64Count++; + pDbStats->bHaveStats = TRUE; + pDbStats->UpdateTransStats.ui64GroupFinished += uiNumFinished; + } + } + + if (bMutexLocked) + { + f_mutexUnlock( m_hBufMutex); + } + + return (rc); +} + +/******************************************************************** +Desc: Calculate the checksum for a packet. +*********************************************************************/ +FLMBYTE RflCalcChecksum( + const FLMBYTE * pucPacket, + FLMUINT uiPacketBodyLen) +{ + FLMUINT uiBytesToChecksum; + FLMUINT uiChecksum = 0; + FLMBYTE ucTmp; + const FLMBYTE * pucStart; + const FLMBYTE * pucEnd; + const FLMBYTE * pucSectionEnd; + const FLMBYTE * pucCur; + + // Checksum is calculated for every byte in the packet that comes + // after the checksum byte. + + pucStart = &pucPacket[RFL_PACKET_CHECKSUM_OFFSET + 1]; + uiBytesToChecksum = (FLMUINT)(uiPacketBodyLen + + RFL_PACKET_OVERHEAD - + (RFL_PACKET_CHECKSUM_OFFSET + 1)); + + pucCur = pucStart; + pucEnd = pucStart + uiBytesToChecksum; + +#ifdef FLM_64BIT + pucSectionEnd = pucStart + (sizeof( FLMUINT) - ((FLMUINT)pucStart & 0x7)); +#else + pucSectionEnd = pucStart + (sizeof( FLMUINT) - ((FLMUINT)pucStart & 0x3)); +#endif + + if (pucSectionEnd > pucEnd) + { + pucSectionEnd = pucEnd; + } + + while (pucCur < pucSectionEnd) + { + uiChecksum = (uiChecksum << 8) +*pucCur++; + } + +#ifdef FLM_64BIT + pucSectionEnd = (FLMBYTE *)((FLMUINT)pucEnd & 0xFFFFFFFFFFFFFFF8); +#else + pucSectionEnd = (FLMBYTE *)((FLMUINT)pucEnd & 0xFFFFFFFC); +#endif + + while (pucCur < pucSectionEnd) + { + uiChecksum ^= *((FLMUINT *) pucCur); + pucCur += sizeof(FLMUINT); + } + + while (pucCur < pucEnd) + { + uiChecksum ^= *pucCur++; + } + + ucTmp = (FLMBYTE) uiChecksum; + + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE) uiChecksum; + + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE) uiChecksum; + +#ifdef FLM_64BIT + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE)uiChecksum; + + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE)uiChecksum; + + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE)uiChecksum; + + uiChecksum >>= 8; + ucTmp ^= (FLMBYTE)uiChecksum; +#endif + ucTmp ^= (FLMBYTE) (uiChecksum >> 8); + uiChecksum = ucTmp; + + if ((uiChecksum = ucTmp) == 0) + { + uiChecksum = 1; + } + + return ((FLMBYTE) uiChecksum); +} + +/******************************************************************** +Desc: Flush all completed packets out of the RFL buffer, and shift + the new partial packet down. This guarantees that there is + now room in the buffer for the maximum packet size. +*********************************************************************/ +RCODE F_Rfl::shiftPacketsDown( + FLMUINT uiCurrPacketLen, + FLMBOOL bStartingNewFile) +{ + RCODE rc = FERR_OK; + + // The call to flush will move whatever needs to be moved from the + // current buffer into a new buffer if multiple buffers are being used. + // If only one buffer is being used, it will move the part of the + // packet that needs to be moved down to the beginning of the buffer - + // AFTER writing out the buffer. + + if (RC_BAD( rc = flush( m_pCurrentBuf, FALSE, uiCurrPacketLen, + bStartingNewFile))) + { + goto Exit; + } + + // NOTE: If multiple buffers are being used, whatever was moved to the + // new buffer has not yet been written out + + if (bStartingNewFile) + { + if (RC_BAD( rc = waitPendingWrites())) + { + goto Exit; + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Determine if we should start a new file. If we are over the + low limit, and the bDoNewIfOverLowLimit flag is set, we + will start a new log file. Or, if this packet size would + put us over the upper limit, we will start a new log file. +*********************************************************************/ +RCODE F_Rfl::seeIfNeedNewFile( + FLMUINT uiPacketLen, + FLMBOOL bDoNewIfOverLowLimit) +{ + RCODE rc = FERR_OK; + FLMBYTE ucNextSerialNum[F_SERIAL_NUM_SIZE]; + + flmAssert( m_pFile); + + // If the keep files flag is FALSE, we won't start a new file. NOTE: + // This should ALWAYS be false for pre 4.3 databases. + + if (!m_bKeepRflFiles) + { + goto Exit; // Should return FERR_OK; + } + + // VERY IMPORTANT NOTE: It is preferrable that we keep transactions + // entirely contained in the same RFL file if at all possible. Note + // that it is NOT a hard and fast requirement. The system will work + // just fine if we don't. However, it would be nice if RFL files always + // ended with a commit or abort packet. This preferences is due to what + // happens after a restore operation. After a restore operation, we + // always need to start a new RFL file, but if possible, we would like + // that new RFL file to be the next one in the sequence after the last + // RFL file that was restored. We can only do this if we were able to + // restore EVERY transaction that was in the last restored RFL file - + // which we can only do if the last restored RFL file ended with a + // commit or abort packet. To accomplish this end, we try to roll to + // new files on the first transaction begin packet that occurs after we + // have exceeded our low threshold - which is why bDoNewIfOverLowLimit + // is only set to TRUE on transaction begin packets. It is set to FALSE + // on other packets so that we will continue logging the transaction in + // the same file that we started the transaction in - if possible. The + // only thing that will cause a non-transaction-begin packet to roll to + // a new file is if we would exceed the high limit. + + if ((bDoNewIfOverLowLimit && + m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes >= + m_uiRflMinFileSize) || + (m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes + + uiPacketLen >= m_uiRflMaxFileSize)) + { + FLMUINT uiCurrFileEOF = m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes; + + // Shift the current packet to the beginning of the buffer. Any + // packets in the buffer before that one will be written out to the + // current file. + + if (RC_BAD( rc = shiftPacketsDown( uiPacketLen, TRUE))) + { + goto Exit; + } + + // Update the header of the current file and close it. + + if (RC_BAD( rc = writeHeader( m_pCurrentBuf->uiCurrFileNum, uiCurrFileEOF, + m_ucCurrSerialNum, m_ucNextSerialNum, TRUE))) + { + goto Exit; + } + + // Truncate the file. + + if (!ON_512_BYTE_BOUNDARY( uiCurrFileEOF)) + { + uiCurrFileEOF = ROUND_DOWN_TO_NEAREST_512( uiCurrFileEOF) + 512; + } + + if (RC_BAD( rc = m_pFileHdl->Truncate( uiCurrFileEOF))) + { + goto Exit; + } + + // Close the file handle. + + m_pFileHdl->Close(); + m_pFileHdl->Release(); + m_pFileHdl = NULL; + + // Get the next serial number that will be used for the RFL file + // after this one. + + if (RC_BAD( rc = f_createSerialNumber( ucNextSerialNum))) + { + goto Exit; + } + + // Create next file in the sequence. Use the next serial number + // stored in the FDB's log header for the serial number on this RFL + // file. Use the serial number we just generated as the next RFL + // serial number. + + if (RC_BAD( rc = createFile( m_pCurrentBuf->uiCurrFileNum + 1, + m_ucNextSerialNum, ucNextSerialNum, TRUE))) + { + goto Exit; + } + + // Move the next serial number to the current serial number and the + // serial number we generated above into the next serial number. + + f_memcpy( m_ucCurrSerialNum, m_ucNextSerialNum, F_SERIAL_NUM_SIZE); + f_memcpy( m_ucNextSerialNum, ucNextSerialNum, F_SERIAL_NUM_SIZE); + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Finish the current RFL file - set up so that next transaction + will begin a new RFL file. +********************************************************************/ +RCODE F_Rfl::finishCurrFile( + FDB * pDb, + FLMBOOL bNewKeepState) +{ + RCODE rc = FERR_OK; + FLMBOOL bDbLocked = FALSE; + FLMUINT uiTransFileNum; + FLMUINT uiTransOffset; + FLMUINT uiTruncateSize; + FLMBYTE * pucUncommittedLogHdr; + FLMBYTE ucCheckpointLogHdr[ LOG_HEADER_SIZE]; + + // Make sure we don't have a transaction going + + if (pDb->uiTransType != FLM_NO_TRANS) + { + rc = RC_SET( FERR_TRANS_ACTIVE); + goto Exit; + } + + // Make sure there is no active backup running + + f_mutexLock( gv_FlmSysData.hShareMutex); + if (m_pFile->bBackupActive) + { + f_mutexUnlock( gv_FlmSysData.hShareMutex); + rc = RC_SET( FERR_BACKUP_ACTIVE); + goto Exit; + } + + f_mutexUnlock( gv_FlmSysData.hShareMutex); + + // Lock the database - need to prevent update transactions and + // checkpoint thread from running. + + if (RC_BAD( rc = dbLock( pDb, FLM_NO_TIMEOUT))) + { + goto Exit; + } + + bDbLocked = TRUE; + + // Must wait for all RFL writes before switching files. + + (void) seeIfRflWritesDone( TRUE); + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better not be in the middle of a transaction. + + flmAssert( !m_uiCurrTransID); + + // If DB version is less than 4.3 we cannot do this. + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; // Will return FERR_OK + } + + pucUncommittedLogHdr = &m_pFile->ucUncommittedLogHdr[0]; + + // Don't want to copy last committed log header into uncommitted log + // header if bNewKeepState is TRUE because the caller has already done + // it, and has made modifications to the uncommitted log header that we + // don't want to lose. + + if (!bNewKeepState) + { + f_memcpy( pucUncommittedLogHdr, m_pFile->ucLastCommittedLogHdr, + LOG_HEADER_SIZE); + + // If we are in a no-keep state, but we were not told that we have + // a new keep state, we cannot roll to the next RFL file, because a + // checkpoint has not been done. This is not an error - it is just + // the case where FlmDbConfig was asked to roll to the next RFL file + // when the keep flag was still FALSE. + + if (!pucUncommittedLogHdr[LOG_KEEP_RFL_FILES]) + { + goto Exit; // Will return FERR_OK + } + } + + // Get the last committed serial numbers from the file's log header + // buffer. + + f_memcpy( m_ucCurrSerialNum, + &pucUncommittedLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + + f_memcpy( m_ucNextSerialNum, &pucUncommittedLogHdr[LOG_RFL_NEXT_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + + uiTransFileNum = (FLMUINT) FB2UD( &pucUncommittedLogHdr[LOG_RFL_FILE_NUM]); + uiTransOffset = (FLMUINT) FB2UD( &pucUncommittedLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + // If the LOG_RFL_LAST_TRANS_OFFSET is zero, there is no need to go + // set up to go to the next file, because we are already poised to do + // so at the beginning of the next transaction. Just return if this is + // the case. Same for if the file does not exist. + + if (!uiTransOffset) + { + if (!bNewKeepState) + { + goto Exit; // Will return FERR_OK + } + } + else if (RC_BAD( rc = openFile( uiTransFileNum, m_ucCurrSerialNum))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) + { + rc = FERR_OK; + if (!bNewKeepState) + { + goto Exit; + } + } + else + { + goto Exit; + } + } + else + { + + // At this point, we know the file exists, so we will update its + // header and then update the log header. Note that we use the keep + // RFL state from the last committed log header, not the uncommitted + // log header - because it will contain the correct keep-state for + // the current RFL file. + + if (RC_BAD( rc = writeHeader( m_pCurrentBuf->uiCurrFileNum, uiTransOffset, + m_ucCurrSerialNum, m_ucNextSerialNum, + m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] + ? TRUE + : FALSE))) + { + goto Exit; + } + + // Truncate the file down to its EOF size - the nearest 512 byte + // boundary. + + uiTruncateSize = uiTransOffset; + if (!ON_512_BYTE_BOUNDARY( uiTruncateSize)) + { + uiTruncateSize = ROUND_DOWN_TO_NEAREST_512( uiTruncateSize) + 512; + } + + if (RC_BAD( rc = m_pFileHdl->Truncate( uiTruncateSize))) + { + goto Exit; + } + + // Close the file handle. + + m_pFileHdl->Close(); + m_pFileHdl->Release(); + m_pFileHdl = NULL; + + // Set things up in the log header to go to the next file when we + // begin the next transaction. NOTE: NO need to lock the mutex, + // because nobody but an update transaction looks at the uncommitted + // log header. + + uiTransFileNum++; + UD2FBA( (FLMUINT32) uiTransFileNum, + &pucUncommittedLogHdr[LOG_RFL_FILE_NUM]); + } + + // Generate a new current serial number if bNewKeepState is TRUE. + // Otherwise, move the next serial number into the current serial + // number. + + if (bNewKeepState) + { + if (RC_BAD( rc = f_createSerialNumber( m_ucCurrSerialNum))) + { + goto Exit; + } + } + else + { + f_memcpy( m_ucCurrSerialNum, m_ucNextSerialNum, F_SERIAL_NUM_SIZE); + } + + // Always generate a new next serial number. + + if (RC_BAD( rc = f_createSerialNumber( m_ucNextSerialNum))) + { + goto Exit; + } + + // Set transaction offset to zero. This will force the next RFL file + // to be created on the next transaction begin. It will be created even + // if it is already there. + + UD2FBA( (FLMUINT32) 0, &pucUncommittedLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + f_memcpy( &pucUncommittedLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM], + m_ucCurrSerialNum, F_SERIAL_NUM_SIZE); + + f_memcpy( &pucUncommittedLogHdr[LOG_RFL_NEXT_SERIAL_NUM], m_ucNextSerialNum, + F_SERIAL_NUM_SIZE); + + // Set the CP file number and CP offset to point into the new file. + // The outer code (FlmDbConfig) has done a checkpoint and the database + // is still locked. We need to set these values here, otherwise if we + // crash before the next checkpoint, recovery will start in the old RFL + // file, causing an FERR_BAD_RFL_SERIAL_NUM to be returned when + // traversing from the old RFL file to the new RFL file. NOTE: These + // changes must be made to the uncommitted log header AND the CP log + // header (so that they will be written out even though we are not + // forcing a checkpoint). + + if (bNewKeepState) + { +#ifdef FLM_DEBUG + // Do a quick check to see if it looks like we are in a + // checkpointed state + + if (!m_pFile->ucLastCommittedLogHdr[LOG_KEEP_RFL_FILES] && + (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_LAST_TRANS_OFFSET]) > 512) + { + flmAssert( 0); + } +#endif + + f_memcpy( ucCheckpointLogHdr, m_pFile->ucCheckpointLogHdr, + LOG_HEADER_SIZE); + + UD2FBA( (FLMUINT32) uiTransFileNum, + &ucCheckpointLogHdr[LOG_RFL_LAST_CP_FILE_NUM]); + + UD2FBA( (FLMUINT32) uiTransFileNum, + &pucUncommittedLogHdr[LOG_RFL_LAST_CP_FILE_NUM]); + + UD2FBA( (FLMUINT32) 512, &ucCheckpointLogHdr[LOG_RFL_LAST_CP_OFFSET]); + + UD2FBA( (FLMUINT32) 512, &pucUncommittedLogHdr[LOG_RFL_LAST_CP_OFFSET]); + } + + // Write out the log header to disk. + + if (RC_BAD( rc = flmWriteLogHdr( pDb->pDbStats, pDb->pSFileHdl, + m_pFile, pucUncommittedLogHdr, + bNewKeepState + ? ucCheckpointLogHdr + : m_pFile->ucCheckpointLogHdr, FALSE))) + { + goto Exit; + } + + // Copy the uncommitted log header back to the committed log header + // and copy the CP log header (if changed above). + + f_mutexLock( gv_FlmSysData.hShareMutex); + f_memcpy( m_pFile->ucLastCommittedLogHdr, pucUncommittedLogHdr, + LOG_HEADER_SIZE); + + if (bNewKeepState) + { + f_memcpy( m_pFile->ucCheckpointLogHdr, ucCheckpointLogHdr, + LOG_HEADER_SIZE); + } + + f_mutexUnlock( gv_FlmSysData.hShareMutex); + +Exit: + + if (bDbLocked) + { + (void) dbUnlock( pDb); + } + + return (rc); +} + +/******************************************************************** +Desc: Finish packet by outputting header information for it. +*********************************************************************/ +RCODE F_Rfl::finishPacket( + FLMUINT uiPacketType, + FLMUINT uiPacketBodyLen, + FLMBOOL bDoNewIfOverLowLimit) +{ + RCODE rc = FERR_OK; + FLMUINT uiEncryptPacketBodyLen; + FLMUINT uiPacketLen; + FLMBYTE * pucPacket; + + // Encrypt the packet body, if requested. + + uiEncryptPacketBodyLen = getEncryptPacketBodyLen( uiPacketType, + uiPacketBodyLen); + uiPacketLen = uiEncryptPacketBodyLen + RFL_PACKET_OVERHEAD; + + // See if this packet will cause us to overflow the limits on the + // current file. If so, create a new file. + + if (RC_BAD( rc = seeIfNeedNewFile( uiPacketLen, bDoNewIfOverLowLimit))) + { + goto Exit; + } + + // Get a pointer to packet header. + + pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[ + m_pCurrentBuf->uiRflBufBytes]); + + // Set the packet address in the packet header. + + m_uiPacketAddress = m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes; + + UD2FBA( (FLMUINT32) m_uiPacketAddress, &pucPacket[ + RFL_PACKET_ADDRESS_OFFSET]); + + // Set the packet type and packet body length. + + pucPacket[RFL_PACKET_TYPE_OFFSET] = (FLMBYTE) uiPacketType; + + UW2FBA( (FLMUINT16) uiPacketBodyLen, + &pucPacket[RFL_PACKET_BODY_LENGTH_OFFSET]); + + // Set the checksum for the packet. + + pucPacket[RFL_PACKET_CHECKSUM_OFFSET] = + RflCalcChecksum( pucPacket, uiEncryptPacketBodyLen); + + // Increment bytes in the buffer to reflect the fact that this packet + // is now complete. + + m_pCurrentBuf->uiRflBufBytes += uiPacketLen; + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Truncate roll-forward log file to a certain size - only do if + not keeping RFL files. +*********************************************************************/ +RCODE F_Rfl::truncate( + FLMUINT uiTruncateSize) +{ + RCODE rc = FERR_OK; + FLMUINT uiFileNum; + + flmAssert( uiTruncateSize >= 512); + + // Keeping of log files better not be enabled. + + flmAssert( !m_pFile->ucLastCommittedLogHdr[LOG_KEEP_RFL_FILES]); + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better not be in the middle of a transaction. + + flmAssert( !m_uiCurrTransID); + + // Open the current RFL file. If it does not exist, it is OK - there + // is nothing to truncate. + + uiFileNum = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_FILE_NUM]); + + if (RC_BAD( rc = openFile( uiFileNum, &m_pFile->ucLastCommittedLogHdr[ + LOG_LAST_TRANS_RFL_SERIAL_NUM]))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) + { + rc = FERR_OK; + } + + goto Exit; + } + + if (RC_BAD( rc = m_pFileHdl->Truncate( uiTruncateSize))) + { + m_bRflVolumeOk = FALSE; + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Setup to begin a transaction +*********************************************************************/ +RCODE F_Rfl::setupTransaction(void) +{ + RCODE rc = FERR_OK; + FLMUINT uiFileNum; + FLMUINT uiLastTransOffset; + FLMBOOL bCreateFile; + + f_mutexLock( m_hBufMutex); + m_pCurrentBuf->bTransInProgress = TRUE; + f_mutexUnlock( m_hBufMutex); + + // Get the last committed serial numbers from the file's log header + // buffer. + + f_memcpy( m_ucCurrSerialNum, + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + + f_memcpy( m_ucNextSerialNum, + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_NEXT_SERIAL_NUM], + F_SERIAL_NUM_SIZE); + + uiFileNum = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_FILE_NUM]); + + uiLastTransOffset = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_LAST_TRANS_OFFSET]); + + // If the LOG_RFL_LAST_TRANS_OFFSET is zero, we need to create the + // next RFL file number no matter what. There are two cases where this + // happens: 1) when the database is first created, and 2) after a + // restore operation. + + if (!uiLastTransOffset) + { + bCreateFile = TRUE; + + // Close the current file, just in case we had opened it before. At + // this point, it doesn't matter because we are going to overwrite + // it. + + if (RC_BAD( rc = waitForCommit())) + { + goto Exit; + } + + closeFile(); + } + else if (RC_BAD( rc = openFile( uiFileNum, m_ucCurrSerialNum))) + { + if (rc != FERR_IO_PATH_NOT_FOUND && rc != FERR_IO_INVALID_PATH) + { + goto Exit; + } + + bCreateFile = TRUE; + } + else + { + bCreateFile = FALSE; + } + + if (bCreateFile) + { + + // If the log header indicates that data has already been logged to + // the file, we need to return the I/O error rather than just + // re-creating the file. This may mean that someone changed the RFL + // directory without moving the RFL files properly. + + if (uiLastTransOffset > 512) + { + rc = RC_SET( FERR_RFL_FILE_NOT_FOUND); + goto Exit; + } + + // Create the RFL file if not found. Use the next serial number + // stored in the FDB's log header for the serial number on this RFL + // file. Use the serial number we just generated as the next RFL + // serial number. + + if (RC_BAD( rc = createFile( uiFileNum, + m_ucCurrSerialNum, m_ucNextSerialNum, + m_pFile->ucLastCommittedLogHdr [LOG_KEEP_RFL_FILES] + ? TRUE + : FALSE))) + { + goto Exit; + } + } + else + { + + // Read in enough of the buffer from the RFL file so that we are + // positioned on a 512 byte boundary. + + if (RC_BAD( positionTo( uiLastTransOffset))) + { + goto Exit; + } + } + + // These can only be changed when starting a transaction. + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_3) + { + m_bKeepRflFiles = m_pFile->ucLastCommittedLogHdr[LOG_KEEP_RFL_FILES] + ? TRUE + : FALSE; + + m_uiRflMaxFileSize = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_MAX_FILE_SIZE]); + + // Round maximum down to nearest 512 boundary. This is necessary + // because we always write a minimum of 512 byte units in direct IO + // mode. If we did not round the maximum down, our last packet could + // end at an offset that is less than the maximum, but greater than + // the nearest 512 byte boundary - technically within the + // user-specified size limit. However, because we always write a + // full 512 bytes of data to fill out the last sector when we are in + // direct IO mode, we would end up with a file that was slightly + // larger than the user-specified limit. The EOF in the header of + // the file would be below the limit, but the actual file size would + // not be. Thus, the need to round down. + + m_uiRflMaxFileSize = ROUND_DOWN_TO_NEAREST_512( m_uiRflMaxFileSize); + + // The maximum cannot go below a certain threshold - must have room + // for least one packet plus the header. + + if (m_uiRflMaxFileSize < RFL_MAX_PACKET_SIZE + 512) + { + m_uiRflMaxFileSize = RFL_MAX_PACKET_SIZE + 512; + } + else if (m_uiRflMaxFileSize > gv_FlmSysData.uiMaxFileSize) + { + m_uiRflMaxFileSize = gv_FlmSysData.uiMaxFileSize; + } + } + else + { + m_bKeepRflFiles = FALSE; + m_uiRflMaxFileSize = gv_FlmSysData.uiMaxFileSize; + } + + m_uiRflMinFileSize = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_MIN_FILE_SIZE]); + + // Minimum RFL file size should not be allowed to be larger than + // maximum! + + if (m_uiRflMinFileSize > m_uiRflMaxFileSize) + { + m_uiRflMinFileSize = m_uiRflMaxFileSize; + } + + // Set the operation count to zero. + + m_uiOperCount = 0; + + // Set file extend sizes + + m_pFileHdl->setMaxAutoExtendSize( m_uiRflMaxFileSize); + m_pFileHdl->setExtendSize( m_pFile->uiFileExtendSize); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log transaction begin. This routine will also make sure + we have opened an RFL file. + NOTE: The prior version of FLAIM (before 4.3) would log + a time and set the RFL_TIME_LOGGED_FLAG bit in the packet + type. This is no longer done. Old code should be + compatible because it reads the flag. +*********************************************************************/ +RCODE F_Rfl::logBeginTransaction( + FDB * pDb) +{ + RCODE rc = FERR_OK; + FLMUINT uiDbVersion = pDb->pFile->FileHdr.uiVersionNum; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + FLMUINT uiGMTTime; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better not be in the middle of a transaction. + + flmAssert( !m_uiCurrTransID); + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = uiDbVersion >= FLM_FILE_FORMAT_VER_4_31 ? 12 : 8; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) pDb->LogHdr.uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // This used to be a FLM_GET_TIMER() value in pre-4.3 code, but it was + // never really used. Set it to GMT time now. + + f_timeGetSeconds( &uiGMTTime); + UD2FBA( (FLMUINT32) uiGMTTime, pucPacketBody); + pucPacketBody += 4; + + // NOTE: In the pre-4.3 code the next four bytes would be zero, but + // that is really unnecessary. We will simply no longer set the + // RFL_TIME_LOGGED_FLAG bit in the packet type. Pre-4.3 code should be + // compatible. + + if (uiDbVersion >= FLM_FILE_FORMAT_VER_4_31) + { + FLMUINT uiLastLoggedCommitID; + + uiLastLoggedCommitID = FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_RFL_COMMIT_ID]); + + UD2FBA( (FLMUINT32) uiLastLoggedCommitID, pucPacketBody); + pucPacketBody += 4; + + if (RC_BAD( rc = finishPacket( RFL_TRNS_BEGIN_EX_PACKET, uiPacketBodyLen, + TRUE))) + { + goto Exit; + } + } + else + { + if (RC_BAD( rc = finishPacket( RFL_TRNS_BEGIN_PACKET, uiPacketBodyLen, + TRUE))) + { + goto Exit; + } + } + + // Save the file offset for the start transaction packet. + + m_uiTransStartFile = m_pCurrentBuf->uiCurrFileNum; + m_uiTransStartAddr = m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes - + uiPacketBodyLen - + RFL_PACKET_OVERHEAD; + m_uiCurrTransID = pDb->LogHdr.uiCurrTransID; + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Flushes the RFL and sets some things in the log header. +*********************************************************************/ +void F_Rfl::finalizeTransaction(void) +{ + FLMUINT uiRflTransEndOffset; + FLMBYTE * pucLogHdr = &m_pFile->ucUncommittedLogHdr[0]; + + // Save the serial numbers and file numbers into the file's + // uncommitted log header. + + UD2FBA( (FLMUINT32) m_pCurrentBuf->uiCurrFileNum, + &pucLogHdr[LOG_RFL_FILE_NUM]); + + uiRflTransEndOffset = getCurrWriteOffset(); + UD2FBA( (FLMUINT32) uiRflTransEndOffset, + &pucLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + f_memcpy( &pucLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM], m_ucCurrSerialNum, + F_SERIAL_NUM_SIZE); + + f_memcpy( &pucLogHdr[LOG_RFL_NEXT_SERIAL_NUM], m_ucNextSerialNum, + F_SERIAL_NUM_SIZE); +} + +/******************************************************************** +Desc: Handles the commit and abort log operations. If aborting + the transaction, or if the transaction was empty, we will + simply throw away the entire transaction and not bother + to log it. In that case we will reset transaction pointers, + etc. back to the file and offset where the transaction began. + We will also delete RFL files that were created during the + transaction if necessary. NOTE: It is not essential that + the RFL files be deleted. If they are not successfully + deleted, they will be overwritten if need be when creating + new ones. +Note: The prior version of FLAIM (before 4.3) would log + a time and set the RFL_TIME_LOGGED_FLAG bit in the packet + type. This is no longer done. Old code should be + compatible because it reads the flag. +*********************************************************************/ +RCODE F_Rfl::logEndTransaction( + FLMUINT uiPacketType, + FLMBOOL bThrowLogAway, + FLMBOOL * pbLoggedTransEnd) +{ + RCODE rc = FERR_OK; + RCODE rc2 = FERR_OK; + FLMUINT uiLowFileNum; + FLMUINT uiHighFileNum; + char szRflFileName[F_PATH_MAX_SIZE]; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Initialize the "logged trans end" flag + + if (pbLoggedTransEnd) + { + *pbLoggedTransEnd = FALSE; + } + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + flmAssert( m_pFileHdl); + flmAssert( m_pFile); + + // If the transaction had no operations, throw it away - don't even + // log the packet. An abort operation may also elect to throw the log + // away even if there were operations. That is determined by the + // bThrowLogAway flag. The bThrowLogAway flag may be TRUE when doing a + // commit if the caller knows that nothing happened during the + // transction. + + if (bThrowLogAway || !m_uiOperCount) + { +Throw_Away_Transaction: + + // If we have switched files, delete all but the file we started in. + + if (m_pCurrentBuf->uiCurrFileNum != m_uiTransStartFile) + { + flmAssert( m_pCurrentBuf->uiCurrFileNum > m_uiTransStartFile); + + // File number in uncommitted log header better not have been + // changed yet. It is only supposed to be changed when the + // transaction finishes - i.e., in this routine. Up until this + // point, it should only be changed in + // m_pCurrentBuf->uiCurrFileNum. + + flmAssert( m_uiTransStartFile == (FLMUINT) FB2UD( + &m_pFile->ucUncommittedLogHdr[LOG_RFL_FILE_NUM])); + + uiLowFileNum = m_uiTransStartFile + 1; + uiHighFileNum = m_pCurrentBuf->uiCurrFileNum; + + // Close the current file so it can be deleted. + + if (RC_BAD( rc = waitForCommit())) + { + goto Exit; + } + + closeFile(); + + // Delete as many of the files as possible. Don't worry about + // errors here. + + while (uiLowFileNum <= uiHighFileNum) + { + if (RC_OK( getFullRflFileName( uiLowFileNum, szRflFileName))) + { + (void) gv_FlmSysData.pFileSystem->Delete( szRflFileName); + } + + uiLowFileNum++; + } + } + else + { + + // If we are in the file the transaction started in, simply + // reset to where the transaction started. + + if (RC_BAD( rc2 = positionTo( m_uiTransStartAddr))) + { + + // If we got to this point because of a "goto + // Throw_Away_Transaction", we don't want to clobber the + // original error code. So, we use rc2 temporarily and then + // determine if its value should be set into rc. + + if (RC_OK( rc)) + { + rc = rc2; + } + + rc2 = FERR_OK; + goto Exit; + } + } + } + else + { + + // Log a commit or abort packet. + + uiPacketBodyLen = 8; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Throw_Away_Transaction; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + UD2FBA( (FLMUINT32) m_uiTransStartAddr, pucPacketBody); + pucPacketBody += 4; + if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, FALSE))) + { + goto Throw_Away_Transaction; + } + + finalizeTransaction(); + + if (pbLoggedTransEnd) + { + *pbLoggedTransEnd = TRUE; + } + } + +Exit: + + if (!m_bLoggingOff) + { + m_uiCurrTransID = 0; + } + + return (RC_BAD( rc) ? rc : rc2); +} + +/******************************************************************** +Desc: Log add, modify, delete, and reserve DRN packets +*********************************************************************/ +RCODE F_Rfl::logUpdatePacket( + FLMUINT uiPacketType, + FLMUINT uiContainer, + FLMUINT uiDrn, + FLMUINT uiAutoTrans) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better be in the middle of a transaction. + + flmAssert( m_uiCurrTransID); + + m_uiOperCount++; + + if (uiPacketType == RFL_ADD_RECORD_PACKET_VER_2 || + uiPacketType == RFL_MODIFY_RECORD_PACKET_VER_2 || + uiPacketType == RFL_DELETE_RECORD_PACKET_VER_2) + { + uiPacketBodyLen = 11; + } + else + { + uiPacketBodyLen = 10; + } + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the container number. + + UW2FBA( (FLMUINT16) uiContainer, pucPacketBody); + pucPacketBody += 2; + + // Output the DRN. + + UD2FBA( (FLMUINT32) uiDrn, pucPacketBody); + pucPacketBody += 4; + + // Output the flags + + if (uiPacketType == RFL_ADD_RECORD_PACKET_VER_2 || + uiPacketType == RFL_MODIFY_RECORD_PACKET_VER_2 || + uiPacketType == RFL_DELETE_RECORD_PACKET_VER_2) + { + FLMUINT uiFlags = 0; + + // For now, these are the only flags we log + + if (uiAutoTrans & FLM_DO_IN_BACKGROUND) + { + uiFlags |= RFL_UPDATE_BACKGROUND; + } + + if (uiAutoTrans & FLM_SUSPENDED) + { + uiFlags |= RFL_UPDATE_SUSPENDED; + } + + *pucPacketBody++ = (FLMBYTE) uiFlags; + } + + // Finish the packet + + if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, FALSE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log index suspend and resume packets +*********************************************************************/ +RCODE F_Rfl::logIndexSuspendOrResume( + FLMUINT uiIndexNum, + FLMUINT uiPacketType) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // This call is new with 4.51 databases - not supported in older + // versions, so don't log it. + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_51) + { + goto Exit; + } + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better be in the middle of a transaction. + + flmAssert( m_uiCurrTransID); + + m_uiOperCount++; + uiPacketBodyLen = 6; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the index number. + + UW2FBA( (FLMUINT16) uiIndexNum, pucPacketBody); + pucPacketBody += 2; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( uiPacketType, uiPacketBodyLen, FALSE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: +*********************************************************************/ +RCODE F_Rfl::logSizeEventConfig( + FLMUINT uiTransID, + FLMUINT uiSizeThreshold, + FLMUINT uiSecondsBetweenEvents, + FLMUINT uiBytesBetweenEvents) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Don't log the operation if it isn't supported by the current database + // version + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_61) + { + goto Exit; + } + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // We need to set up to log this packet as if we were logging a + // transaction. The only difference is that we don't log the begin + // transaction packet. + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = 16; + + // Make sure we have space in the RFL buffer for a complete packet. + + if( !haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) uiTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the size threshold + + UD2FBA( (FLMUINT32) uiSizeThreshold, pucPacketBody); + pucPacketBody += 4; + + // Output the time frequency + + UD2FBA( (FLMUINT32) uiSecondsBetweenEvents, pucPacketBody); + pucPacketBody += 4; + + // Output the size frequency + + UD2FBA( (FLMUINT32) uiBytesBetweenEvents, pucPacketBody); + pucPacketBody += 4; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_CONFIG_SIZE_EVENT_PACKET, + uiPacketBodyLen, TRUE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Make room in the RFL buffer for the additional bytes. + This is done by flushing the log buffer and shifting down + the bytes already used in the current packet. If that doesn't + make room, the current packet will be finished and a new one + started. +*********************************************************************/ +RCODE F_Rfl::makeRoom( + FLMUINT uiAdditionalBytesNeeded, + FLMUINT * puiCurrPacketLenRV, + FLMUINT uiPacketType, + FLMUINT * puiBytesAvailableRV, + FLMUINT * puiPacketCountRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiBytesNeeded; + + // Must account for encryption, so round bytes needed to nearest four + // byte boundary. + + uiBytesNeeded = *puiCurrPacketLenRV + uiAdditionalBytesNeeded; + if (uiBytesNeeded & 0x3) + { + uiBytesNeeded += (4 - (uiBytesNeeded & 0x3)); + } + + if (uiBytesNeeded <= (FLMUINT) RFL_MAX_PACKET_SIZE) + { + FLMUINT uiTmp = uiBytesNeeded; + + if (haveBuffSpace( uiTmp)) + { + if (puiBytesAvailableRV) + { + *puiBytesAvailableRV = uiAdditionalBytesNeeded; + } + } + else + { + + // Bytes requested will fit into a packet, but not the buffer, + // so we need to shift the packets in the buffer down. The + // shiftPacketsDown guarantees that there is room in the buffer + // for a full size packet. + + if (RC_BAD( rc = shiftPacketsDown( *puiCurrPacketLenRV, FALSE))) + { + goto Exit; + } + + // If a non-NULL puwBytesAvailableRV is passed in it means that + // we are to return the number of bytes that we can actually + // output. Since we know there is enough for the bytes needed, we + // simply return the number of bytes that were requested. + + if (puiBytesAvailableRV) + { + *puiBytesAvailableRV = uiAdditionalBytesNeeded; + } + } + } + else // (uiBytesNeeded > RFL_MAX_PACKET_SIZE) + { + + // This is the case where the bytes needed would overflow the + // maximum packet size. If puwBytesAvailableRV is NULL, it means + // that all of the requested additional bytes must fit into the + // packet. In that case, since the requested bytes would put us over + // the packet size limit, we must finish the current packet and then + // flush the packets out of the buffer so we can start a new packet. + + if (!puiBytesAvailableRV) + { + + // Finish the current packet and start a new one. + + if (puiPacketCountRV) + { + (*puiPacketCountRV)++; + } + + if (RC_BAD( rc = finishPacket( uiPacketType, + *puiCurrPacketLenRV - RFL_PACKET_OVERHEAD, FALSE))) + { + goto Exit; + } + + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + + *puiCurrPacketLenRV = RFL_PACKET_OVERHEAD; + } + else + { + + // When puiBytesAvailableRV is non-NULL, it means we can fill up + // the rest of the packet with part of the bytes. In this case we + // return the number of bytes available and then shift the + // packets down in the buffer to make sure there is room for a + // full-size packet. + + *puiBytesAvailableRV = RFL_MAX_PACKET_SIZE -*puiCurrPacketLenRV; + if (RC_BAD( rc = shiftPacketsDown( *puiCurrPacketLenRV, FALSE))) + { + goto Exit; + } + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log a chunk of data to the RFL log - typically used to log + field data. Will spill over into multiple packets if + necessary. +*********************************************************************/ +RCODE F_Rfl::logData( + FLMUINT uiDataLen, + const FLMBYTE * pucData, + FLMUINT uiPacketType, + FLMUINT * puiPacketLenRV, + FLMUINT * puiPacketCountRV, + FLMUINT * puiMaxLogBytesNeededRV, + FLMUINT * puiTotalBytesLoggedRV) +{ + RCODE rc = FERR_OK; + FLMUINT uiBytesAvail; + FLMBYTE * pucDest; + + while (uiDataLen) + { + if (RC_BAD( rc = makeRoom( uiDataLen, puiPacketLenRV, uiPacketType, + &uiBytesAvail, puiPacketCountRV))) + { + goto Exit; + } + + if (uiBytesAvail) + { + if (puiMaxLogBytesNeededRV) + { + if (RC_BAD( rc = RflCheckMaxLogged( puiMaxLogBytesNeededRV, + *puiPacketCountRV, puiTotalBytesLoggedRV, uiBytesAvail))) + { + goto Exit; + } + } + + pucDest = getPacketPtr() + (*puiPacketLenRV); + f_memcpy( pucDest, pucData, uiBytesAvail); + uiDataLen -= uiBytesAvail; + pucData += uiBytesAvail; + (*puiPacketLenRV) += uiBytesAvail; + } + + // If we didn't get all of the data into the RFL buffer, finish and + // flush the current packet. + + if (uiDataLen) + { + if (puiPacketCountRV) + { + (*puiPacketCountRV)++; + } + + if (RC_BAD( rc = finishPacket( uiPacketType, + *puiPacketLenRV - RFL_PACKET_OVERHEAD, FALSE))) + { + goto Exit; + } + + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + + *puiPacketLenRV = RFL_PACKET_OVERHEAD; + if (puiMaxLogBytesNeededRV) + { + if (RC_BAD( rc = RflCheckMaxLogged( puiMaxLogBytesNeededRV, + *puiPacketCountRV, puiTotalBytesLoggedRV, + RFL_PACKET_OVERHEAD))) + { + goto Exit; + } + } + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Check to see if by logging the requested number of bytes we + will end up exceeding the maximum bytes needed. If so, and + we have not yet actually logged a packet, return + FERR_FAILURE so that we will discard this packet that is + being built. If we have already logged a packet, it is + too late to discard what has been done. +*********************************************************************/ +FSTATIC RCODE RflCheckMaxLogged( + FLMUINT * puiMaxBytesNeededRV, + FLMUINT uiPacketsLogged, + FLMUINT * puiCurrTotalLoggedRV, + FLMUINT uiBytesToLog) +{ + RCODE rc = FERR_OK; + + *puiCurrTotalLoggedRV += uiBytesToLog; + + if ((!uiPacketsLogged) && (*puiCurrTotalLoggedRV > *puiMaxBytesNeededRV)) + { + rc = RC_SET( FERR_FAILURE); + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Callback function that captures the changes being logged by + the call to flmRecordDifference. +*********************************************************************/ +FSTATIC void RflChangeCallback( + GRD_DifferenceData& DiffData, + void * CallbackData) +{ + RFL_CHANGE_DATA * pRflChangeData = (RFL_CHANGE_DATA*) CallbackData; + F_Rfl * pRfl = pRflChangeData->pRfl; + void * pvField; + const FLMBYTE * pucExportPtr; + FLMBYTE * pucTmp; + FLMUINT uiOverhead = 0; + FLMUINT uiBytesToLog; + FLMUINT uiPos; + FLMUINT uiTagNum; + FLMUINT uiDataLen; + FLMBOOL bEncrypted = FALSE; + FLMUINT uiEncId; + + // If we had an error before this callback, do nothing. + + if (RC_BAD( pRflChangeData->rc)) + { + goto Exit; + } + + if (DiffData.pvAfterField) + { + flmAssert( DiffData.pAfterRecord); + bEncrypted = DiffData.pAfterRecord->isEncryptedField( DiffData.pvAfterField); + } + + switch (DiffData.type) + { + case GRD_Inserted: + { + uiOverhead = (bEncrypted ? 13 : 9); + break; + } + + case GRD_Deleted: + { + // Ignore these for versions of the database >= 4.60 + + if (pRflChangeData->uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) + { + goto Exit; + } + + uiOverhead = 3; + break; + } + + case GRD_DeletedSubtree: + { + // Ignore these for versions of the database < 4.60 + + if (pRflChangeData->uiVersionNum < FLM_FILE_FORMAT_VER_4_60) + { + goto Exit; + } + + uiOverhead = 3; + break; + } + + case GRD_Modified: + { + uiOverhead = (bEncrypted ? 10 : 6); + break; + } + + default: + { + flmAssert( 0); + break; + } + } + + // Determine the number of bytes that will actually be logged with + // this overhead. If it won't fit in the current packet, we will have + // to create a new packet - hence, we add RFL_PACKET_OVERHEAD to the + // amount that will be logged. + + uiBytesToLog = uiOverhead; + if (RFL_MAX_PACKET_SIZE - uiOverhead < pRflChangeData->uiCurrPacketLen) + { + uiBytesToLog += RFL_PACKET_OVERHEAD; + } + + // See if the bytes we are going log will exceed the maximum bytes + // needed. + + if (RC_BAD( pRflChangeData->rc = RflCheckMaxLogged( + &pRflChangeData->uiMaxLogBytesNeeded, + pRflChangeData->uiPacketCount, + &pRflChangeData->uiTotalBytesLogged, uiBytesToLog))) + { + goto Exit; + } + + // Make room to log the overhead + + if (RC_BAD( pRflChangeData->rc = pRfl->makeRoom( uiOverhead, + &pRflChangeData->uiCurrPacketLen, RFL_CHANGE_FIELDS_PACKET, NULL, + &pRflChangeData->uiPacketCount))) + { + goto Exit; + } + + pucTmp = pRfl->getPacketPtr() + pRflChangeData->uiCurrPacketLen; + uiPos = DiffData.uiAbsolutePosition; + UW2FBA( (FLMUINT16) uiPos, &pucTmp[1]); + pRflChangeData->uiCurrPacketLen += uiOverhead; + pvField = DiffData.pvAfterField; + + switch (DiffData.type) + { + case GRD_Inserted: + { + *pucTmp = (bEncrypted ? RFL_INSERT_ENC_FIELD : RFL_INSERT_FIELD); + pucTmp += 3; + uiTagNum = DiffData.pAfterRecord->getFieldID( pvField); + UW2FBA( (FLMUINT16) uiTagNum, pucTmp); + pucTmp += 2; + *pucTmp++ = (FLMBYTE) DiffData.pAfterRecord->getDataType( pvField); + *pucTmp++ = (FLMBYTE) DiffData.pAfterRecord->getLevel( pvField); + uiDataLen = DiffData.pAfterRecord->getDataLength( pvField); + UW2FBA( (FLMUINT16) uiDataLen, pucTmp); + pucTmp += 2; + + if (bEncrypted) + { + uiEncId = DiffData.pAfterRecord->getEncryptionID( pvField); + flmAssert( uiEncId); + UW2FBA( (FLMUINT16) uiEncId, pucTmp); + pucTmp += 2; + + uiDataLen = DiffData.pAfterRecord->getEncryptedDataLength( pvField); + UW2FBA( uiDataLen, pucTmp); + pucTmp += 2; + } + + // Log the data, if any. + + if (uiDataLen) + { + if (bEncrypted) + { + pucExportPtr = DiffData.pAfterRecord->getEncryptionDataPtr( pvField); + } + else + { + pucExportPtr = DiffData.pAfterRecord->getDataPtr( pvField); + } + + if (!pucExportPtr) + { + pRflChangeData->rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( pRflChangeData->rc = pRfl->logData( uiDataLen, + pucExportPtr, RFL_CHANGE_FIELDS_PACKET, + &pRflChangeData->uiCurrPacketLen, + &pRflChangeData->uiPacketCount, + &pRflChangeData->uiMaxLogBytesNeeded, + &pRflChangeData->uiTotalBytesLogged))) + { + goto Exit; + } + } + + break; + } + + case GRD_Deleted: + case GRD_DeletedSubtree: + { + *pucTmp = RFL_DELETE_FIELD; + break; + } + + case GRD_Modified: + { + *pucTmp = (bEncrypted ? RFL_MODIFY_ENC_FIELD : RFL_MODIFY_FIELD); + pucTmp += 3; + + // For now, just log the new bytes using RFL_REPLACE_BYTES option + + *pucTmp++ = RFL_REPLACE_BYTES; + uiDataLen = DiffData.pAfterRecord->getDataLength( pvField); + UW2FBA( (FLMUINT16) uiDataLen, pucTmp); + pucTmp += 2; + + if (bEncrypted) + { + uiEncId = DiffData.pAfterRecord->getEncryptionID( pvField); + flmAssert( uiEncId); + UW2FBA( (FLMUINT16) uiEncId, pucTmp); + pucTmp += 2; + + uiDataLen = DiffData.pAfterRecord->getEncryptedDataLength( pvField); + UW2FBA( uiDataLen, pucTmp); + pucTmp += 2; + } + + // Log the data, if any. + + if (uiDataLen) + { + if (bEncrypted) + { + pucExportPtr = DiffData.pAfterRecord->getEncryptionDataPtr( pvField); + } + else + { + pucExportPtr = DiffData.pAfterRecord->getDataPtr( pvField); + } + + if (pucExportPtr == NULL) + { + pRflChangeData->rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( pRflChangeData->rc = pRfl->logData( uiDataLen, + pucExportPtr, RFL_CHANGE_FIELDS_PACKET, + &pRflChangeData->uiCurrPacketLen, + &pRflChangeData->uiPacketCount, + &pRflChangeData->uiMaxLogBytesNeeded, + &pRflChangeData->uiTotalBytesLogged))) + { + goto Exit; + } + } + + break; + } + + default: + { + flmAssert( 0); + break; + } + } + +Exit: + + return; +} + +/******************************************************************** +Desc: Log change fields for a record modify operation. +*********************************************************************/ +RCODE F_Rfl::logChangeFields( + FlmRecord * pOldRecord, + FlmRecord * pNewRecord) +{ + RFL_CHANGE_DATA RflChangeData; + FLMUINT uiTmpBodyLen; + FLMUINT uiDataLen; + void * pvNewField; + FLMBOOL bEncrypted; + FLMUINT uiOverhead; + + RflChangeData.rc = FERR_OK; + RflChangeData.pRfl = this; + RflChangeData.uiVersionNum = m_pFile->FileHdr.uiVersionNum; + + // Determine the total amount that would have to be logged if we just + // logged the new record. + + RflChangeData.uiMaxLogBytesNeeded = RFL_PACKET_OVERHEAD; + uiTmpBodyLen = 0; + pvNewField = pNewRecord->root(); + for (; pvNewField; pvNewField = pNewRecord->next( pvNewField)) + { + bEncrypted = pNewRecord->isEncryptedField( pvNewField); + uiOverhead = (bEncrypted ? 10 : 6); + if (uiTmpBodyLen + uiOverhead <= RFL_MAX_PACKET_BODY_SIZE) + { + uiTmpBodyLen += uiOverhead; + } + else + { + uiTmpBodyLen = uiOverhead; + RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; + } + + RflChangeData.uiMaxLogBytesNeeded += uiOverhead; + if (bEncrypted) + { + uiDataLen = pNewRecord->getEncryptedDataLength( pvNewField); + } + else + { + uiDataLen = pNewRecord->getDataLength( pvNewField); + } + + while (uiDataLen) + { + FLMUINT uiTmp; + + uiTmp = RFL_MAX_PACKET_BODY_SIZE - uiTmpBodyLen; + if (uiTmp >= uiDataLen) + { + uiTmp = uiDataLen; + uiTmpBodyLen += uiDataLen; + } + else + { + uiTmpBodyLen = 0; + RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; + } + + RflChangeData.uiMaxLogBytesNeeded += uiTmp; + uiDataLen -= uiTmp; + } + } + + // Account for terminating 0 at the end. + + if (uiTmpBodyLen + 2 > RFL_MAX_PACKET_BODY_SIZE) + { + RflChangeData.uiMaxLogBytesNeeded += RFL_PACKET_OVERHEAD; + } + + RflChangeData.uiMaxLogBytesNeeded += 2; + + RflChangeData.uiPacketCount = 0; + RflChangeData.uiTotalBytesLogged = RFL_PACKET_OVERHEAD; + RflChangeData.uiCurrPacketLen = RFL_PACKET_OVERHEAD; + + if (!haveBuffSpace( RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( RflChangeData.rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + flmRecordDifference( pOldRecord, pNewRecord, RflChangeCallback, + (void *) &RflChangeData); + + // See if we exceeded the maximum log bytes. If so, just log the + // changed record in its entirety. + + if (RC_BAD( RflChangeData.rc)) + { + if (RflChangeData.rc == FERR_FAILURE) + { + RflChangeData.rc = logRecord( pNewRecord); + } + + goto Exit; + } + else + { + FLMBYTE * pucTmp; + + // Make room to log the 3 bytes of terminator + + if (RC_BAD( RflChangeData.rc = makeRoom( 3, + &RflChangeData.uiCurrPacketLen, RFL_CHANGE_FIELDS_PACKET, NULL, + &RflChangeData.uiPacketCount))) + { + if (RflChangeData.rc == FERR_FAILURE) + { + RflChangeData.rc = logRecord( pNewRecord); + } + + goto Exit; + } + + pucTmp = getPacketPtr() + RflChangeData.uiCurrPacketLen; + *pucTmp++ = RFL_END_FIELD_CHANGES; + UW2FBA( (FLMUINT16) 0, pucTmp); + RflChangeData.uiCurrPacketLen += 3; + + if (RC_BAD( RflChangeData.rc = finishPacket( RFL_CHANGE_FIELDS_PACKET, + RflChangeData.uiCurrPacketLen - RFL_PACKET_OVERHEAD, FALSE))) + { + goto Exit; + } + } + +Exit: + + return (RflChangeData.rc); +} + +/******************************************************************** +Desc: Log a record for the record add or modify operations. +*********************************************************************/ +RCODE F_Rfl::logRecord( + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + FLMUINT uiPacketLen = RFL_PACKET_OVERHEAD; + void * pvField; + FLMBYTE * pucTmp; + FLMUINT uiTagNum; + FLMUINT uiDataLen; + FLMBOOL bEncrypted; + FLMUINT uiEncId; + FLMUINT uiPacketType; + FLMUINT uiOverhead; + + if (!haveBuffSpace( RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_60) + { + uiPacketType = RFL_DATA_RECORD_PACKET; + } + else + { + uiPacketType = RFL_ENC_DATA_RECORD_PACKET; + } + + pvField = pRecord->root(); + for (; pvField; pvField = pRecord->next( pvField)) + { + if (uiPacketType == RFL_DATA_RECORD_PACKET) + { + bEncrypted = FALSE; + uiOverhead = 6; + } + else + { + bEncrypted = pRecord->isEncryptedField( pvField); + uiOverhead = (bEncrypted ? 11 : 7); + } + + if (RC_BAD( rc = makeRoom( uiOverhead, &uiPacketLen, uiPacketType, NULL, + NULL))) + { + goto Exit; + } + + pucTmp = getPacketPtr() + uiPacketLen; + uiPacketLen += uiOverhead; + + uiTagNum = pRecord->getFieldID( pvField); + UW2FBA( (FLMUINT16) uiTagNum, pucTmp); + pucTmp += 2; + *pucTmp++ = (FLMBYTE) pRecord->getDataType( pvField); + *pucTmp++ = (FLMBYTE) pRecord->getLevel( pvField); + uiDataLen = pRecord->getDataLength( pvField); + UW2FBA( (FLMUINT16) uiDataLen, pucTmp); + pucTmp += 2; + + // Record if this field is encrypted. If it is, then there will be + // more data to follow. + + if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) + { + *pucTmp = (bEncrypted ? (FLMBYTE) 1 : (FLMBYTE) 0); + pucTmp++; + + // Check for encrypted field and add the results. + + if (bEncrypted) + { + uiEncId = pRecord->getEncryptionID( pvField); + flmAssert( uiEncId); + UW2FBA( (FLMUINT16) uiEncId, pucTmp); + pucTmp += 2; + + uiDataLen = pRecord->getEncryptedDataLength( pvField); + UW2FBA( uiDataLen, pucTmp); + pucTmp += 2; + } + } + + // Log the data, if any. + + if (uiDataLen) + { + const FLMBYTE * pucExportPtr; + + if (bEncrypted) + { + pucExportPtr = pRecord->getEncryptionDataPtr( pvField); + } + else + { + pucExportPtr = pRecord->getDataPtr( pvField); + } + + if (pucExportPtr == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( rc = logData( uiDataLen, pucExportPtr, uiPacketType, + &uiPacketLen, NULL, NULL, NULL))) + { + goto Exit; + } + } + } + + // Add null to terminate the record. + + if (RC_BAD( rc = makeRoom( 2, &uiPacketLen, uiPacketType, NULL, NULL))) + { + goto Exit; + } + + pucTmp = getPacketPtr() + uiPacketLen; + uiPacketLen += 2; + UW2FBA( 0, pucTmp); + pucTmp += 2; + + // Finish the packet. + + if (RC_BAD( rc = finishPacket( uiPacketType, + uiPacketLen - RFL_PACKET_OVERHEAD, FALSE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log record add, modify, or delete operation +*********************************************************************/ +RCODE F_Rfl::logUpdate( + FLMUINT uiContainer, + FLMUINT uiDrn, + FLMUINT uiAutoTrans, + FlmRecord * pOldRecord, + FlmRecord * pNewRecord) +{ + RCODE rc = FERR_OK; + FLMUINT uiPacketType; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better be in the middle of a transaction. + + flmAssert( m_uiCurrTransID); + + if (pOldRecord && pNewRecord) + { + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) + { + uiPacketType = RFL_MODIFY_RECORD_PACKET_VER_2; + } + else + { + uiPacketType = RFL_MODIFY_RECORD_PACKET; + } + } + else if (pNewRecord) + { + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) + { + uiPacketType = RFL_ADD_RECORD_PACKET_VER_2; + } + else + { + uiPacketType = RFL_ADD_RECORD_PACKET; + } + } + else + { + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) + { + uiPacketType = RFL_DELETE_RECORD_PACKET_VER_2; + } + else + { + uiPacketType = RFL_DELETE_RECORD_PACKET; + } + } + + if (RC_BAD( rc = logUpdatePacket( uiPacketType, uiContainer, uiDrn, + uiAutoTrans))) + { + goto Exit; + } + + // If it is a record modify, log the change fields. If it is a record + // add, log the new record. + + if (pOldRecord && pNewRecord) + { + if (RC_BAD( rc = logChangeFields( pOldRecord, pNewRecord))) + { + goto Exit; + } + } + else if (pNewRecord) + { + if (RC_BAD( rc = logRecord( pNewRecord))) + { + goto Exit; + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log a set of records that is indexed for a specific index. +*********************************************************************/ +RCODE F_Rfl::logIndexSet( + FLMUINT uiIndex, + FLMUINT uiContainerNum, + FLMUINT uiStartDrn, + FLMUINT uiEndDrn) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // This call is a new database version. Database better have been + // upgraded. + + flmAssert( m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_3_02); + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better be in the middle of a transaction. + + flmAssert( m_uiCurrTransID); + + m_uiOperCount++; + uiPacketBodyLen = + (FLMUINT)((m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_50) + ? (FLMUINT) 16 + : (FLMUINT) 14); + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the container number, if db version is >= 4.50 + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_50) + { + UW2FBA( (FLMUINT16) uiContainerNum, pucPacketBody); + pucPacketBody += 2; + } + + // Output the index number. + + UW2FBA( (FLMUINT16) uiIndex, pucPacketBody); + pucPacketBody += 2; + + // Output the starting DRN. + + UD2FBA( (FLMUINT32) (uiStartDrn), pucPacketBody); + pucPacketBody += 4; + + // Output the ending DRN. + + UD2FBA( (FLMUINT32) (uiEndDrn), pucPacketBody); + pucPacketBody += 4; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( (FLMUINT) ( + (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_50) + ? (FLMUINT) RFL_INDEX_SET_PACKET_VER_2 + : (FLMUINT) RFL_INDEX_SET_PACKET), + uiPacketBodyLen, FALSE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Start logging unknown packets. +*********************************************************************/ +RCODE F_Rfl::startLoggingUnknown(void) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + flmAssert( m_pFile); + + // Do nothing if logging is disabled. Also, ignore these packets if we + // are operating on a pre-4.3 database. + + if (m_bLoggingOff || m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; + } + + // Better not already be in the middle of logging unknown stuff for + // the application + + flmAssert( !m_bLoggingUnknown); + + // Better be inside a transaction. + + flmAssert( m_uiCurrTransID); + + m_uiOperCount++; + uiPacketBodyLen = 4; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_START_UNKNOWN_PACKET, uiPacketBodyLen, + FALSE))) + { + goto Exit; + } + + m_bLoggingUnknown = TRUE; + m_uiUnknownPacketLen = RFL_PACKET_OVERHEAD; + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log unknown data. +*********************************************************************/ +RCODE F_Rfl::logUnknown( + FLMBYTE * pucUnknown, + FLMUINT uiLen) +{ + RCODE rc = FERR_OK; + + // Do nothing if logging is disabled. Also, ignore these packets if we + // are operating on a pre-4.3 database. + + if (m_bLoggingOff || m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; + } + + flmAssert( m_bLoggingUnknown); + if (RC_BAD( rc = logData( uiLen, pucUnknown, RFL_UNKNOWN_PACKET, + &m_uiUnknownPacketLen, NULL, NULL, NULL))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: End logging unknown packets. +*********************************************************************/ +RCODE F_Rfl::endLoggingUnknown(void) +{ + RCODE rc = FERR_OK; + + flmAssert( m_pFile); + + // Do nothing if logging is disabled. Also, ignore these packets if we + // are operating on a pre-4.3 database. + + if (m_bLoggingOff || m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; + } + + // Better be in the middle of logging unknown stuff for the application + + flmAssert( m_bLoggingUnknown); + if (m_uiUnknownPacketLen > RFL_PACKET_OVERHEAD) + { + if (RC_BAD( rc = finishPacket( RFL_UNKNOWN_PACKET, + m_uiUnknownPacketLen - RFL_PACKET_OVERHEAD, FALSE))) + { + goto Exit; + } + } + +Exit: + + m_bLoggingUnknown = FALSE; + m_uiUnknownPacketLen = RFL_PACKET_OVERHEAD; + return (rc); +} + +/******************************************************************** +Desc: Log a reduce packet +*********************************************************************/ +RCODE F_Rfl::logReduce( + FLMUINT uiTransID, + FLMUINT uiCount) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // This call is new with 4.3 databases - not supported in older + // versions, so don't log it. + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; + } + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // We need to set up to log this packet as if we were logging a + // transaction. The only difference is that we don't log the begin + // transaction packet. + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = 8; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) uiTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the count + + UD2FBA( (FLMUINT32) uiCount, pucPacketBody); + pucPacketBody += 4; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_REDUCE_PACKET, uiPacketBodyLen, TRUE))) + { + goto Exit; + } + + // Finalize the transaction (as if we were committing a transaction) + + finalizeTransaction(); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log a database conversion packet +Note: This routine performs most of the setup for logging a full + transaction, but it does not cause begin and commit packets + to be logged. It is a "standalone" transaction. +*********************************************************************/ +RCODE F_Rfl::logUpgrade( + FLMUINT uiTransID, + FLMUINT uiOldVersion, + FLMBYTE * pucDBKey, + FLMUINT32 ui32DBKeyLen) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // We need to set up to log this packet as if we were logging a + // transaction. The only difference is that we don't log the begin + // transaction packet. + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = 14 + ui32DBKeyLen; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID + + UD2FBA( (FLMUINT32) uiTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the old database version + + UD2FBA( (FLMUINT32) uiOldVersion, pucPacketBody); + pucPacketBody += 4; + + // Output the new database version + + UD2FBA( (FLMUINT32) FLM_CUR_FILE_FORMAT_VER_NUM, pucPacketBody); + pucPacketBody += 4; + + // For versions >= 4.60, the next two bytes will give the length of + // the DB Key. + + flmAssert( ui32DBKeyLen <= 0xFFFF); + UW2FBA( (FLMUINT16) ui32DBKeyLen, pucPacketBody); + pucPacketBody += 2; + + // If we were built without encryption, the key length will be zero, + // so no need to store the key. + + if (ui32DBKeyLen) + { + f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); + pucPacketBody += ui32DBKeyLen; + } + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_UPGRADE_PACKET, uiPacketBodyLen, TRUE))) + { + goto Exit; + } + + // Finalize the transaction (as if we were committing a transaction) + + finalizeTransaction(); + +Exit: + + if (!m_bLoggingOff) + { + m_uiCurrTransID = 0; + } + + return (rc); +} + +/******************************************************************** +Desc: Log the wrapped database key +*********************************************************************/ +RCODE F_Rfl::logWrappedKey( + FLMUINT uiTransID, + FLMBYTE * pucDBKey, + FLMUINT32 ui32DBKeyLen) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = 6 + ui32DBKeyLen; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID + + UD2FBA( (FLMUINT32) uiTransID, pucPacketBody); + pucPacketBody += 4; + + // The next two bytes will give the length of the DB Key. + + flmAssert( ui32DBKeyLen <= 0xFFFF); + UW2FBA( (FLMUINT16) ui32DBKeyLen, pucPacketBody); + pucPacketBody += 2; + + // If we were built without encryption, the key length will be zero, + // so no need to store the key. + + if (ui32DBKeyLen) + { + f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); + pucPacketBody += ui32DBKeyLen; + } + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_WRAP_KEY_PACKET, uiPacketBodyLen, TRUE))) + { + goto Exit; + } + + finalizeTransaction(); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log that we have enabled encryption +*********************************************************************/ +RCODE F_Rfl::logEnableEncryption( + FLMUINT uiTransID, + FLMBYTE * pucDBKey, + FLMUINT32 ui32DBKeyLen) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + if (RC_BAD( rc = setupTransaction())) + { + goto Exit; + } + + uiPacketBodyLen = 6 + ui32DBKeyLen; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID + + UD2FBA( (FLMUINT32) uiTransID, pucPacketBody); + pucPacketBody += 4; + + // The next two bytes will give the length of the DB Key. + + flmAssert( ui32DBKeyLen <= 0xFFFF); + UW2FBA( (FLMUINT16) ui32DBKeyLen, pucPacketBody); + pucPacketBody += 2; + + // If we were built without encryption, the key length will be zero, + // so no need to store the key. + + if (ui32DBKeyLen) + { + f_memcpy( pucPacketBody, pucDBKey, ui32DBKeyLen); + pucPacketBody += ui32DBKeyLen; + } + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_ENABLE_ENCRYPTION_PACKET, uiPacketBodyLen, + TRUE))) + { + goto Exit; + } + + finalizeTransaction(); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Log a block chain free operation +*********************************************************************/ +RCODE F_Rfl::logBlockChainFree( + FLMUINT uiTrackerDrn, + FLMUINT uiCount, + FLMUINT uiEndAddr) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + // This call is new with 4.52 databases - not supported in older + // versions, so don't log it. + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_60) + { + flmAssert( 0); + goto Exit; + } + + // Do nothing if logging is disabled. + + if (m_bLoggingOff) + { + goto Exit; + } + + // Better not be in the middle of logging unknown stuff for the + // application + + flmAssert( !m_bLoggingUnknown); + + // Better be in the middle of a transaction. + + flmAssert( m_uiCurrTransID); + m_uiOperCount++; + + uiPacketBodyLen = 16; + + // Make sure we have space in the RFL buffer for a complete packet. + + if (!haveBuffSpace( uiPacketBodyLen + RFL_PACKET_OVERHEAD)) + { + if (RC_BAD( rc = flush( m_pCurrentBuf))) + { + goto Exit; + } + } + + // Get a pointer to where we will be laying down the packet body. + + pucPacketBody = getPacketBodyPtr(); + + // Output the transaction ID. + + UD2FBA( (FLMUINT32) m_uiCurrTransID, pucPacketBody); + pucPacketBody += 4; + + // Output the tracker record number + + UD2FBA( (FLMUINT32) uiTrackerDrn, pucPacketBody); + pucPacketBody += 4; + + // Output the count + + UD2FBA( (FLMUINT32) uiCount, pucPacketBody); + pucPacketBody += 4; + + // Output the ending block address + + UD2FBA( (FLMUINT32) uiEndAddr, pucPacketBody); + pucPacketBody += 4; + + // Finish the packet + + if (RC_BAD( rc = finishPacket( RFL_BLK_CHAIN_FREE_PACKET, uiPacketBodyLen, + TRUE))) + { + goto Exit; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Reads a full packet, based on what file offset and read + offset are currently set to. +*********************************************************************/ +RCODE F_Rfl::readPacket( + FLMUINT uiMinBytesNeeded) +{ + RCODE rc = FERR_OK; + FLMUINT uiTmpOffset; + FLMUINT uiReadLen; + FLMUINT uiBytesRead; + + // If we have enough bytes in the buffer for the minimum bytes needed, + // we don't need to retrieve any more bytes. + + if (m_pCurrentBuf->uiRflBufBytes - m_uiRflReadOffset >= uiMinBytesNeeded) + { + goto Exit; + } + + // If we are doing restore, we have to do only sequential reads - + // cannot depend on doing reads on 512 byte boundaries. Otherwise, we + // read directly from disk on 512 byte boundaries. + + if (m_pRestore) + { + FLMUINT uiCurrFilePos = m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes; + + if (m_uiRflReadOffset > 0) + { + + // Move the bytes left in the buffer down to the beginning of + // the buffer. + + f_memmove( m_pCurrentBuf->pIOBuffer->m_pucBuffer, + &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[m_uiRflReadOffset]), + m_pCurrentBuf->uiRflBufBytes - m_uiRflReadOffset); + m_pCurrentBuf->uiRflBufBytes -= m_uiRflReadOffset; + m_pCurrentBuf->uiRflFileOffset += m_uiRflReadOffset; + m_uiRflReadOffset = 0; + } + + uiReadLen = m_uiBufferSize - m_pCurrentBuf->uiRflBufBytes; + + // Read enough to fill the rest of the buffer, which is guaranteed + // to hold at least one full packet. + + if (!m_uiFileEOF) + { + if (uiCurrFilePos > (FLMUINT) (-1) - uiReadLen) + { + uiReadLen = (FLMUINT) (-1) - uiCurrFilePos; + } + } + else + { + if (uiCurrFilePos + uiReadLen > m_uiFileEOF) + { + uiReadLen = m_uiFileEOF - uiCurrFilePos; + } + } + + // If reading will not give us the minimum bytes needed, we cannot + // satisfy this request from the current file. + + if (uiReadLen + m_pCurrentBuf->uiRflBufBytes < uiMinBytesNeeded) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Read enough to get the entire packet. + + if (RC_BAD( rc = m_pRestore->read( uiReadLen, &( + m_pCurrentBuf->pIOBuffer->m_pucBuffer[ + m_pCurrentBuf->uiRflBufBytes]), &uiBytesRead))) + { + if (rc == FERR_IO_END_OF_FILE) + { + rc = FERR_OK; + } + else + { + goto Exit; + } + } + + // If we didn't read enough to satisfy the minimum bytes needed, we + // cannot satisfy this request from the current file. + + if (uiBytesRead + m_pCurrentBuf->uiRflBufBytes < uiMinBytesNeeded) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + m_pCurrentBuf->uiRflBufBytes += uiBytesRead; + } + else + { + + // Set offsets so we are on a 512 byte boundary for our next read. + // No need to move data, since we will be re-reading it anyway. + + if (m_uiRflReadOffset > 0) + { + uiTmpOffset = m_uiRflReadOffset - (m_uiRflReadOffset & 511); + m_pCurrentBuf->uiRflFileOffset += uiTmpOffset; + m_uiRflReadOffset -= uiTmpOffset; + } + else if (m_pCurrentBuf->uiRflFileOffset & 511) + { + m_uiRflReadOffset = m_pCurrentBuf->uiRflFileOffset & 511; + m_pCurrentBuf->uiRflFileOffset -= m_uiRflReadOffset; + } + + m_pCurrentBuf->uiRflBufBytes = 0; + + // Read enough to fill the rest of the buffer, which is guaranteed + // to hold at least one full packet. + + uiReadLen = m_uiBufferSize; + + // m_uiFileEOF better not be zero at this point - we should always + // know precisely where the RFL file ends when we are doing recovery + // as opposed to doing a restore. + + flmAssert( m_uiFileEOF >= 512); + if (m_pCurrentBuf->uiRflFileOffset + uiReadLen > m_uiFileEOF) + { + uiReadLen = m_uiFileEOF - m_pCurrentBuf->uiRflFileOffset; + } + + // If reading will not give us the minimum number of bytes needed, + // we have a bad packet. + + if (uiReadLen < m_uiRflReadOffset || + uiReadLen - m_uiRflReadOffset < uiMinBytesNeeded) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Read to get the entire packet. + + if (RC_BAD( rc = m_pFileHdl->SectorRead( m_pCurrentBuf->uiRflFileOffset, + uiReadLen, m_pCurrentBuf->pIOBuffer->m_pucBuffer, + &uiBytesRead))) + { + if (rc == FERR_IO_END_OF_FILE) + { + rc = FERR_OK; + } + else + { + m_bRflVolumeOk = FALSE; + goto Exit; + } + } + + if (uiBytesRead < uiReadLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + m_pCurrentBuf->uiRflBufBytes = uiReadLen; + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Gets and verifies the next packet from the roll-forward + log file. Packet checksum will be verified. +*********************************************************************/ +RCODE F_Rfl::getPacket( + FLMBOOL bForceNextFile, + FLMUINT * puiPacketTypeRV, + FLMBYTE ** ppucPacketBodyRV, + FLMUINT * puiPacketBodyLenRV, + FLMBOOL * pbLoggedTimes) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacket; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketType; + FLMUINT uiEncryptPacketBodyLen; + FLMBYTE ucHdr[512]; + FLMUINT uiBytesRead; + + // See if we need to go to the next file. Note that we only check for + // this exactly on packet boundaries. We do not expect packets to be + // split across files. If we are not at the end of processing what is + // in the buffer, we should be able to read the rest of the packet from + // the current file. + +Get_Next_File: + + if (bForceNextFile || + (m_uiFileEOF && m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && + m_pCurrentBuf->uiRflFileOffset + m_pCurrentBuf->uiRflBufBytes == + m_uiFileEOF)) + { + if (m_bKeepRflFiles) + { + if (!m_pRestore) + { + + // Only doing recovery after a failure, see if we are at the + // last file already. + + if (m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) + { + rc = RC_SET( FERR_END); + goto Exit; + } + else if( (m_pCurrentBuf->uiCurrFileNum + 1 ) == + m_uiLastRecoverFileNum && + !(FLMUINT)FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_LAST_TRANS_OFFSET])) + { + + // We are going to try to open the last file. Since the + // log header shows a current offset of 0, the file may + // have been created but nothing was logged to it. We don't + // want to try to open it here because it may not have been + // initialized fully at the time of the server crash. + + m_pCurrentBuf->uiCurrFileNum = m_uiLastRecoverFileNum; + rc = RC_SET( FERR_END); + goto Exit; + } + + // Open the next file in the sequence. + + if (RC_BAD( rc = openFile( m_pCurrentBuf->uiCurrFileNum + 1, + m_ucNextSerialNum))) + { + if (rc == FERR_IO_PATH_NOT_FOUND || rc == FERR_IO_INVALID_PATH) + { + rc = RC_SET( FERR_END); + } + + goto Exit; + } + + // If this is the last RFL file, the EOF is contained in the + // log header. Otherwise, it will be in the RFL file's header, + // and openFile will already have retrieved it. + + if (m_pCurrentBuf->uiCurrFileNum == m_uiLastRecoverFileNum) + { + m_uiFileEOF = (FLMUINT) FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_LAST_TRANS_OFFSET]); + + // Could be zero if RFL file wasn't created yet. + + if (!m_uiFileEOF) + { + m_uiFileEOF = 512; + } + } + + // By this point, the EOF better be greater than or equal to + // 512. + + flmAssert( m_uiFileEOF >= 512); + } + else + { + if (RC_BAD( rc = m_pRestore->close())) + { + goto Exit; + } + + // Ask the recovery object to open the file. + + if (RC_BAD( rc = m_pRestore->openRflFile( + m_pCurrentBuf->uiCurrFileNum + 1))) + { + if (rc == FERR_IO_PATH_NOT_FOUND) + { + rc = RC_SET( FERR_END); + } + + goto Exit; + } + + // Get the first 512 bytes from the file and verify the + // header. + + if (RC_BAD( rc = m_pRestore->read( 512, ucHdr, &uiBytesRead))) + { + goto Exit; + } + + if (uiBytesRead < 512) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + + if (RC_BAD( rc = verifyHeader( ucHdr, + m_pCurrentBuf->uiCurrFileNum + 1, m_ucNextSerialNum))) + { + goto Exit; + } + + // We may not know the actual EOF of files during restore + // operations. m_uiFileEOF could be zero here. + + m_uiFileEOF = (FLMUINT) FB2UD( &ucHdr[RFL_EOF_POS]); + + // File EOF may be zero or >= 512 at this point. + + flmAssert( !m_uiFileEOF || m_uiFileEOF >= 512); + + // Need to increment current file number. + + m_pCurrentBuf->uiCurrFileNum++; + } + + m_pCurrentBuf->uiRflFileOffset = 512; + m_uiRflReadOffset = 0; + m_pCurrentBuf->uiRflBufBytes = 0; + + // Get the next packet from the new file. + + if (RC_BAD( rc = readPacket( RFL_PACKET_OVERHEAD))) + { + if (m_uiFileEOF == 512 && m_bKeepRflFiles) + { + + // File was empty, try to go to the next file. + + bForceNextFile = TRUE; + goto Get_Next_File; + } + + goto Exit; + } + } + else + { + + // This is the case where we are not keeping the RFL files. So, + // there is no next file to go to. If we get to this point, we + // had better not be doing a restore. + + flmAssert( m_pRestore == NULL && !bForceNextFile); + rc = RC_SET( FERR_END); + goto Exit; + } + } + + // Make sure we at least have a packet header in the buffer. + + if (RC_BAD( rc = readPacket( RFL_PACKET_OVERHEAD))) + { + goto Exit; + } + + // Verify the packet address. + + m_uiPacketAddress = m_pCurrentBuf->uiRflFileOffset + m_uiRflReadOffset; + pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[m_uiRflReadOffset]); + if ((FLMUINT) FB2UD( &pucPacket[RFL_PACKET_ADDRESS_OFFSET]) != m_uiPacketAddress) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Get packet type, time flag, and packet body length + + *puiPacketTypeRV = uiPacketType = RFL_GET_PACKET_TYPE( + pucPacket[RFL_PACKET_TYPE_OFFSET]); + + if (pbLoggedTimes) + { + *pbLoggedTimes = (pucPacket[RFL_PACKET_TYPE_OFFSET] & RFL_TIME_LOGGED_FLAG) + ? TRUE + : FALSE; + } + + *puiPacketBodyLenRV = (FLMUINT) FB2UW( + &pucPacket[RFL_PACKET_BODY_LENGTH_OFFSET]); + + // Adjust the packet body length for encryption if necessary. NOTE: + // This adjusted length is NOT returned to the caller. The actual body + // length is what will be returned. + + uiEncryptPacketBodyLen = getEncryptPacketBodyLen( uiPacketType, + *puiPacketBodyLenRV); + + // Make sure we have the entire packet in the buffer. + + if (RC_BAD( rc = readPacket( uiEncryptPacketBodyLen + RFL_PACKET_OVERHEAD))) + { + goto Exit; + } + + pucPacket = &(m_pCurrentBuf->pIOBuffer->m_pucBuffer[m_uiRflReadOffset]); + + // At this point, we are guaranteed to have the entire packet in the + // buffer. + + *ppucPacketBodyRV = pucPacketBody = &pucPacket[RFL_PACKET_OVERHEAD]; + + // Validate the packet checksum + + if (RflCalcChecksum( pucPacket, uiEncryptPacketBodyLen) != + pucPacket[RFL_PACKET_CHECKSUM_OFFSET]) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if (uiPacketType == RFL_TRNS_BEGIN_PACKET || + uiPacketType == RFL_TRNS_BEGIN_EX_PACKET || + uiPacketType == RFL_UPGRADE_PACKET || + uiPacketType == RFL_REDUCE_PACKET || + uiPacketType == RFL_WRAP_KEY_PACKET || + uiPacketType == RFL_ENABLE_ENCRYPTION_PACKET) + { + + // Current transaction ID better be zero, otherwise, we have two or + // more begin packets in a row. + + if (m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + m_uiCurrTransID = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + // Make sure the transaction numbers are ascending + + if (m_uiCurrTransID <= m_uiLastTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if (uiPacketType == RFL_TRNS_BEGIN_EX_PACKET) + { + FLMUINT uiLastLoggedCommitTransID; + + // Skip past seconds + + pucPacketBody += 4; + + uiLastLoggedCommitTransID = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31 && + m_uiLastLoggedCommitTransID != uiLastLoggedCommitTransID) + { + rc = RC_SET( FERR_RFL_TRANS_GAP); + goto Exit; + } + } + } + else + { + + // If transaction ID is not zero, we are not inside a transaction, + // and it is likely that we have a corrupt packet. + + if (!m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Decrypt the packet if it is a packet type that was encrypted. + + if (uiPacketType == RFL_TRNS_COMMIT_PACKET || + uiPacketType == RFL_TRNS_ABORT_PACKET) + { + if ((FLMUINT) FB2UD( pucPacketBody) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + } + + // Set read offset to beginning of next packet. + + m_uiRflReadOffset += (RFL_PACKET_OVERHEAD + uiEncryptPacketBodyLen); + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Get a record from the packets in the roll-forward log. + This expects a series of RFL_DATA_RECORD_PACKETs. +*********************************************************************/ +RCODE F_Rfl::getRecord( + FDB * pDb, + FLMUINT uiPacketType, + FLMBYTE * pucPacketBody, + FLMUINT uiPacketBodyLen, + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + FLMUINT uiTagNum; + FLMUINT uiDataType; + FLMUINT uiLevel; + FLMUINT uiDataLen; + FLMBYTE * pucFieldData = NULL; + void * pvField; + FLMBOOL bEncrypted = FALSE; + FLMUINT uiEncId = 0; + FLMUINT uiEncDataLen = 0; + POOL pool; + + GedPoolInit( &pool, 512); + + // Go into a loop processing packets until we have retrieved all of + // the fields of the record. At that point, we had better be at the end + // of the record. + + for (;;) + { + + // If we don't currently have a packet, get one Packet type had + // better be RFL_DATA_RECORD_PACKET. + + if (!uiPacketBodyLen) + { + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_DATA_RECORD_PACKET && + uiPacketType != RFL_ENC_DATA_RECORD_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + + // Packet body length better be at least two or we have an + // incomplete packet - we need to at least be able to get the tag + // number at this point. + + if (uiPacketBodyLen < 2) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + else if (uiPacketBodyLen == 2) + { + + // If the packet body length is only two, we had better be at + // the end of the record with a tag number of zero. Otherwise, we + // have an incomplete packet. + + if ((uiTagNum = (FLMUINT) FB2UW( pucPacketBody)) != 0) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + break; + } + else if (uiPacketType == RFL_DATA_RECORD_PACKET) + { + if (uiPacketBodyLen < 6) + { + + // If we have a packet body length less than six (for + // RFL_DATA_RECORD_PACKETs), we have an incomplete field + // header. + + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + else if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) + { + + // This type of packet is only valid with versions of flaim >= + // 4.60 + + flmAssert( m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60); + + if (uiPacketBodyLen < 7) + { + + // If we have a packet body length less than seven we have an + // incomplete field header. + + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + + // At this point, we have a packet body length that is greater than + // or equal to seven (or six), meaning we could not possibly be on + // the last field of the record. Hence, a zero tag number is invalid + // here. + + if ((uiTagNum = (FLMUINT) FB2UW( pucPacketBody)) == 0) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pucPacketBody += 2; + uiDataType = *pucPacketBody++; + uiLevel = *pucPacketBody++; + uiDataLen = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + uiPacketBodyLen -= 6; + + // If the database version supports encryption, we need to check + // for it. + + if (uiPacketType == RFL_ENC_DATA_RECORD_PACKET) + { + bEncrypted = (FLMBOOL) * pucPacketBody++; + --uiPacketBodyLen; + + if (bEncrypted) + { + if (uiPacketBodyLen < 4) + { + flmAssert( 0); + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Extract the encryption ID and the encrypted length. + + uiEncId = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiEncDataLen = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiPacketBodyLen -= 4; + } + } + + // Create a new field. + + if (RC_BAD( rc = pRecord->insertLast( uiLevel, uiTagNum, uiDataType, + &pvField))) + { + goto Exit; + } + + if (!bEncrypted && uiDataLen) + { + if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, uiDataType, + uiDataLen, 0, 0, 0, &pucFieldData, NULL))) + { + goto Exit; + } + + while (uiDataLen) + { + if (uiDataLen > uiPacketBodyLen) + { + f_memcpy( pucFieldData, pucPacketBody, uiPacketBodyLen); + pucFieldData += uiPacketBodyLen; + pucPacketBody += uiPacketBodyLen; + uiDataLen -= uiPacketBodyLen; + + uiPacketBodyLen = 0; + + // Get the next packet. Packet type had better be + // RFL_DATA_RECORD_PACKET. + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_DATA_RECORD_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + else + { + f_memcpy( pucFieldData, pucPacketBody, uiDataLen); + pucFieldData += uiDataLen; + uiPacketBodyLen -= uiDataLen; + pucPacketBody += uiDataLen; + uiDataLen = 0; + } + } + + pucFieldData = NULL; + } + else if (bEncrypted) + { + FLMBYTE * pucEncFieldData; + + if (uiEncDataLen) + { + if (RC_BAD( rc = pRecord->allocStorageSpace( pvField, uiDataType, + uiDataLen, uiEncDataLen, uiEncId, + FLD_HAVE_ENCRYPTED_DATA, &pucFieldData, &pucEncFieldData + ))) + { + goto Exit; + } + } + + while (uiEncDataLen) + { + if (uiEncDataLen > uiPacketBodyLen) + { + f_memcpy( pucEncFieldData, pucPacketBody, uiPacketBodyLen); + pucEncFieldData += uiPacketBodyLen; + pucPacketBody += uiPacketBodyLen; + uiEncDataLen -= uiPacketBodyLen; + + uiPacketBodyLen = 0; + + // Get the next packet. Packet type had better be + // RFL_ENC_DATA_RECORD_PACKET. + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_ENC_DATA_RECORD_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + else + { + f_memcpy( pucEncFieldData, pucPacketBody, uiEncDataLen); + pucEncFieldData += uiEncDataLen; + uiPacketBodyLen -= uiEncDataLen; + pucPacketBody += uiEncDataLen; + uiEncDataLen = 0; + } + } + + pucEncFieldData = NULL; + + if (!m_pFile->bInLimitedMode) + { + if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, pvField, + uiEncId, &pool))) + { + goto Exit; + } + } + } + } + +Exit: + + GedPoolFree( &pool); + + return (rc); +} + +/******************************************************************** +Desc: Modify a record using RFL_DATA_RECORD_PACKETs or + RFL_CHANGE_FIELD_PACKETs. +*********************************************************************/ +RCODE F_Rfl::modifyRecord( + HFDB hDb, + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + FLMUINT uiPacketType; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + FLMUINT uiChangeType; + FLMUINT uiPosition; + FLMUINT uiTagNum = 0; + FLMUINT uiDataType = 0; + FLMUINT uiLevel = 0; + FLMUINT uiDataLen = 0; + FLMBYTE * pucData; + FLMBYTE * pucEncData; + FDB * pDb = (FDB *) hDb; + FLMBOOL bEncrypted = FALSE; + FLMUINT uiEncDataLen; + FLMUINT uiEncId; + FLMUINT uiFlags; + FlmField * pField; + FLMUINT uiCurPos = 1; + void * pvField; + + // Get the first packet and see what it is. If it is an + // RFL_DATA_RECORD_PACKET, just call Rfl3GetRecord to get the entire + // new record. + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType == RFL_DATA_RECORD_PACKET || + uiPacketType == RFL_ENC_DATA_RECORD_PACKET) + { + pRecord->clear(); + rc = getRecord( pDb, uiPacketType, pucPacketBody, uiPacketBodyLen, pRecord); + goto Exit; + } + else if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Go into a loop processing packets until we have processed all of + // the changed fields for the record. + + pField = pRecord->getFieldPointer( pRecord->root()); + + flmAssert( pField); + + for (;;) + { + uiEncDataLen = 0; + uiEncId = 0; + + // If we don't currently have a packet, get one Packet type had + // better be RFL_CHANGE_FIELDS_PACKET. + + if (!uiPacketBodyLen) + { + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + + // Packet body length better be at least three or we have an + // incomplete packet - we need to at least be able to get the type + // of change and the absolute position of the change. + + if (uiPacketBodyLen < 3) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // Get the change type and the absolute position where the change + // is to be put. A position of zero is illegal. + + uiChangeType = *pucPacketBody++; + uiPosition = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + uiPacketBodyLen -= 3; + + if (uiChangeType == RFL_END_FIELD_CHANGES) + { + + // If we are not at the end of the packet, it must be a bad + // packet. Also, uiPosition should be a zero for this packet. + + if (uiPacketBodyLen || uiPosition) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + break; + } + + // If not RFL_END_FIELD_CHANGES, a position of zero is illegal. + + if (!uiPosition) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + switch (uiChangeType) + { + case RFL_INSERT_FIELD: + case RFL_INSERT_ENC_FIELD: + { + if (uiPacketBodyLen < 6) + { + + // If the change type is insert field and there are not at + // least six bytes in the packet, we have a problem. + + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + uiTagNum = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + uiDataType = *pucPacketBody++; + uiLevel = *pucPacketBody++; + uiDataLen = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + uiPacketBodyLen -= 6; + bEncrypted = (uiChangeType == RFL_INSERT_FIELD ? FALSE : TRUE); + if (bEncrypted) + { + if (uiPacketBodyLen < 4) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + uiEncId = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiEncDataLen = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiPacketBodyLen -= 4; + } + break; + } + + case RFL_MODIFY_FIELD: + case RFL_MODIFY_ENC_FIELD: + { + + // Packet better have at least three bytes and the first byte + // had better be RFL_REPLACE_BYTES. + + if (uiPacketBodyLen < 3 || *pucPacketBody != RFL_REPLACE_BYTES) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pucPacketBody++; + uiDataLen = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + + bEncrypted = (uiChangeType == RFL_MODIFY_FIELD ? FALSE : TRUE); + uiPacketBodyLen -= 3; + + if (bEncrypted) + { + if (uiPacketBodyLen < 4) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + uiEncId = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiEncDataLen = FB2UW( pucPacketBody); + pucPacketBody += 2; + + uiPacketBodyLen -= 4; + } + break; + } + + case RFL_DELETE_FIELD: + { + break; + } + + default: + { + + // Bad change type in packet. + + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + + // Now position to the target field. + + switch (uiChangeType) + { + case RFL_DELETE_FIELD: + case RFL_MODIFY_FIELD: + case RFL_MODIFY_ENC_FIELD: + { + while (uiCurPos != uiPosition) + { + if (uiPosition < uiCurPos) + { + flmAssert( pField->uiPrev); + pField = pRecord->prevField( pField); + --uiCurPos; + } + else + { + flmAssert( pField->uiNext); + pField = pRecord->nextField( pField); + uiCurPos++; + } + } + + if (uiChangeType != RFL_DELETE_FIELD) + { + + // Get the data type ... not supplied in the modify field + // packet. + + uiDataType = pRecord->getFieldDataType( pField); + uiTagNum = pField->ui16FieldID; + } + break; + } + + case RFL_INSERT_FIELD: + case RFL_INSERT_ENC_FIELD: + { + FlmField * pNewField; + + // On insert, we may be trying to position to a field that + // does not exist yet. Therefore we need to position to the + // field prior to the field position we want to insert. + + flmAssert( uiPosition > 1); // cannot insert at the root + ///position. + + while (uiCurPos != uiPosition - 1) + { + if (uiPosition - 1 < uiCurPos) + { + flmAssert( pField->uiPrev); + pField = pRecord->prevField( pField); + --uiCurPos; + } + else + { + flmAssert( pField->uiNext); + pField = pRecord->nextField( pField); + uiCurPos++; + } + } + + // Insert the new field at the specified position and get + // back a new field to use later. + + if (RC_BAD( rc = pRecord->createField( pField, &pNewField))) + { + goto Exit; + } + + if (RC_BAD( rc = pRecord->setFieldLevel( pNewField, uiLevel))) + { + goto Exit; + } + + pField = pNewField; + pField->ui16FieldID = (FLMUINT16) uiTagNum; + uiCurPos++; // Bump the position as we have + ///just added a new field and + + // we are positioned on it. + + break; + } + } + + if (uiChangeType == RFL_DELETE_FIELD) + { + + // Remove the specified field or subtree + + pvField = (void *) ((FLMUINT) (pField->uiPrev)); + --uiCurPos; + if (!pvField) + { + pvField = pRecord->root(); + uiCurPos = 1; + } + + // For versions 4.60 and greater, the interpretation for + // RFL_DELETE_FIELD is to delete the entire sub-tree. Prior to + // that, it is to delete only a single field. + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_60) + { + if (RC_BAD( rc = pRecord->remove( pField))) + { + goto Exit; + } + } + else + { + + // Passing in the same pointer to removeFields will + // effectively delete just pField. + + if (RC_BAD( rc = pRecord->removeFields( pField, pField))) + { + goto Exit; + } + } + + // We need to reset our pField. + + pField = pRecord->getFieldPointer( pvField); + + continue; // Next field... + } + + // Both insert & modify need to have space allocated. + + if (bEncrypted) + { + uiFlags = FLD_HAVE_ENCRYPTED_DATA; + } + else + { + uiFlags = 0; + } + + flmAssert( pField); + + // Allocate space for the data. We call this even if uiDataLen is + // zero so that the appropriate data type will be set in the node as + // well. ; + // Before we allocate storage space, save the field offset. The + // field buffer may get reallocated, resulting in a nwe address for + // pField. + pvField = pRecord->getFieldVoid( pField); + if (RC_BAD( rc = pRecord->getNewDataPtr( pField, uiDataType, uiDataLen, + uiEncDataLen, uiEncId, uiFlags, &pucData, &pucEncData))) + { + goto Exit; + } + + pField = pRecord->getFieldPointer( pvField); + + // Get the data for insert or modify, if any + + if (bEncrypted) + { + while (uiEncDataLen) + { + if (uiEncDataLen > uiPacketBodyLen) + { + f_memcpy( pucEncData, pucPacketBody, uiPacketBodyLen); + pucEncData += uiPacketBodyLen; + uiEncDataLen -= uiPacketBodyLen; + uiPacketBodyLen = 0; + + // Get the next packet. Packet type had better be + // RFL_CHANGE_FIELDS_PACKET. + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + else + { + f_memcpy( pucEncData, pucPacketBody, uiEncDataLen); + pucEncData += uiEncDataLen; + uiPacketBodyLen -= uiEncDataLen; + pucPacketBody += uiEncDataLen; + uiEncDataLen = 0; + } + } + } + else // Not encrypted + { + while (uiDataLen) + { + if (uiDataLen > uiPacketBodyLen) + { + f_memcpy( pucData, pucPacketBody, uiPacketBodyLen); + pucData += uiPacketBodyLen; + uiDataLen -= uiPacketBodyLen; + uiPacketBodyLen = 0; + + // Get the next packet. Packet type had better be + // RFL_CHANGE_FIELDS_PACKET. + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, &pucPacketBody, + &uiPacketBodyLen, NULL))) + { + goto Exit; + } + + if (uiPacketType != RFL_CHANGE_FIELDS_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + } + else + { + f_memcpy( pucData, pucPacketBody, uiDataLen); + pucData += uiDataLen; + uiPacketBodyLen -= uiDataLen; + pucPacketBody += uiDataLen; + uiDataLen = 0; + } + } + } + + // If this field is involved in an index, and it is encrypted, we + // need to make sure we decrypt it too. If it is not encrypted, we + // don't care if it involved in an index. + + if (bEncrypted && !(pDb->pFile->bInLimitedMode)) + { + IFD * pIfd; + + if (RC_BAD( rc = fdictGetField( pDb->pDict, uiTagNum, NULL, &pIfd, NULL + ))) + { + goto Exit; + } + + if (pIfd) + { + if (RC_BAD( rc = flmDecryptField( pDb->pDict, pRecord, + pRecord->getFieldVoid( pField), uiEncId, &pDb->TempPool))) + { + goto Exit; + } + } + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Read the next operation from the roll-forward log. +*********************************************************************/ +RCODE F_Rfl::readOp( + FDB * pDb, + FLMBOOL bForceNextFile, + RFL_OP_INFO * pOpInfo, + FlmRecord * pRecord) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + FLMUINT uiExpectedBodyLen; + FLMBOOL bLoggedTimes; + + f_memset( pOpInfo, 0, sizeof( RFL_OP_INFO)); + + // Get the next packet. + + if (RC_BAD( rc = getPacket( bForceNextFile, &pOpInfo->uiPacketType, + &pucPacketBody, &uiPacketBodyLen, &bLoggedTimes))) + { + goto Exit; + } + + // Must be one of our packet types that represents an operation. + + switch (pOpInfo->uiPacketType) + { + case RFL_TRNS_BEGIN_PACKET: + { + uiExpectedBodyLen = 8; + if (bLoggedTimes) + { + uiExpectedBodyLen += 4; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + pOpInfo->uiStartTime = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + break; + } + + case RFL_TRNS_BEGIN_EX_PACKET: + { + uiExpectedBodyLen = 12; + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + pOpInfo->uiStartTime = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + pOpInfo->uiLastLoggedCommitTransId = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + break; + } + + case RFL_TRNS_COMMIT_PACKET: + case RFL_TRNS_ABORT_PACKET: + { + uiExpectedBodyLen = 8; + if (bLoggedTimes) + { + uiExpectedBodyLen += 8; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 8; + break; + } + + case RFL_ADD_RECORD_PACKET: + case RFL_MODIFY_RECORD_PACKET: + case RFL_DELETE_RECORD_PACKET: + case RFL_RESERVE_DRN_PACKET: + { + uiExpectedBodyLen = 10; + if (bLoggedTimes) + { + uiExpectedBodyLen += 16; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + pucPacketBody += 4; + + pOpInfo->uiContainer = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + + pOpInfo->uiDrn = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + if (pOpInfo->uiPacketType == RFL_ADD_RECORD_PACKET) + { + if (RC_BAD( rc = getRecord( pDb, 0, NULL, 0, pRecord))) + { + goto Exit; + } + } + break; + } + + case RFL_ADD_RECORD_PACKET_VER_2: + case RFL_MODIFY_RECORD_PACKET_VER_2: + case RFL_DELETE_RECORD_PACKET_VER_2: + { + uiExpectedBodyLen = 11; + if (bLoggedTimes) + { + uiExpectedBodyLen += 16; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + pucPacketBody += 4; + + pOpInfo->uiContainer = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + + pOpInfo->uiDrn = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + pOpInfo->uiFlags = *pucPacketBody; + pucPacketBody++; + + // Translate the flags + + if (pOpInfo->uiFlags) + { + FLMUINT uiTmp = 0; + + if (pOpInfo->uiFlags & RFL_UPDATE_BACKGROUND) + { + uiTmp |= FLM_DO_IN_BACKGROUND; + } + + if (pOpInfo->uiFlags & RFL_UPDATE_SUSPENDED) + { + uiTmp |= FLM_SUSPENDED; + } + + pOpInfo->uiFlags = uiTmp; + } + + if (pOpInfo->uiPacketType == RFL_ADD_RECORD_PACKET_VER_2) + { + if (RC_BAD( rc = getRecord( pDb, 0, NULL, 0, pRecord))) + { + goto Exit; + } + } + break; + } + + case RFL_INDEX_SET_PACKET: + case RFL_INDEX_SET_PACKET_VER_2: + { + uiExpectedBodyLen = + (FLMUINT) ((pOpInfo->uiPacketType == RFL_INDEX_SET_PACKET_VER_2) + ? (FLMUINT) 16 + : (FLMUINT) 14); + + if (bLoggedTimes) + { + uiExpectedBodyLen += 16; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + pucPacketBody += 4; + + if (pOpInfo->uiPacketType == RFL_INDEX_SET_PACKET_VER_2) + { + pOpInfo->uiContainer = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + } + + pOpInfo->uiIndex = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + + pOpInfo->uiDrn = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + pOpInfo->uiEndDrn = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + break; + } + + case RFL_START_UNKNOWN_PACKET: + { + uiExpectedBodyLen = 4; + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pucPacketBody += 4; + break; + } + + case RFL_REDUCE_PACKET: + { + uiExpectedBodyLen = 8; + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pOpInfo->uiLastLoggedCommitTransId = pOpInfo->uiTransId; + pucPacketBody += 4; + + pOpInfo->uiCount = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + break; + } + + case RFL_BLK_CHAIN_FREE_PACKET: + { + uiExpectedBodyLen = 16; + + if (bLoggedTimes) + { + uiExpectedBodyLen += 16; + } + + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pucPacketBody += 4; + + // Tracker record ID + + pOpInfo->uiDrn = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + // Count + + pOpInfo->uiCount = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + // Ending block address + + pOpInfo->uiEndBlock = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + break; + } + + case RFL_INDEX_SUSPEND_PACKET: + case RFL_INDEX_RESUME_PACKET: + { + uiExpectedBodyLen = 6; + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((pOpInfo->uiTransId = + (FLMUINT) FB2UD( pucPacketBody)) != m_uiCurrTransID) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pucPacketBody += 4; + + pOpInfo->uiIndex = (FLMUINT) FB2UW( pucPacketBody); + pucPacketBody += 2; + break; + } + + case RFL_UPGRADE_PACKET: + { + FLMUINT uiDBKeyLen; + + uiExpectedBodyLen = 12; + if (uiExpectedBodyLen > uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + uiPacketBodyLen -= 4; + + pOpInfo->uiOldVersion = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + uiPacketBodyLen -= 4; + + pOpInfo->uiNewVersion = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + uiPacketBodyLen -= 4; + + // Only look for the wrapping key if the new database version is + // greater than 4.60 and there isn't already a key. + + if (pOpInfo->uiEndDrn >= FLM_FILE_FORMAT_VER_4_60 && + !m_pFile->pDbWrappingKey) + { + if (uiPacketBodyLen < 2) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + uiDBKeyLen = FB2UW( pucPacketBody); + pucPacketBody += 2; + uiPacketBodyLen -= 2; + + if (uiDBKeyLen) + { + if (uiPacketBodyLen != uiDBKeyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if ((m_pFile->pDbWrappingKey = f_new F_CCS) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + if (RC_BAD( rc = m_pFile->pDbWrappingKey->init( TRUE, + FLM_NICI_AES))) + { + goto Exit; + } + + if (RC_BAD( rc = m_pFile->pDbWrappingKey->setKeyFromStore( + pucPacketBody, (FLMUINT32) uiDBKeyLen, NULL, NULL, + FALSE))) + { + goto Exit; + } + + pucPacketBody += uiDBKeyLen; + uiPacketBodyLen -= uiDBKeyLen; + flmAssert( !uiPacketBodyLen); + } + } + break; + } + + case RFL_CONFIG_SIZE_EVENT_PACKET: + { + uiExpectedBodyLen = 16; + if (uiExpectedBodyLen != uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pOpInfo->uiLastLoggedCommitTransId = pOpInfo->uiTransId; + pucPacketBody += 4; + + pOpInfo->uiSizeThreshold = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + pOpInfo->uiTimeInterval = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + pOpInfo->uiSizeInterval = (FLMUINT) FB2UD( pucPacketBody); + pucPacketBody += 4; + + break; + } + + case RFL_WRAP_KEY_PACKET: + case RFL_ENABLE_ENCRYPTION_PACKET: + { + FLMUINT uiDBKeyLen; + FLMBYTE * pucUncommittedLogHdr = &m_pFile->ucUncommittedLogHdr[0]; + eRestoreActionType eRestoreAction; + + uiExpectedBodyLen = 6; + if (uiExpectedBodyLen >= uiPacketBodyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + pOpInfo->uiTransId = (FLMUINT) FB2UD( pucPacketBody); + pOpInfo->uiLastLoggedCommitTransId = pOpInfo->uiTransId; + pucPacketBody += 4; + uiPacketBodyLen -= 4; + + if (uiPacketBodyLen < 2) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + uiDBKeyLen = FB2UW( pucPacketBody); + pucPacketBody += 2; + uiPacketBodyLen -= 2; + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( + pOpInfo->uiPacketType == RFL_WRAP_KEY_PACKET + ? RESTORE_WRAP_KEY + : RESTORE_ENABLE_ENCRYPTION, + pOpInfo->uiTransId, (void *) uiDBKeyLen, (void *) 0, + (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + m_uiCurrTransID = 0; + break; + } + } + + if (uiDBKeyLen) + { + if (uiPacketBodyLen != uiDBKeyLen) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + // We cannot directly set the key at this point as it may be + // encrypted using a password, which we do not have here. We + // will write the key out to the log header and trust the user + // to know whether or not a password is needed to open the + // database. + + if (RC_BAD( rc = flmBeginDbTrans( pDb, FLM_UPDATE_TRANS, 0, 0))) + { + goto Exit; + } + + f_memcpy( &pucUncommittedLogHdr[ LOG_DATABASE_KEY], pucPacketBody, + uiDBKeyLen); + + UW2FBA( uiDBKeyLen, &pucUncommittedLogHdr[ LOG_DATABASE_KEY_LEN]); + + if (RC_BAD( rc = flmCommitDbTrans( pDb, 0, TRUE))) + { + goto Exit; + } + + pucPacketBody += uiDBKeyLen; + uiPacketBodyLen -= uiDBKeyLen; + flmAssert( !uiPacketBodyLen); + } + + m_uiCurrTransID = 0; + break; + } + + default: + { + flmAssert( 0); + rc = RC_SET( FERR_BAD_RFL_PACKET); + break; + } + } + +Exit: + + return (rc); +} + +/******************************************************************** +Desc: Reads through unknown packets. +*********************************************************************/ +RCODE F_Rfl::readUnknown( + FLMUINT uiLenToRead, + FLMBYTE * pucBuffer, + FLMUINT * puiBytesRead) +{ + RCODE rc = FERR_OK; + FLMUINT uiPacketType; + FLMUINT uiBytesRead = 0; + FLMUINT uiBytesToCopy; + + // If we have read through all of the unknown packets, return + // FERR_EOF_HIT. + + if (!m_bReadingUnknown) + { + rc = RC_SET( FERR_EOF_HIT); + goto Exit; + } + + // Process packets until we have satisfied the read request or until + // we run out of unknown packets. + + while (uiLenToRead) + { + + // Get a packet, if we don't have one. + + if (!m_uiUnknownPacketBodyLen) + { + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, + &m_pucUnknownPacketBody, &m_uiUnknownPacketBodyLen, NULL))) + { + m_bReadingUnknown = FALSE; + m_uiUnknownPacketRc = rc; + goto Exit; + } + + if (uiPacketType != RFL_UNKNOWN_PACKET) + { + if (!uiBytesRead) + { + rc = RC_SET( FERR_EOF_HIT); + } + + m_bReadingUnknown = FALSE; + + // At this point, we know that the entire packet is inside + // our memory buffer, so it is safe to reset m_uiRflReadOffset + // back to the beginning of the packet. The call to readOp() + // will call getPacket again, which will get this exact same + // packet for processing. + + m_uiRflReadOffset -= (RFL_PACKET_OVERHEAD + m_uiUnknownPacketBodyLen); + goto Exit; + } + + m_uiUnknownBodyLenProcessed = 0; + } + + uiBytesToCopy = uiLenToRead; + if (uiBytesToCopy > m_uiUnknownPacketBodyLen - + m_uiUnknownBodyLenProcessed) + { + uiBytesToCopy = m_uiUnknownPacketBodyLen - m_uiUnknownBodyLenProcessed; + } + + f_memcpy( pucBuffer, m_pucUnknownPacketBody + m_uiUnknownBodyLenProcessed, + uiBytesToCopy); + pucBuffer += uiBytesToCopy; + uiLenToRead -= uiBytesToCopy; + uiBytesRead += uiBytesToCopy; + m_uiUnknownBodyLenProcessed += uiBytesToCopy; + + // If we have exhausted the current packet, reset things so that we + // will get a new packet the next time around. + + if (m_uiUnknownBodyLenProcessed == m_uiUnknownPacketBodyLen) + { + m_uiUnknownPacketBodyLen = 0; + m_uiUnknownBodyLenProcessed = 0; + m_pucUnknownPacketBody = NULL; + } + } + +Exit: + + *puiBytesRead = uiBytesRead; + return (rc); +} + +/******************************************************************** +Desc: Restore transactions from the roll-forward log to the + database. +*********************************************************************/ +RCODE F_Rfl::recover( + FDB * pDb, + F_Restore * pRestore) +{ + RCODE rc = FERR_OK; + HFDB hDb = (HFDB) pDb; + FLMUINT uiStartFileNum; + FLMUINT uiStartOffset; + FLMUINT uiOffset; + FLMUINT uiReadLen; + FLMUINT uiBytesRead; + FLMBYTE ucHdr[ 512]; + FLMUINT uiCount; + RFL_OP_INFO opInfo; + FlmRecord * pRecord = NULL; + FlmRecord * pTmpRecord = NULL; + eRestoreActionType eRestoreAction; + FLMBOOL bTransActive = FALSE; + FLMBOOL bHadOperations = FALSE; + FLMBOOL bLastTransEndedAtFileEOF = FALSE; + FLMBOOL bForceNextFile; + + flmAssert( m_pFile); + + m_pCurrentBuf = &m_Buf1; + m_uiLastLoggedCommitTransID = 0; + + // We need to allow all updates logged in the RFL (including + // dictionary updates). + + pDb->bFldStateUpdOk = TRUE; + + // If we are less than version 4.3, we cannot do restore. + + if (pRestore && m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; + } + + // Turn off logging. + + m_bLoggingOff = TRUE; + + // Set the replay flag on the database. + + pDb->uiFlags |= FDB_REPLAYING_RFL; + + // Set the flag as to whether or not we are using multiple RFL files. + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + m_bKeepRflFiles = FALSE; + } + else + { + m_bKeepRflFiles = m_pFile->ucLastCommittedLogHdr[LOG_KEEP_RFL_FILES] + ? TRUE + : FALSE; + } + + // Determine the current, on-disk size of the RFL + + if( m_bKeepRflFiles) + { + FLMUINT64 ui64RflDiskUsage; + + if( RC_BAD( rc = flmRflCalcDiskUsage( m_szRflDir, m_szDbPrefix, + m_pFile->FileHdr.uiVersionNum, &ui64RflDiskUsage))) + { + goto Exit; + } + + f_mutexLock( gv_FlmSysData.hShareMutex); + m_pFile->ui64RflDiskUsage = ui64RflDiskUsage; + f_mutexUnlock( gv_FlmSysData.hShareMutex); + } + + // If pRestore is NULL, we are doing a database recovery after open. + // In that case, we start from the last checkpoint offset and only run + // until the last transaction offset. + + if ((m_pRestore = pRestore) == NULL) + { + FLMBYTE * pucCheckSerialNum; + FLMUINT uiEndOffset; + + uiStartFileNum = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[ LOG_RFL_LAST_CP_FILE_NUM]); + + m_uiLastRecoverFileNum = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[ LOG_RFL_FILE_NUM]); + + uiStartOffset = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[ LOG_RFL_LAST_CP_OFFSET]); + + uiEndOffset = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + // Could be zero if the file was created, but no transactions were + // ever committed to it. + + if (!uiEndOffset) + { + uiEndOffset = 512; + } + + // Start offset better not be less than 512. + + flmAssert( uiStartOffset >= 512); + flmAssert( uiEndOffset >= 512); + + // If start and end are at the same place, there is nothing to + // recover. + + if (uiStartFileNum == m_uiLastRecoverFileNum && + uiStartOffset == uiEndOffset) + { + goto Finish_Recovery; + } + + // We have not recorded the serial number of the last checkpoint + // file number, so we pass in NULL, unless it happens to be the same + // as the last transaction file number, in which case we can pass in + // the serial number we have stored in the log header. + + pucCheckSerialNum = (uiStartFileNum == m_uiLastRecoverFileNum) + ? &m_pFile->ucLastCommittedLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM] + : NULL; + + if (RC_BAD( rc = openFile( uiStartFileNum, pucCheckSerialNum))) + { + goto Exit; + } + + // If this is the last RFL file, the EOF is contained in the log + // header. Otherwise, it will be in the RFL file's header, and + // openFile will already have retrieved it. + + if (uiStartFileNum == m_uiLastRecoverFileNum) + { + m_uiFileEOF = uiEndOffset; + } + + // At this point, file EOF better be greater than or equal to 512. + + flmAssert( m_uiFileEOF >= 512); + } + else if (!m_bKeepRflFiles) + { + + // FlmDbRestore should be checking the "keep" flag and not + // attempting to do a restore of the RFL. + + flmAssert( 0); + rc = RC_SET( FERR_CANNOT_RESTORE_RFL_FILES); + goto Exit; + } + else + { + uiStartFileNum = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_FILE_NUM]); + + uiStartOffset = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + // Could be zero if the RFL file had never been created. + + if (!uiStartOffset) + { + uiStartOffset = 512; + } + + // Ask the recovery object to open the file. + +Retry_Open: + + flmAssert( uiStartFileNum); + if (RC_BAD( rc = m_pRestore->openRflFile( uiStartFileNum))) + { + if (rc == FERR_IO_PATH_NOT_FOUND) + { + + // Need to set m_pCurrentBuf->uiCurrFileNum in case the first + // call to openRflFile fails. This will cause the code at the + // Finish_Recovery label to correctly set up the log header. + + if (!uiStartOffset) + { + m_pCurrentBuf->uiCurrFileNum = uiStartFileNum - 1; + } + else + { + m_pCurrentBuf->uiCurrFileNum = uiStartFileNum; + } + + rc = FERR_OK; + goto Finish_Recovery; + } + else + { + goto Exit; + } + } + + // Get the first 512 bytes from the file and verify the header. + + if (RC_BAD( rc = m_pRestore->read( 512, ucHdr, &uiBytesRead))) + { + goto Exit; + } + + if (uiBytesRead < 512) + { + rc = RC_SET( FERR_NOT_RFL); + goto Exit; + } + + if (RC_BAD( rc = verifyHeader( ucHdr, uiStartFileNum, + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_TRANS_RFL_SERIAL_NUM]))) + { + RCODE tmpRc; + + if (RC_BAD( tmpRc = m_pRestore->status( RESTORE_ERROR, 0, + (void *) ((FLMUINT) rc), (void *) 0, (void *) 0, + &eRestoreAction))) + { + rc = tmpRc; + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_RETRY) + { + if (RC_BAD( rc = m_pRestore->close())) + { + goto Exit; + } + + goto Retry_Open; + } + + goto Exit; + } + + // We may not know the actual EOF of files during restore + // operations. + + if ((m_uiFileEOF = (FLMUINT) FB2UD( &ucHdr[RFL_EOF_POS])) == 0) + { + bLastTransEndedAtFileEOF = TRUE; + } + else + { + bLastTransEndedAtFileEOF = (m_uiFileEOF == uiStartOffset) + ? TRUE + : FALSE; + } + + // Position to the start offset. Unfortunately, this means reading + // through the data and discarding it. + + uiOffset = 512; + while (uiOffset < uiStartOffset) + { + uiReadLen = (uiStartOffset - uiOffset); + if (uiReadLen > m_uiBufferSize) + { + uiReadLen = m_uiBufferSize; + } + + if (RC_BAD( rc = m_pRestore->read( uiReadLen, + m_pCurrentBuf->pIOBuffer->m_pucBuffer, &uiBytesRead))) + { + goto Exit; + } + + // RFL file is incomplete if we could not read up to the last + // committed transaction. + + if (uiBytesRead < uiReadLen) + { + rc = RC_SET( FERR_RFL_INCOMPLETE); + goto Exit; + } + + uiOffset += uiBytesRead; + } + + // Need to set current file number + + m_pCurrentBuf->uiCurrFileNum = uiStartFileNum; + + // Better not be any transactions to recover - last database state + // needs to be a completed checkpoint. + + flmAssert( + FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_LAST_CP_TRANS_ID]) == + FB2UD( &m_pFile->ucLastCommittedLogHdr [LOG_CURR_TRANS_ID])); + + // Use uiStartOffset here instead of LOG_RFL_LAST_TRANS_OFFSET, + // because LOG_RFL_LAST_TRANS_OFFSET may be zero, but we in that + // case we should be comparing to 512, and uiStartOffset will have + // been adjusted to 512 if that is the case. + + flmAssert( FB2UD( &m_pFile->ucLastCommittedLogHdr [ + LOG_RFL_LAST_CP_OFFSET]) == uiStartOffset); + + flmAssert( FB2UD( &m_pFile->ucLastCommittedLogHdr[ + LOG_RFL_LAST_CP_FILE_NUM]) == uiStartFileNum); + } + + // Set last transaction ID to the last transaction that was + // checkpointed - transaction numbers should ascend from here. + + m_uiLastTransID = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_CP_TRANS_ID]); + + // Set the last committed trans ID if this is a 4.31+ database + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31) + { + m_uiLastLoggedCommitTransID = (FLMUINT) FB2UD( + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_RFL_COMMIT_ID]); + } + + m_pCurrentBuf->uiRflFileOffset = uiStartOffset; + m_uiRflReadOffset = 0; + m_pCurrentBuf->uiRflBufBytes = 0; + + // Now, read until we are done. + + bForceNextFile = FALSE; + for (;;) + { + if (!pRecord) + { + if ((pRecord = f_new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + } + + // Get the next operation from the file. + + rc = readOp( pDb, bForceNextFile, &opInfo, pRecord); + bForceNextFile = FALSE; + + if (RC_BAD( rc)) + { +Handle_Packet_Error: + + if (rc == FERR_END) + { + if (!m_pRestore) + { + + // If we didn't end exactly where we should have, we have + // an incomplete log. The same is true if we are in the + // middle of a transaction. + + if (m_pCurrentBuf->uiCurrFileNum != m_uiLastRecoverFileNum || + bTransActive) + { + rc = RC_SET( FERR_RFL_INCOMPLETE); + } + else + { + rc = FERR_OK; + goto Finish_Recovery; + } + } + else + { + + // If we are doing a restore, and we get to the end of the + // log, it is OK - even if we are in the middle of a + // transaction - the transaction will simply be aborted. + + rc = FERR_OK; + goto Finish_Recovery; + } + } + else if (rc == FERR_BAD_RFL_PACKET) + { + + // If we don't know the current file size, and we are doing a + // restore, it is OK to end on a bad packet - we will simply + // abort the current transaction, if any. Then, try to go to + // the next file, because we really don't know where this file + // ends. + + if (m_pRestore && !m_uiFileEOF) + { + if (bTransActive) + { + FlmDbTransAbort( hDb); + bTransActive = FALSE; + } + + // Set current transaction ID to zero - as if we had + // encountered an abort packet. + + m_uiCurrTransID = 0; + bLastTransEndedAtFileEOF = TRUE; + + // Force to go to the next file + + bForceNextFile = TRUE; + rc = FERR_OK; + continue; + } + } + + goto Exit; + } + + // At this point, we know we have a good packet, see what it is and + // handle it. + + bHadOperations = TRUE; + switch (opInfo.uiPacketType) + { + case RFL_TRNS_BEGIN_EX_PACKET: + case RFL_TRNS_BEGIN_PACKET: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_BEGIN_TRANS, + opInfo.uiTransId, (void *) opInfo.uiStartTime, + (void *) 0, (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + + // Need to set m_uiCurrTransID to 0 since it was set by + // getPacket(). We are not going to start a transaction + // because of the user's request to exit. + + m_uiCurrTransID = 0; + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + // If we already have a transaction active, we have a problem. + + flmAssert( !bTransActive); + + if (RC_BAD( rc = FlmDbTransBegin( hDb, FLM_UPDATE_TRANS, 0))) + { + goto Exit; + } + + bTransActive = TRUE; + break; + } + + case RFL_TRNS_COMMIT_PACKET: + { + + // Commit the current transaction. + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_COMMIT_TRANS, + opInfo.uiTransId, (void *) 0, (void *) 0, (void *) 0, + &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + flmAssert( bTransActive); + pDb->uiFlags |= FDB_REPLAYING_COMMIT; + rc = FlmDbTransCommit( hDb); + pDb->uiFlags &= ~FDB_REPLAYING_COMMIT; + bTransActive = FALSE; + + if (RC_BAD( rc)) + { + goto Exit; + } + + m_uiLastLoggedCommitTransID = opInfo.uiTransId; + +Finish_Transaction: + + if (!m_uiFileEOF) + { + bLastTransEndedAtFileEOF = TRUE; + } + else + { + bLastTransEndedAtFileEOF = + (m_uiRflReadOffset == m_pCurrentBuf->uiRflBufBytes && + m_pCurrentBuf->uiRflFileOffset + + m_pCurrentBuf->uiRflBufBytes == m_uiFileEOF) + ? TRUE + : FALSE; + } + + m_uiLastTransID = opInfo.uiTransId; + m_uiCurrTransID = 0; + break; + } + + case RFL_TRNS_ABORT_PACKET: + { + + // Abort the current transaction. + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_ABORT_TRANS, + opInfo.uiTransId, (void *) 0, (void *) 0, (void *) 0, + &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + flmAssert( bTransActive); + rc = FlmDbTransAbort( hDb); + bTransActive = FALSE; + + if (RC_BAD( rc)) + { + goto Exit; + } + + goto Finish_Transaction; + } + + case RFL_ADD_RECORD_PACKET: + case RFL_ADD_RECORD_PACKET_VER_2: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_ADD_REC, + opInfo.uiTransId, (void *) opInfo.uiContainer, + (void *) opInfo.uiDrn, + (void *) pRecord, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + rc = FlmRecordAdd( hDb, opInfo.uiContainer, &opInfo.uiDrn, + pRecord, opInfo.uiFlags); + pRecord->Release(); + pRecord = NULL; + if (RC_BAD( rc)) + { + goto Exit; + } + break; + } + + case RFL_MODIFY_RECORD_PACKET: + case RFL_MODIFY_RECORD_PACKET_VER_2: + { + + // Must retrieve the record and then get the modify packet(s) + // to alter it. + + if (RC_BAD( rc = FlmRecordRetrieve( hDb, opInfo.uiContainer, + opInfo.uiDrn, FO_EXACT, &pRecord, NULL))) + { + goto Exit; + } + + if ((pTmpRecord = pRecord->copy()) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + pRecord->Release(); + pRecord = NULL; + + if (RC_BAD( rc = modifyRecord( hDb, pTmpRecord))) + { + goto Handle_Packet_Error; + } + + // Finally, modify the record in the database. + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_MOD_REC, + opInfo.uiTransId, + (void *) opInfo.uiContainer, (void *) opInfo.uiDrn, + (void *) pTmpRecord, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + rc = FlmRecordModify( hDb, opInfo.uiContainer, opInfo.uiDrn, + pTmpRecord, opInfo.uiFlags); + + pTmpRecord->Release(); + pTmpRecord = NULL; + + if (RC_BAD( rc)) + { + goto Exit; + } + + break; + } + + case RFL_DELETE_RECORD_PACKET: + case RFL_DELETE_RECORD_PACKET_VER_2: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_DEL_REC, + opInfo.uiTransId, + (void *) opInfo.uiContainer, (void *) opInfo.uiDrn, + (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = FlmRecordDelete( hDb, opInfo.uiContainer, + opInfo.uiDrn, opInfo.uiFlags))) + { + goto Exit; + } + break; + } + + case RFL_RESERVE_DRN_PACKET: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_RESERVE_DRN, + opInfo.uiTransId, (void *) opInfo.uiContainer, + (void *) opInfo.uiDrn, (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = FlmReserveNextDrn( hDb, opInfo.uiContainer, + &opInfo.uiDrn))) + { + goto Exit; + } + + break; + } + + case RFL_INDEX_SUSPEND_PACKET: + { + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_INDEX_SUSPEND, + opInfo.uiTransId, (void *) opInfo.uiIndex, + (void *) 0, (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = FlmIndexSuspend( hDb, opInfo.uiIndex))) + { + goto Exit; + } + + break; + } + + case RFL_INDEX_RESUME_PACKET: + { + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_INDEX_RESUME, + opInfo.uiTransId, (void *) opInfo.uiIndex, (void *) 0, + (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = FlmIndexResume( hDb, opInfo.uiIndex))) + { + goto Exit; + } + break; + } + + case RFL_INDEX_SET_PACKET: + case RFL_INDEX_SET_PACKET_VER_2: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_INDEX_SET, + opInfo.uiTransId, (void *) opInfo.uiIndex, + (void *) opInfo.uiDrn, (void *) opInfo.uiEndDrn, + &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (m_pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_50 && + opInfo.uiPacketType != RFL_INDEX_SET_PACKET) + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + goto Exit; + } + + if (RC_BAD( rc = flmDbIndexSetOfRecords( hDb, opInfo.uiIndex, + opInfo.uiContainer, opInfo.uiDrn, opInfo.uiEndDrn))) + { + goto Exit; + } + + break; + } + + case RFL_BLK_CHAIN_FREE_PACKET: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_BLK_CHAIN_DELETE, + opInfo.uiTransId, (void *) opInfo.uiDrn, + (void *) opInfo.uiCount, + (void *) opInfo.uiEndBlock, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = flmMaintFreeBlockChain( pDb, opInfo.uiDrn, + opInfo.uiCount, opInfo.uiEndBlock, NULL))) + { + goto Exit; + } + break; + } + + case RFL_START_UNKNOWN_PACKET: + { + if (m_pRestore) + { + F_RflUnknownStream unkStrm; + + unkStrm.setup( this, TRUE); + m_bReadingUnknown = TRUE; + m_uiUnknownPacketBodyLen = 0; + m_pucUnknownPacketBody = NULL; + m_uiUnknownBodyLenProcessed = 0; + m_uiUnknownPacketRc = FERR_OK; + + if (RC_BAD( rc = m_pRestore->processUnknown( + (F_UnknownStream*) &unkStrm))) + { + if (m_uiUnknownPacketRc != FERR_OK) + { + rc = m_uiUnknownPacketRc; + goto Handle_Packet_Error; + } + + goto Exit; + } + + // If we did not read through all of the unknown packets, + // skip them at this time. + + if (m_bReadingUnknown) + { + goto Skip_Unknown_Packets; + } + } + else + { +Skip_Unknown_Packets: + + // Skip all unknown packets. + + for (;;) + { + FLMUINT uiPacketType; + FLMBYTE * pucPacketBody; + FLMUINT uiPacketBodyLen; + + if (RC_BAD( rc = getPacket( FALSE, &uiPacketType, + &pucPacketBody, &uiPacketBodyLen, NULL))) + { + goto Handle_Packet_Error; + } + + // If we hit something other than an unknown packet, + // "push" it back into the pipe so it will be processed + // by readOp() up above. + + if (uiPacketType != RFL_UNKNOWN_PACKET) + { + + // At this point, we know that the entire packet is + // inside our memory buffer, so it is safe to reset + // m_uiRflReadOffset back to the beginning of the + // packet. The call to readOp() above will call + // getPacket again, which will get this exact same + // packet for processing. + + m_uiRflReadOffset -= + (RFL_PACKET_OVERHEAD + uiPacketBodyLen); + break; + } + } + } + break; + } + + case RFL_REDUCE_PACKET: + { + + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_REDUCE, + opInfo.uiTransId, (void *) opInfo.uiCount, + (void *) 0, (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + + // Need to set m_uiCurrTransID to 0 since it was set by + // getPacket(). We are not going to start a transaction + // because of the user's request to exit. + + m_uiCurrTransID = 0; + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = FlmDbReduceSize( hDb, opInfo.uiCount, &uiCount))) + { + goto Exit; + } + + goto Finish_Transaction; + } + + case RFL_UPGRADE_PACKET: + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_UPGRADE, + opInfo.uiTransId, + (void *) opInfo.uiOldVersion, + (void *) opInfo.uiNewVersion, + (void *) 0, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + + // Need to set m_uiCurrTransID to 0 since it was set by + // getPacket(). We are not going to start a transaction + // because of the user's request to exit. + + m_uiCurrTransID = 0; + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + // Attempt the conversion if the current version is less than + // the target version and the target version is less than or + // equal to the highest version supported by this code. + + if (opInfo.uiNewVersion > FLM_CUR_FILE_FORMAT_VER_NUM) + { + rc = RC_SET( FERR_UNALLOWED_UPGRADE); + goto Exit; + } + else + { + flmAssert( m_pFile->FileHdr.uiVersionNum < opInfo.uiNewVersion); + + // The logged "new" version may be a lesser version than + // FLM_CURRENT_FILE_FORMAT_VERSION, which is what FlmDbUpgrade + // upgrades to. This is OK because the current version + // should support all packets in the RFL for versions that + // are less than it. Otherwise, the RFL chain would have + // been broken by the original upgrade and it would not + // have logged an upgrade packet. + + if (RC_BAD( rc = FlmDbUpgrade( hDb, opInfo.uiNewVersion, + NULL, NULL))) + { + goto Exit; + } + } + + goto Finish_Transaction; + } + + case RFL_WRAP_KEY_PACKET: + case RFL_ENABLE_ENCRYPTION_PACKET: + { + goto Finish_Transaction; + } + + case RFL_CONFIG_SIZE_EVENT_PACKET: // here + { + if (m_pRestore) + { + if (RC_BAD( rc = m_pRestore->status( RESTORE_CONFIG_SIZE_EVENT, + opInfo.uiTransId, + (void *) opInfo.uiSizeThreshold, + (void *) opInfo.uiTimeInterval, + (void *) opInfo.uiSizeInterval, &eRestoreAction))) + { + goto Exit; + } + + if (eRestoreAction == RESTORE_ACTION_STOP) + { + + // Need to set m_uiCurrTransID to 0 since it was set by + // getPacket(). We are not going to start a transaction + // because of the user's request to exit. + + m_uiCurrTransID = 0; + bLastTransEndedAtFileEOF = FALSE; + goto Finish_Recovery; + } + } + + if (RC_BAD( rc = flmSetRflSizeThreshold( + hDb, opInfo.uiSizeThreshold, opInfo.uiTimeInterval, + opInfo.uiSizeInterval))) + { + goto Exit; + } + + goto Finish_Transaction; + } + + default: + { + + // Should not be getting other packet types at this point. ; + // If we don't know the current file size, and we are doing a + // restore, it is OK to end on a bad packet - we will simply + // abort the current transaction, if any. + + if (m_pRestore && !m_uiFileEOF) + { + rc = FERR_OK; + goto Finish_Recovery; + } + else + { + rc = RC_SET( FERR_BAD_RFL_PACKET); + } + + goto Exit; + } + } + } + +Finish_Recovery: + + if (bTransActive) + { + FlmDbTransAbort( hDb); + bTransActive = FALSE; + } + + if (m_pRestore) + { + FLMUINT uiNextRflFileNum = m_pCurrentBuf->uiCurrFileNum + 1; + + // At the end of the restore operation, we need to set things up so + // that the next transaction will begin a new RFL file. If we ended + // the restore in the middle of an RFL file, we need to set it up so + // that the new RFL file will have a new serial number. If we ended + // at the end of an RFL file, we can set it up so that the new RFL + // file will have the next serial number. ; + // Set up the next RFL file number and offset. + + UD2FBA( uiNextRflFileNum, + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_FILE_NUM]); + + // Set a zero into the offset, this is a special case which tells + // us that we should create the file no matter what - even if it + // already exists - it should be overwritten. + + UD2FBA( 0, &m_pFile->ucLastCommittedLogHdr[LOG_RFL_LAST_TRANS_OFFSET]); + + if (bLastTransEndedAtFileEOF) + { + + // Move the next serial number of the last RFL file processed + // into into the current RFL serial number so that the log header + // will be correct + + f_memcpy( &m_pFile->ucLastCommittedLogHdr[ + LOG_LAST_TRANS_RFL_SERIAL_NUM], m_ucNextSerialNum, + F_SERIAL_NUM_SIZE); + } + else + { + + // Must create a new serial number so that when the new RFL file + // is created, it will have that next serial number. + + if (RC_BAD( rc = f_createSerialNumber( &m_pFile->ucLastCommittedLogHdr[ + LOG_LAST_TRANS_RFL_SERIAL_NUM]))) + { + goto Exit; + } + } + + // Save the last logged commit transaction ID. + + if (m_pFile->FileHdr.uiVersionNum >= FLM_FILE_FORMAT_VER_4_31 && + m_uiLastLoggedCommitTransID) + { + UD2FBA( m_uiLastLoggedCommitTransID, + &m_pFile->ucLastCommittedLogHdr[LOG_LAST_RFL_COMMIT_ID]); + } + + // No matter what, we must generate a new next serial number. This + // is what will be written to the new RFL file's header when it is + // created. + + if (RC_BAD( rc = f_createSerialNumber( + &m_pFile->ucLastCommittedLogHdr[LOG_RFL_NEXT_SERIAL_NUM]))) + { + goto Exit; + } + } + + if (!bHadOperations) + { + + // No transactions were recovered, but still need to setup a few + // things. + + m_pFile->uiFirstLogCPBlkAddress = 0; + m_pFile->uiLastCheckpointTime = (FLMUINT) FLM_GET_TIMER(); + + // Save the state of the log header into the ucCheckpointLogHdr + // buffer. + + f_memcpy( m_pFile->ucCheckpointLogHdr, m_pFile->ucLastCommittedLogHdr, + LOG_HEADER_SIZE); + } + + // Force a checkpoint to force the log files to be truncated and + // everything to be reset. This is done because during recovery the + // checkpoints that are executed do NOT truncate the RFL file - because + // it is using the log file to recover! + + closeFile(); + m_pRestore = NULL; + m_bLoggingOff = FALSE; + pDb->uiFlags &= ~FDB_REPLAYING_RFL; + + if (RC_BAD( rc = FlmDbCheckpoint( hDb, 0))) + { + goto Exit; + } + +Exit: + + if (pRecord) + { + pRecord->Release(); + } + + if (pTmpRecord) + { + pTmpRecord->Release(); + } + + if (bTransActive) + { + FlmDbTransAbort( hDb); + } + + pDb->bFldStateUpdOk = FALSE; + pDb->uiFlags &= ~FDB_REPLAYING_RFL; + + return (rc); +} + +/******************************************************************** +Desc: +********************************************************************/ +RCODE flmRflCalcDiskUsage( + const char * pszRflDir, + const char * pszRflPrefix, + FLMUINT uiDbVersionNum, + FLMUINT64 * pui64DiskUsage) +{ + RCODE rc = FERR_OK; + F_DirHdl * pDirHdl = NULL; + FLMUINT uiFileNumber; + FLMUINT64 ui64DiskUsage; + + ui64DiskUsage = 0; + + if( RC_BAD( rc = gv_FlmSysData.pFileSystem->OpenDir( pszRflDir, + (char *) "*", &pDirHdl))) + { + if( rc == FERR_IO_PATH_NOT_FOUND) + { + rc = FERR_OK; + } + + goto Exit; + } + + for( ;;) + { + if( RC_BAD( rc = pDirHdl->Next())) + { + if( rc != FERR_IO_NO_MORE_FILES && rc != FERR_IO_PATH_NOT_FOUND) + { + goto Exit; + } + + rc = FERR_OK; + break; + } + + // If the current file is an RFL file, increment the disk usage + + if( rflGetFileNum( uiDbVersionNum, pszRflPrefix, + pDirHdl->CurrentItemName(), &uiFileNumber)) + { + ui64DiskUsage += pDirHdl->CurrentItemSize(); + } + } + +Exit: + + *pui64DiskUsage = ui64DiskUsage; + + if( pDirHdl) + { + pDirHdl->Release(); + } + + return( rc); +} + +/******************************************************************** +Desc: Returns the name of an RFL file given its number +********************************************************************/ +FLMEXP RCODE FLMAPI FlmDbGetRflFileName( + HFDB hDb, + FLMUINT uiFileNum, + char * pszFileName) +{ + ((FDB *) hDb)->pFile->pRfl->getBaseRflFileName( uiFileNum, pszFileName); + return (FERR_OK); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +F_RflUnknownStream::F_RflUnknownStream() +{ + m_pRfl = NULL; + m_bStartedWriting = FALSE; + m_bInputStream = FALSE; + m_bSetupCalled = FALSE; +} + +/**************************************************************************** +Desc: +****************************************************************************/ +F_RflUnknownStream::~F_RflUnknownStream() +{ + if (m_bSetupCalled) + { + (void)close(); + } +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_RflUnknownStream::setup( + F_Rfl * pRfl, + FLMBOOL bInputStream) +{ + RCODE rc = FERR_OK; + + flmAssert( !m_bSetupCalled); + + if (!pRfl) + { + flmAssert( 0); + rc = RC_SET( FERR_INVALID_PARM); + goto Exit; + } + m_pRfl = pRfl; + m_bInputStream = bInputStream; + m_bSetupCalled = TRUE; + m_bStartedWriting = FALSE; + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_RflUnknownStream::close( void) +{ + RCODE rc = FERR_OK; + + flmAssert( m_bSetupCalled); + + // There is nothing to do for input streams, because the RFL + // code handles skipping over any unknown data that may not have + // been read yet. + // For output streams, we need to call the endLoggingUnknown + // routine so that the last packet gets written out. + + if (!m_bInputStream) + { + if (m_bStartedWriting) + { + m_bStartedWriting = FALSE; + if (RC_BAD( rc = m_pRfl->endLoggingUnknown())) + { + goto Exit; + } + } + } +Exit: + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_RflUnknownStream::read( + FLMUINT uiLength, + void * pvBuffer, + FLMUINT * puiBytesRead) +{ + RCODE rc = FERR_OK; + + flmAssert( m_bSetupCalled); + + if (!m_bInputStream) + { + + // Cannot read from an output stream. + + flmAssert( 0); + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + if (RC_BAD( rc = m_pRfl->readUnknown( uiLength, (FLMBYTE *)pvBuffer, + puiBytesRead))) + { + goto Exit; + } + +Exit: + return( rc); +} + +/**************************************************************************** +Desc: +****************************************************************************/ +RCODE F_RflUnknownStream::write( + FLMUINT uiLength, + void * pvBuffer) +{ + RCODE rc = FERR_OK; + + flmAssert( m_bSetupCalled); + flmAssert( m_pRfl); + + if (m_bInputStream) + { + + // Cannot write to an input stream. + + flmAssert( 0); + rc = RC_SET( FERR_ILLEGAL_OP); + goto Exit; + } + + // Need to start logging on the first write. + + if (!m_bStartedWriting) + { + if (RC_BAD( rc = m_pRfl->startLoggingUnknown())) + { + goto Exit; + } + m_bStartedWriting = TRUE; + } + + // Log the data. + + if (RC_BAD( rc = m_pRfl->logUnknown( (FLMBYTE *)pvBuffer, uiLength))) + { + goto Exit; + } +Exit: + return( rc); +} + +/**************************************************************************** +Desc: Returns an unknown stream object - suitable for writing unknown + streams into the roll-forward log. +****************************************************************************/ +FLMEXP RCODE FLMAPI FlmDbGetUnknownStreamObj( + HFDB hDb, + F_UnknownStream ** ppUnknownStream) +{ + RCODE rc = FERR_OK; + FDB * pDb = (FDB *)hDb; + F_RflUnknownStream * pUnkStream = NULL; + + flmAssert( pDb); + flmAssert( ppUnknownStream); + + // See if the database is being forced to close + + if( RC_BAD( rc = flmCheckDatabaseState( pDb))) + { + goto Exit; + } + + // This is only valid on 4.3 and greater. + + if (pDb->pFile->FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) + { + goto Exit; // Will return FERR_OK and a NULL pointer. + } + + // Must be in an update transaction. + + if (pDb->uiTransType == FLM_NO_TRANS) + { + rc = RC_SET( FERR_NO_TRANS_ACTIVE); + goto Exit; + } + if (pDb->uiTransType != FLM_UPDATE_TRANS) + { + rc = RC_SET( FERR_ILLEGAL_TRANS_OP); + goto Exit; + } + + // Allocate the stream object we want. + + if ((pUnkStream = f_new F_RflUnknownStream) == NULL) + { + rc = RC_SET( FERR_MEM); + goto Exit; + } + + // Setup the unknown stream object. + + if (RC_BAD( rc = pUnkStream->setup( pDb->pFile->pRfl, FALSE))) + { + goto Exit; + } + +Exit: + + if (RC_BAD( rc) && pUnkStream) + { + pUnkStream->Release(); + pUnkStream = NULL; + } + *ppUnknownStream = (F_UnknownStream *)pUnkStream; + return( rc); +} diff --git a/flaim/src/rfl.h b/flaim/src/rfl.h index 604fec4..f8f1fd5 100644 --- a/flaim/src/rfl.h +++ b/flaim/src/rfl.h @@ -26,6 +26,7 @@ #define RFL_H #include "fpackon.h" + // IMPORTANT NOTE: No other include files should follow this one except // for fpackoff.h @@ -57,6 +58,7 @@ #define RFL_RESERVED_FOR_KEPLER_24 24 #define RFL_WRAP_KEY_PACKET 25 #define RFL_ENABLE_ENCRYPTION_PACKET 26 +#define RFL_CONFIG_SIZE_EVENT_PACKET 27 #define RFL_TIME_LOGGED_FLAG 0x80 #define RFL_PACKET_TYPE_MASK 0x7F @@ -135,19 +137,45 @@ #define RFL_MAX_PACKET_BODY_SIZE ((RFL_MAX_PACKET_SIZE - \ RFL_PACKET_OVERHEAD) & 0xFFFC) - -typedef struct RflWaiterTag * RFL_WAITER_p; - -typedef struct RflWaiterTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct RFL_OP_INFO +{ + FLMUINT uiPacketType; + FLMUINT uiContainer; + FLMUINT uiDrn; + FLMUINT uiIndex; + FLMUINT uiEndDrn; + FLMUINT uiTransId; + FLMUINT uiStartTime; + FLMUINT uiLastLoggedCommitTransId; + FLMUINT uiFlags; + FLMUINT uiCount; + FLMUINT uiEndBlock; + FLMUINT uiOldVersion; + FLMUINT uiNewVersion; + FLMUINT uiSizeThreshold; + FLMUINT uiSizeInterval; + FLMUINT uiTimeInterval; +} RFL_OP_INFO; + +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct RFL_WAITER { FLMUINT uiThreadId; FLMBOOL bIsWriter; F_SEM hESem; RCODE * pRc; - RFL_WAITER_p pNext; + RFL_WAITER * pNext; } RFL_WAITER; -typedef struct RflBufferTag +/**************************************************************************** +Desc: +****************************************************************************/ +typedef struct RFL_BUFFER { F_IOBufferMgr * pBufferMgr; // Write buffer manager F_IOBuffer * pIOBuffer; @@ -189,17 +217,17 @@ public: // database is first opened or created. RCODE setup( - FFILE_p pFile, + FFILE * pFile, const char * pszRflDir); RCODE finishCurrFile( - FDB_p pDb, + FDB * pDb, FLMBOOL bNewKeepState); // Log transaction begin RCODE logBeginTransaction( - FDB_p pDb); + FDB * pDb); // Log transaction commit or abort @@ -269,6 +297,14 @@ public: FLMUINT uiOldVersion, FLMBYTE * pucDBKey, FLMUINT32 ui32DBKeyLen); + + // Routine for logging size event configuration + + RCODE logSizeEventConfig( + FLMUINT uiTransID, + FLMUINT uiSizeThreshold, + FLMUINT uiSecondsBetweenEvents, + FLMUINT uiBytesBetweenEvents); // Routines for restore operations. @@ -278,7 +314,7 @@ public: FLMUINT * puiBytesRead); RCODE recover( - FDB_p pDb, + FDB * pDb, F_Restore * pRestore); FLMBOOL atEndOfLog( void); @@ -305,7 +341,12 @@ public: FINLINE const char * getRflDirPtr( void) { - return &m_szRflDir [0]; + return( m_szRflDir); + } + + FINLINE const char * getDbPrefixPtr( void) + { + return( m_szDbPrefix); } FINLINE FLMBOOL isRflDirSameAsDbDir( void) @@ -409,6 +450,7 @@ public: { flmAssert( !m_pCurrentBuf->pBufferMgr->havePendingIO()); } + if (m_pFileHdl) { m_pFileHdl->Close(); @@ -476,7 +518,7 @@ public: FLMBOOL bIsWriter); RCODE completeTransWrites( - FDB_p pDb, + FDB * pDb, FLMBOOL bCommitting, FLMBOOL bOkToUnlock); @@ -489,6 +531,11 @@ public: FLMUINT uiTransID, FLMBYTE * pucDBKey, FLMUINT32 ui32DBKeyLen); + + FINLINE const char * getRflDir( void) + { + return( m_szRflDir); + } private: @@ -631,16 +678,8 @@ private: RCODE readOp( FDB * pDb, FLMBOOL bForceNextFile, - FLMUINT * puiOpRV, - FLMUINT * puiContainerRV, - FLMUINT * puiDrnRV, - FLMUINT * puiIndexRV, - FLMUINT * puiEndDrnRV, - FlmRecord * pRecord, - FLMUINT * puiTransIDRV, - FLMUINT * puiStartTimeRV, - FLMUINT * puiLastCommittedTransId, - FLMUINT * puiFlags); + RFL_OP_INFO * pOpInfo, + FlmRecord * pRecord); RCODE setupTransaction( void); @@ -648,7 +687,7 @@ private: // Member variables - FFILE_p m_pFile; // Pointer to FFILE structure + FFILE * m_pFile; // Pointer to FFILE structure RFL_BUFFER m_Buf1; RFL_BUFFER m_Buf2; F_MUTEX m_hBufMutex; @@ -719,13 +758,51 @@ private: // RFL volume? }; +/**************************************************************************** +Desc: This object is our implementation of the + F_UnknownStream object which is used to handle unknown + objects in the RFL. +****************************************************************************/ +class F_RflUnknownStream : public F_UnknownStream +{ +public: + + F_RflUnknownStream(); + virtual ~F_RflUnknownStream(); + + RCODE setup( + F_Rfl * pRfl, + FLMBOOL bInputStream); + + RCODE reset( void); + + RCODE read( + FLMUINT uiLength, // Number of bytes to read + void * pvBuffer, // Buffer to place read bytes into + FLMUINT * puiBytesRead); // [out] Number of bytes read + + RCODE write( + FLMUINT uiLength, // Number of bytes to write + void * pvBuffer); + + RCODE close( void); // Reads to the end of the + // stream and discards any + // remaining data (if input stream). + +private: + + FLMBOOL m_bSetupCalled; + F_Rfl * m_pRfl; // RFL object. + FLMBOOL m_bInputStream; // TRUE=input stream, FALSE=output stream + FLMBOOL m_bStartedWriting; // Only used for output streams +}; + /************************************************************************** -Struct: RFL_CHANGE_DATA Desc: This structure is passed to the callback function that gets the differences between an old and a new record when a record modify operation is logged. **************************************************************************/ -typedef struct Rfl_Change_Data +typedef struct RFL_CHANGE_DATA { RCODE rc; FLMUINT uiVersionNum; @@ -734,7 +811,7 @@ typedef struct Rfl_Change_Data FLMUINT uiPacketCount; FLMUINT uiTotalBytesLogged; FLMUINT uiMaxLogBytesNeeded; -} RFL_CHANGE_DATA, * RFL_CHANGE_DATA_p; +} RFL_CHANGE_DATA; FLMBYTE RflCalcChecksum( const FLMBYTE * pucPacket, @@ -766,6 +843,12 @@ FLMBOOL rflGetFileNum( const char * pszRflFileName, FLMUINT * puiFileNum); +RCODE flmRflCalcDiskUsage( + const char * pszRflDir, + const char * pszRflPrefix, + FLMUINT uiDbVersionNum, + FLMUINT64 * pui64DiskUsage); + #include "fpackoff.h" #endif diff --git a/flaim/src/scache.cpp b/flaim/src/scache.cpp index b376d60..e42d083 100644 --- a/flaim/src/scache.cpp +++ b/flaim/src/scache.cpp @@ -30,13 +30,7 @@ #define MAX_BLOCKS_TO_SORT 500 -FINLINE FLMUINT SCA_MEM_SIZE( - SCACHE * pSCache) -{ - return( sizeof( SCACHE) + pSCache->ui16BlkSize); -} - -typedef struct Tmp_Read_Stats +typedef struct TMP_READ_STATS { DISKIO_STAT BlockReads; // Statistics on block reads DISKIO_STAT OldViewBlockReads; // Statistics on old view @@ -47,13 +41,13 @@ typedef struct Tmp_Read_Stats FLMUINT uiOldViewBlockChkErrs; // Number of times we had // check errors reading an // old view of a block -} TMP_READ_STATS, * TMP_READ_STATS_p; +} TMP_READ_STATS; FLMUINT ScaGetBlkSize( SCACHE ** pSCache); -#define ScaGetBlkSize( pSCache) (FLMUINT)((pSCache)->ui16BlkSize) - +#define ScaGetBlkSize( pSCache) \ + (FLMUINT)((pSCache)->ui16BlkSize) FSTATIC void ScaUnlinkFromGlobalList( SCACHE * pSCache); @@ -86,8 +80,7 @@ FSTATIC void ScaUnlinkFromFreeList( FSTATIC void ScaDebugMsg( const char * pszMsg, SCACHE * pSCache, - SCACHE_USE * pUse - ); + SCACHE_USE * pUse); FSTATIC void _ScaDbgUseForThread( SCACHE * pSCache, @@ -123,8 +116,7 @@ FSTATIC void ScaSavePrevBlkAddress( FSTATIC RCODE ScaAllocBlocksArray( FFILE * pFile, FLMUINT uiNewSize, - FLMBOOL bOneArray - ); + FLMBOOL bOneArray); FSTATIC RCODE ScaFlushLogBlocks( DB_STATS * pDbStats, @@ -188,6 +180,96 @@ FSTATIC RCODE scaFinishCheckpoint( FLMUINT uiCPStartTime, FLMUINT uiTotalToWrite); +FSTATIC RCODE ScaReadIntoCache( + FDB * pDb, + FLMUINT uiBlkType, + LFILE * pLFile, + FLMUINT uiBlkAddress, + SCACHE * pPrevInVerList, + SCACHE * pNextInVerList, + SCACHE ** ppSCacheRV, + FLMBOOL * pbGotFromDisk + ); + +FSTATIC void scaSort( + SCACHE ** ppSCacheTbl, + FLMUINT uiLowerBounds, + FLMUINT uiUpperBounds); + +FSTATIC RCODE ScaWriteContiguousBlocks( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + F_IOBuffer * pIOBuffer, + FLMUINT uiBlkAddress, + FLMBOOL bDoAsync); + +FSTATIC RCODE scaWriteSortedBlocks( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMUINT uiMaxDirtyCache, + FLMUINT * puiDirtyCacheLeft, + FLMBOOL * pbForceCheckpoint, + FLMBOOL bIsCPThread, + FLMBOOL bDoAsync, + FLMUINT uiNumSortedBlocks, + FLMBOOL * pbWroteAll); + +FSTATIC RCODE ScaFlushDirtyBlocks( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMUINT uiMaxDirtyCache, + FLMBOOL bForceCheckpoint, + FLMBOOL bIsCPThread, + FLMBOOL * pbWroteAll); + +FSTATIC RCODE ScaReduceNewBlocks( + DB_STATS * pDbStats, + F_SuperFileHdl * pSFileHdl, + FFILE * pFile, + FLMUINT * puiBlocksFlushed); + +FSTATIC void scaSetBlkDirty( + FFILE * pFile, + SCACHE * pSCache); + +FSTATIC FLMUINT ScaNumHashBuckets( + FLMUINT uiMaxSharedCache + ); + +FSTATIC RCODE ScaInitHashTbl( + FLMUINT uiNumBuckets + ); + +#ifdef SCACHE_LINK_CHECKING + FSTATIC void scaVerifyCache( + SCACHE * pSCache, + int iPlace); + + FSTATIC void scaVerify( + int iPlace); +#else + + #define scaVerifyCache(pSCache,iPlace) + #define scaVerify(iPlace) + +#endif + +FSTATIC void scaReduceFreeCache( + FLMBOOL bFreeAll); + +FSTATIC void scaReduceReuseList( void); + +#ifdef FLM_DEBUG +FSTATIC FLMUINT ScaComputeChecksum( + SCACHE * pSCache); + +FSTATIC void ScaVerifyChecksum( + SCACHE * pSCache); +#endif + FLMBOOL ScaNeededByReadTrans( FFILE * pFile, SCACHE * pSCache); @@ -218,6 +300,34 @@ FSTATIC void ScaRelocate( void * pvOldAlloc, void * pvNewAlloc); +#ifdef FLM_DEBUG + + FSTATIC void ScaDbgUseForThread( + SCACHE * pSCache, + FLMUINT * puiThreadId); + + FSTATIC void ScaDbgReleaseForThread( + SCACHE * pSCache); + + #define ScaUseForThread ScaDbgUseForThread + #define ScaReleaseForThread ScaDbgReleaseForThread + +#else + + #define ScaUseForThread ScaNonDbgUseForThread + #define ScaReleaseForThread ScaNonDbgReleaseForThread + +#endif + +/*************************************************************************** +Desc: +*****************************************************************************/ +FINLINE FLMUINT SCA_MEM_SIZE( + SCACHE * pSCache) +{ + return( sizeof( SCACHE) + pSCache->ui16BlkSize); +} + /*************************************************************************** Desc: Compare two cache blocks to determine which one has lower address. *****************************************************************************/ @@ -657,115 +767,6 @@ FINLINE FLMBOOL scaIsCacheOverLimit( void) return( FALSE); } -#ifdef FLM_DEBUG - - FSTATIC void ScaDbgUseForThread( - SCACHE * pSCache, - FLMUINT * puiThreadId); - - FSTATIC void ScaDbgReleaseForThread( - SCACHE * pSCache); - - #define ScaUseForThread ScaDbgUseForThread - #define ScaReleaseForThread ScaDbgReleaseForThread - -#else - - #define ScaUseForThread ScaNonDbgUseForThread - #define ScaReleaseForThread ScaNonDbgReleaseForThread - -#endif - -FSTATIC RCODE ScaReadIntoCache( - FDB * pDb, - FLMUINT uiBlkType, - LFILE * pLFile, - FLMUINT uiBlkAddress, - SCACHE * pPrevInVerList, - SCACHE * pNextInVerList, - SCACHE ** ppSCacheRV, - FLMBOOL * pbGotFromDisk - ); - -FSTATIC void scaSort( - SCACHE ** ppSCacheTbl, - FLMUINT uiLowerBounds, - FLMUINT uiUpperBounds); - -FSTATIC RCODE ScaWriteContiguousBlocks( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - F_IOBuffer * pIOBuffer, - FLMUINT uiBlkAddress, - FLMBOOL bDoAsync); - -FSTATIC RCODE scaWriteSortedBlocks( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMUINT uiMaxDirtyCache, - FLMUINT * puiDirtyCacheLeft, - FLMBOOL * pbForceCheckpoint, - FLMBOOL bIsCPThread, - FLMBOOL bDoAsync, - FLMUINT uiNumSortedBlocks, - FLMBOOL * pbWroteAll); - -FSTATIC RCODE ScaFlushDirtyBlocks( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMUINT uiMaxDirtyCache, - FLMBOOL bForceCheckpoint, - FLMBOOL bIsCPThread, - FLMBOOL * pbWroteAll); - -FSTATIC RCODE ScaReduceNewBlocks( - DB_STATS * pDbStats, - F_SuperFileHdl * pSFileHdl, - FFILE * pFile, - FLMUINT * puiBlocksFlushed); - -FSTATIC void scaSetBlkDirty( - FFILE * pFile, - SCACHE * pSCache); - -FSTATIC FLMUINT ScaNumHashBuckets( - FLMUINT uiMaxSharedCache - ); - -FSTATIC RCODE ScaInitHashTbl( - FLMUINT uiNumBuckets - ); - -#ifdef SCACHE_LINK_CHECKING - FSTATIC void scaVerifyCache( - SCACHE * pSCache, - int iPlace); - - FSTATIC void scaVerify( - int iPlace); -#else - - #define scaVerifyCache(pSCache,iPlace) - #define scaVerify(iPlace) - -#endif - -FSTATIC void scaReduceFreeCache( - FLMBOOL bFreeAll); - -FSTATIC void scaReduceReuseList( void); - -#ifdef FLM_DEBUG - FSTATIC FLMUINT ScaComputeChecksum( - SCACHE * pSCache); - - FSTATIC void ScaVerifyChecksum( - SCACHE * pSCache); -#endif - /**************************************************************************** Desc: Unlinks a cache block from the replace list NOTE: This function assumes that the global mutex is locked. @@ -1542,11 +1543,9 @@ FSTATIC void ScaUnlinkCache( "UNLINK"); #endif - /* - If cache block has no previous versions linked to it, it - is in the hash bucket and needs to be unlinked from it. - Otherwise, it only needs to be unlinked from the version list. - */ + // If cache block has no previous versions linked to it, it + // is in the hash bucket and needs to be unlinked from it. + // Otherwise, it only needs to be unlinked from the version list. if (pSCache->pFile) { @@ -3505,6 +3504,7 @@ FSTATIC RCODE ScaReadTheBlock( // need to decrypt it before we can use it. // The function ScaDecryptBlock will check if the index // is encrypted first. If not, it will return. + if (pLFile && pLFile->uiLfType == LF_INDEX) { if (RC_BAD( rc = ScaDecryptBlock( pDb->pFile, pucBlk))) @@ -3921,9 +3921,8 @@ FSTATIC RCODE ScaReadBlock( pTmpReadStats = NULL; } - // Read in the block from the database - - // Stay in a loop reading until we get an error or get the block + // Read in the block from the database. Stay in a loop reading until + // we get an error or get the block for (;;) { @@ -3938,8 +3937,8 @@ FSTATIC RCODE ScaReadBlock( // Read and verify the block. - if (RC_BAD( rc = ScaReadTheBlock( pDb, pLFile, pTmpReadStats, pucBlk, uiFilePos, - uiBlkAddress))) + if (RC_BAD( rc = ScaReadTheBlock( pDb, pLFile, pTmpReadStats, pucBlk, + uiFilePos, uiBlkAddress))) { goto Exit; } @@ -5017,7 +5016,6 @@ FSTATIC RCODE ScaWriteContiguousBlocks( pucWriteBuffer = pIOBuffer->getBuffer(); -#if defined( FLM_NLM) || defined( FLM_WIN) if (!bDoAsync) { pAsyncBuffer = NULL; @@ -5026,10 +5024,6 @@ FSTATIC RCODE ScaWriteContiguousBlocks( { pAsyncBuffer = pIOBuffer; } -#else - pAsyncBuffer = NULL; - F_UNREFERENCED_PARM( bDoAsync); -#endif // Determine how many bytes to write @@ -5356,11 +5350,13 @@ Add_Contiguous_Block: flmAssert( uiCopyLen >= BH_OVHD && uiCopyLen <= uiBlockSize); f_memcpy( pucBuffer, pSCache->pucBlk, uiCopyLen); - // If this is an encrypted block, see that - // it gets encrypted. - if (BH_GET_TYPE( pSCache->pucBlk) != BHT_FREE && pSCache->pucBlk[ BH_ENCRYPTED]) + // If this is an encrypted block, see that it gets encrypted. + + if (BH_GET_TYPE( pSCache->pucBlk) != BHT_FREE && + pSCache->pucBlk[ BH_ENCRYPTED]) { // Encrypt the block? Will check the IXD + if (RC_BAD( rc = ScaEncryptBlock( pSCache->pFile, pucBuffer, uiCopyLen, @@ -6779,7 +6775,7 @@ RCODE ScaLogPhysBlk( } pDb->bHadUpdOper = TRUE; - if( uiDbVersion >= FLM_VER_4_3) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { // See if the transaction ID is greater than the last backup // transaction ID. If so, we need to update our block change @@ -7008,8 +7004,7 @@ Desc: This routine calculates the number of hash buckets to use based on the maximum amount of cache we want utilized. ****************************************************************************/ FSTATIC FLMUINT ScaNumHashBuckets( - FLMUINT uiMaxSharedCache - ) + FLMUINT uiMaxSharedCache) { FLMUINT uiNumBuckets; FLMUINT uiCeiling; @@ -7061,8 +7056,7 @@ Exit: Desc: This routine initializes the hash table for shared cache. ****************************************************************************/ FSTATIC RCODE ScaInitHashTbl( - FLMUINT uiNumBuckets - ) + FLMUINT uiNumBuckets) { RCODE rc = FERR_OK; FLMUINT uiAllocSize; @@ -7597,8 +7591,7 @@ Desc: This routine computes an in-memory checksum on a cache block. This ****************************************************************************/ #ifdef FLM_DEBUG FSTATIC FLMUINT ScaComputeChecksum( - SCACHE * pSCache - ) + SCACHE * pSCache) { FLMUINT uiChecksum = 0; @@ -8166,7 +8159,7 @@ FSTATIC RCODE scaFinishCheckpoint( if (bDoTruncate) { if (RC_BAD( rc = pSFileHdl->TruncateFile( - (FLMUINT)FB2UD( &pucCommittedLogHdr [LOG_LOGICAL_EOF])))) + (FLMUINT)FB2UD( &pucCommittedLogHdr [LOG_LOGICAL_EOF])))) { goto Exit; } @@ -8595,35 +8588,33 @@ RCODE ScaEncryptBlock( if (uiEncLen == 0) { - // return FERR_OK. Nothing to do since we don't encrypt the header. goto Exit; } uiIxNum = FB2UW( &pucBuffer[ BH_LOG_FILE_NUM]); - // Get the index. - if (RC_BAD( rc = fdictGetIndex( pFile->pDictList, - pFile->bInLimitedMode, - uiIxNum, - NULL, - &pIxd, - TRUE))) + // Get the index + + if (RC_BAD( rc = fdictGetIndex( pFile->pDictList, pFile->bInLimitedMode, + uiIxNum, NULL, &pIxd, TRUE))) { - // Not an index. + // Not an index + if (rc == FERR_BAD_IX) { rc = FERR_OK; } + goto Exit; } - // The index may not be encrypted. - // We can just exit here. + // The index may not be encrypted. We can just exit here. + if (!pIxd || !pIxd->uiEncId) { flmAssert( pucBuffer[ BH_ENCRYPTED] == 0); pucBuffer[ BH_ENCRYPTED] = 0; - goto Exit; // FERR_OK; + goto Exit; } flmAssert(pucBuffer[ BH_ENCRYPTED]); @@ -8641,18 +8632,17 @@ RCODE ScaEncryptBlock( goto Exit; } - - // Need to get the encryption object. + // Need to get the encryption object + pCcs = (F_CCS *)pFile->pDictList->pIttTbl[ pIxd->uiEncId].pvItem; flmAssert( pCcs); flmAssert( !(uiEncLen % 16)); - // Encrypt the buffer in place. + // Encrypt the buffer in place + if (RC_BAD( rc = pCcs->encryptToStore( &pucBuffer[ BH_OVHD], - uiEncLen, - &pucBuffer[ BH_OVHD], - &uiEncLen))) + uiEncLen, &pucBuffer[ BH_OVHD], &uiEncLen))) { goto Exit; } @@ -8660,6 +8650,7 @@ RCODE ScaEncryptBlock( flmAssert( uiEncLen == uiBufLen - BH_OVHD); // Fill the rest of the buffer with random data. + if (uiBufLen < uiBlockSize) { FLMUINT uiContext; @@ -8670,9 +8661,8 @@ RCODE ScaEncryptBlock( goto Exit; } - if (CCS_GetRandom(uiContext, - &pucBuffer[uiBufLen], - uiBlockSize - uiBufLen) != 0) + if (CCS_GetRandom( uiContext, &pucBuffer[uiBufLen], + uiBlockSize - uiBufLen) != 0) { rc = RC_SET( FERR_NICI_BAD_RANDOM); goto Exit; @@ -8693,8 +8683,7 @@ Desc: This function will decrypt the block of data passed in. ****************************************************************************/ RCODE ScaDecryptBlock( FFILE * pFile, - FLMBYTE * pucBuffer - ) + FLMBYTE * pucBuffer) { RCODE rc = FERR_OK; IXD * pIxd; @@ -8710,38 +8699,37 @@ RCODE ScaDecryptBlock( if (!uiEncLen) { - // Nothing to decrypt - goto Exit; // FERR_OK; + goto Exit; } uiIxNum = FB2UW( &pucBuffer[ BH_LOG_FILE_NUM]); - // Get the index. - if (RC_BAD( rc = fdictGetIndex( pFile->pDictList, - pFile->bInLimitedMode, - uiIxNum, - NULL, - &pIxd, - TRUE))) + // Get the index + + if (RC_BAD( rc = fdictGetIndex( pFile->pDictList, pFile->bInLimitedMode, + uiIxNum, NULL, &pIxd, TRUE))) { // Not an index + if (rc == FERR_BAD_IX) { rc = FERR_OK; } + goto Exit; } - // The index may not be encrypted. - // We can just exit here. + // The index may not be encrypted. We can just exit here. + if (!pIxd || !pIxd->uiEncId) { if (pucBuffer[ BH_ENCRYPTED]) { flmAssert(0); } + pucBuffer[ BH_ENCRYPTED] = 0; - goto Exit; // FERR_OK; + goto Exit; } if (!pucBuffer[ BH_ENCRYPTED]) @@ -8749,6 +8737,7 @@ RCODE ScaDecryptBlock( // Block was not encrypted on disk so don't decrypt it. Setting the // BH_ENCRYPTED bit here will ensure we encrypt it next time we write it // out. + flmAssert(0); pucBuffer[ BH_ENCRYPTED] = 1; goto Exit; @@ -8767,14 +8756,13 @@ RCODE ScaDecryptBlock( } // Need to get the encryption object. + pCcs = (F_CCS *)pFile->pDictList->pIttTbl[ pIxd->uiEncId].pvItem; flmAssert( pCcs); if (RC_BAD( rc = pCcs->decryptFromStore( &pucBuffer[ BH_OVHD], - uiEncLen, - &pucBuffer[ BH_OVHD], - &uiEncLen))) + uiEncLen, &pucBuffer[ BH_OVHD], &uiEncLen))) { goto Exit; } diff --git a/flaim/src/translog.cpp b/flaim/src/translog.cpp index adccfea..ccebe08 100644 --- a/flaim/src/translog.cpp +++ b/flaim/src/translog.cpp @@ -27,6 +27,9 @@ FSTATIC void lgWriteComplete( F_IOBuffer * pIOBuffer); +/**************************************************************************** +Desc: +****************************************************************************/ #ifdef FLM_DBG_LOG void scaLogWrite( FLMUINT uiFFileId, @@ -34,8 +37,7 @@ void scaLogWrite( FLMBYTE * pucBlkBuf, FLMUINT uiBufferLen, FLMUINT uiBlockSize, - char * pszEvent - ) + char * pszEvent) { FLMUINT uiOffset = 0; FLMUINT uiBlkAddress; @@ -63,8 +65,7 @@ Desc: This is the callback routine that is called when a disk write is completed. ****************************************************************************/ FSTATIC void lgWriteComplete( - F_IOBuffer * pIOBuffer - ) + F_IOBuffer * pIOBuffer) { #ifdef FLM_DBG_LOG FFILE * pFile = (FFILE *)pIOBuffer->getCompletionCallbackData( 0); @@ -107,7 +108,6 @@ RCODE lgFlushLogBuffer( FLMUINT uiBytesWritten; F_IOBuffer * pAsyncBuffer; -#if defined( FLM_NLM) || defined( FLM_WIN) if (!bDoAsync) { pAsyncBuffer = NULL; @@ -116,10 +116,6 @@ RCODE lgFlushLogBuffer( { pAsyncBuffer = pFile->pCurrLogBuffer; } -#else - pAsyncBuffer = NULL; - F_UNREFERENCED_PARM( bDoAsync); -#endif if (pDbStats) { @@ -144,10 +140,12 @@ RCODE lgFlushLogBuffer( pFile->pCurrLogBuffer->getBuffer(), pFile->pCurrLogBuffer->getBufferSize(), pAsyncBuffer, &uiBytesWritten); + if (!pAsyncBuffer) { pFile->pCurrLogBuffer->notifyComplete( rc); } + pFile->pCurrLogBuffer = NULL; if (RC_BAD( rc)) @@ -158,7 +156,9 @@ RCODE lgFlushLogBuffer( } goto Exit; } + Exit: + pFile->uiCurrLogWriteOffset = 0; pFile->pCurrLogBuffer = NULL; return( rc); @@ -171,14 +171,13 @@ RCODE lgOutputBlock( DB_STATS * pDbStats, F_SuperFileHdl * pSFileHdl, FFILE * pFile, - SCACHE * pLogBlock, // Cached log block. - FLMBYTE * pucBlk, // Pointer to the corresponding modified - // block in cache. This block will be - // modified to the logged version of - // the block - FLMBOOL bDoAsync, // Do asynchronous writes? - FLMUINT * puiLogEofRV // Returns log EOF - ) + SCACHE * pLogBlock, // Cached log block. + FLMBYTE * pucBlk, // Pointer to the corresponding modified + // block in cache. This block will be + // modified to the logged version of + // the block + FLMBOOL bDoAsync, // Do asynchronous writes? + FLMUINT * puiLogEofRV) // Returns log EOF { RCODE rc = FERR_OK; FLMUINT uiFilePos = *puiLogEofRV; @@ -237,8 +236,9 @@ RCODE lgOutputBlock( pFile->uiCurrLogBlkAddr = uiFilePos; // Get a buffer for logging. + // // NOTE: Buffers are not kept by the FFILE's buffer manager, - // so once we are done with this buffer, it will be freed. + // so once we are done with this buffer, it will be freed uiLogBufferSize = MAX_LOG_BUFFER_SIZE; @@ -248,7 +248,7 @@ RCODE lgOutputBlock( &pFile->pCurrLogBuffer, uiLogBufferSize, uiLogBufferSize))) { // If we failed to get a buffer of the requested size, - // reduce the buffer size by half and try again. + // reduce the buffer size by half and try again if( rc == FERR_MEM) { @@ -276,7 +276,7 @@ RCODE lgOutputBlock( // transaction, set the BEFORE IMAGE (BI) flag in the block header // so we will know that this block is a before image block that // needs to be restored when aborting the current update - // transaction. + // transaction if (pLogBlock->ui16Flags & CA_WRITE_TO_LOG) { @@ -284,7 +284,8 @@ RCODE lgOutputBlock( } // If this is an index block, and it is encrypted, we need to encrypt - // it before we calculate the checksum. + // it before we calculate the checksum + if (BH_GET_TYPE( pucLogBlk) != BHT_FREE && pucLogBlk[ BH_ENCRYPTED]) { FLMUINT uiBufLen = getEncryptSize( pucLogBlk); @@ -299,7 +300,8 @@ RCODE lgOutputBlock( goto Exit; } } - // Calculate the block checksum. + + // Calculate the block checksum uiBlkAddress = GET_BH_ADDR( pucLogBlk); BlkCheckSum( pucLogBlk, CHECKSUM_SET, uiBlkAddress, uiBlkSize); @@ -308,7 +310,7 @@ RCODE lgOutputBlock( pFile->uiCurrLogWriteOffset += uiBlkSize; - // If this log buffer is full, write it out. + // If this log buffer is full, write it out if (pFile->uiCurrLogWriteOffset == pFile->pCurrLogBuffer->getBufferSize()) @@ -321,7 +323,7 @@ RCODE lgOutputBlock( } // Save the previous block address into the modified block's - // block header area. Also save the transaction id. + // block header area. Also save the transaction id UD2FBA( (FLMUINT32)uiFilePos, &pucBlk [BH_PREV_BLK_ADDR]); f_memcpy( &pucBlk [BH_PREV_TRANS_ID], &pLogBlock->pucBlk [BH_TRANS_ID], 4); diff --git a/flaim/util/basic_test.cpp b/flaim/util/basic_test.cpp index d839510..989489b 100644 --- a/flaim/util/basic_test.cpp +++ b/flaim/util/basic_test.cpp @@ -33,7 +33,9 @@ FSTATIC const char * gv_pszSampleDictionary = " 1 type text\n" "0 @4@ field Age\n" " 1 type number\n" - "0 @5@ index LastFirst_IX\n" + "0 @5@ field Misc\n" + " 1 type binary\n" + "0 @100@ index LastFirst_IX\n" " 1 language US\n" " 1 key\n" " 2 field 2\n" @@ -45,7 +47,8 @@ FSTATIC const char * gv_pszSampleDictionary = #define LAST_NAME_TAG 2 #define FIRST_NAME_TAG 3 #define AGE_TAG 4 -#define LAST_NAME_FIRST_NAME_IX 5 +#define MISC_TAG 5 +#define LAST_NAME_FIRST_NAME_IX 100 #ifdef FLM_NLM #define DB_NAME_STR "SYS:\\SAMPLE.DB" @@ -93,6 +96,8 @@ public: RCODE addRecordTest( FLMUINT * puiDrn); + RCODE largeFieldTest( void); + RCODE modifyRecordTest( FLMUINT uiDrn); @@ -684,12 +689,153 @@ Exit: return( rc); } +/*************************************************************************** +Desc: +****************************************************************************/ +RCODE IFlmTestImpl::largeFieldTest( void) +{ + RCODE rc = FERR_OK; + FLMBYTE * pucValue = NULL; + FlmRecord * pRec = NULL; + void * pvField; + FLMUINT uiDrn; + FLMUINT uiValueSize; + FLMUINT uiLoop; + f_randomGenerator randGen; + FLM_MEM_INFO memInfo; + FLMBOOL bTransActive = FALSE; + FLMBOOL bPassed = FALSE; + + beginTest( "Large Field Test"); + + // Generate a large binary value + + uiValueSize = 1024 * 1024; + if( RC_BAD( rc = f_alloc( uiValueSize, &pucValue))) + { + goto Exit; + } + + f_randomize( &randGen); + + for( uiLoop = 0; uiLoop < uiValueSize; uiLoop++) + { + pucValue[ uiLoop] = (FLMBYTE)f_randomLong( &randGen); + } + + // Create a record object + + if( (pRec = new FlmRecord) == NULL) + { + rc = RC_SET( FERR_MEM); + MAKE_ERROR_STRING( "allocating FlmRecord", rc, m_szFailInfo); + goto Exit; + } + + // Populate the record object with fields and values + + if( RC_BAD( rc = pRec->insertLast( 0, MISC_TAG, + FLM_BINARY_TYPE, &pvField))) + { + MAKE_ERROR_STRING( "calling insertLast", rc, m_szFailInfo); + goto Exit; + } + + if( RC_BAD( rc = pRec->setBinary( pvField, pucValue, uiValueSize))) + { + MAKE_ERROR_STRING( "calling setBinary", rc, m_szFailInfo); + goto Exit; + } + + // Start an update transaction + + if( RC_BAD( rc = FlmDbTransBegin( m_hDb, FLM_UPDATE_TRANS, 15))) + { + MAKE_ERROR_STRING( "calling FlmDbTransBegin", rc, m_szFailInfo); + goto Exit; + } + bTransActive = TRUE; + + // Add the record to the database. + + uiDrn = 0; + if( RC_BAD( rc = FlmRecordAdd( m_hDb, FLM_DATA_CONTAINER, + &uiDrn, pRec, 0))) + { + MAKE_ERROR_STRING( "calling FlmRecordAdd", rc, m_szFailInfo); + goto Exit; + } + + // Commit the transaction + + if( RC_BAD( rc = FlmDbTransCommit( m_hDb))) + { + MAKE_ERROR_STRING( "calling FlmDbTransCommit", rc, m_szFailInfo); + goto Exit; + } + + // Clear cache + + FlmGetMemoryInfo( &memInfo); + FlmConfig( FLM_CACHE_LIMIT, 0, 0); + FlmConfig( FLM_CACHE_LIMIT, + (void *)(memInfo.RecordCache.uiMaxBytes + memInfo.BlockCache.uiMaxBytes), 0); + + // Make sure the record was removed from cache + + if( pRec->isCached()) + { + rc = RC_SET( FERR_FAILURE); + MAKE_ERROR_STRING( "Record is still cached", rc, m_szFailInfo); + goto Exit; + } + + pRec->Release(); + pRec = NULL; + + if (RC_BAD( rc = FlmRecordRetrieve( m_hDb, FLM_DATA_CONTAINER, uiDrn, + FO_EXACT, &pRec, &uiDrn))) + { + MAKE_ERROR_STRING( "calling FlmRecordRetrieve", rc, m_szFailInfo); + goto Exit; + } + + if( f_memcmp( pucValue, pRec->getDataPtr( pRec->root()), uiValueSize) != 0) + { + rc = RC_SET( FERR_FAILURE); + MAKE_ERROR_STRING( "Data value did not match.", rc, m_szFailInfo); + goto Exit; + } + + bTransActive = FALSE; + bPassed = TRUE; + +Exit: + + if( bTransActive) + { + (void)FlmDbTransAbort( m_hDb); + } + + if( pRec) + { + pRec->Release(); + } + + if( pucValue) + { + f_free( &pucValue); + } + + endTest( bPassed); + return( rc); +} + /*************************************************************************** Desc: ****************************************************************************/ RCODE IFlmTestImpl::modifyRecordTest( - FLMUINT uiDrn - ) + FLMUINT uiDrn) { RCODE rc = FERR_OK; FlmRecord * pRec = NULL; @@ -3436,6 +3582,13 @@ RCODE IFlmTestImpl::execute( void) goto Exit; } + // Large field test + + if (RC_BAD( rc = largeFieldTest())) + { + goto Exit; + } + // Retrieve record and query tests if (RC_BAD( rc = queryRecordTest())) diff --git a/flaim/util/dbshell.cpp b/flaim/util/dbshell.cpp index a3086e0..5279fe6 100644 --- a/flaim/util/dbshell.cpp +++ b/flaim/util/dbshell.cpp @@ -4393,7 +4393,7 @@ FLMINT FlmEditCommand::execute( f_sprintf( szTitle, "Database Edit for FLAIM [DB=%s/BUILD=%s]", - FLM_CURRENT_VER_STR, __DATE__); + FLM_CUR_FILE_FORMAT_VER_STR, __DATE__); if( FTXScreenInit( gv_pFtxInfo, szTitle, &pScreen) != FTXRC_SUCCESS) { diff --git a/flaim/util/rebuild.cpp b/flaim/util/rebuild.cpp index 579816e..2ea3b47 100644 --- a/flaim/util/rebuild.cpp +++ b/flaim/util/rebuild.cpp @@ -563,7 +563,7 @@ FSTATIC FLMBOOL bldGetParams( gv_DefaultCreateOpts.bKeepRflFiles = DEFAULT_KEEP_RFL_FILES_FLAG; gv_DefaultCreateOpts.bLogAbortedTransToRfl = DEFAULT_LOG_ABORTED_TRANS_FLAG; gv_DefaultCreateOpts.uiDefaultLanguage = DEFAULT_LANG; - gv_DefaultCreateOpts.uiVersionNum = FLM_CURRENT_VERSION_NUM; + gv_DefaultCreateOpts.uiVersionNum = FLM_CUR_FILE_FORMAT_VER_NUM; gv_DefaultCreateOpts.uiAppMajorVer = gv_DefaultCreateOpts.uiAppMinorVer = 0; gv_uiCacheSize = 30000; diff --git a/flaim/util/view.cpp b/flaim/util/view.cpp index 28f0b9e..bb2bc8d 100644 --- a/flaim/util/view.cpp +++ b/flaim/util/view.cpp @@ -508,13 +508,13 @@ FSTATIC RCODE ViewReadAndVerifyHdrInfo( uiTmpLen); gv_szFlaimName [uiTmpLen] = 0; - uiTmpLen = FLM_VER_LEN; + uiTmpLen = FLM_FILE_FORMAT_VER_LEN; if (uiTmpLen > sizeof( gv_szFlaimVersion) - 1) { uiTmpLen = sizeof( gv_szFlaimVersion) - 1; } f_memcpy( gv_szFlaimVersion, - &pReadBuf [FLAIM_HEADER_START + FLM_VER_POS], uiTmpLen); + &pReadBuf [FLAIM_HEADER_START + FLM_FILE_FORMAT_VER_POS], uiTmpLen); gv_szFlaimVersion [uiTmpLen] = 0; /* diff --git a/flaim/util/viewblk.cpp b/flaim/util/viewblk.cpp index 97aec8c..642ba2a 100644 --- a/flaim/util/viewblk.cpp +++ b/flaim/util/viewblk.cpp @@ -23,7 +23,6 @@ //------------------------------------------------------------------------- #include "view.h" -#include "fddpcode.h" FSTATIC void InitStatusBits( FLMBYTE * StatusBytes diff --git a/flaim/util/viewfhdr.cpp b/flaim/util/viewfhdr.cpp index 0a3f299..c38ef48 100644 --- a/flaim/util/viewfhdr.cpp +++ b/flaim/util/viewfhdr.cpp @@ -91,7 +91,8 @@ FSTATIC FLMINT ViewSetupFileHeaderMenu( if (!ViewAddMenuItem( LBL_FLAIM_VERSION, LABEL_WIDTH, VAL_IS_TEXT_PTR, (FLMUINT)((FLMBYTE *)(&gv_szFlaimVersion[ 0])), 0, - 0, FLAIM_HEADER_START + FLM_VER_POS, FLM_VER_LEN, MOD_TEXT, + 0, FLAIM_HEADER_START + FLM_FILE_FORMAT_VER_POS, + FLM_FILE_FORMAT_VER_LEN, MOD_TEXT, Col, Row++, 0, bc, fc, bc, fc)) goto Zero_Exit; @@ -133,7 +134,7 @@ FSTATIC FLMINT ViewSetupFileHeaderMenu( /* Display the first PCODE block address */ - if (gv_ViewHdrInfo.FileHdr.uiVersionNum < FLM_VER_4_3) + if (gv_ViewHdrInfo.FileHdr.uiVersionNum < FLM_FILE_FORMAT_VER_4_3) { if (!ViewAddMenuItem( LBL_FIRST_PCODE_BLOCK_ADDRESS, LABEL_WIDTH, VAL_IS_NUMBER | DISP_HEX_DECIMAL, diff --git a/flaim/util/viewlfil.cpp b/flaim/util/viewlfil.cpp index b48cb3b..7ade4cb 100644 --- a/flaim/util/viewlfil.cpp +++ b/flaim/util/viewlfil.cpp @@ -23,7 +23,6 @@ //------------------------------------------------------------------------- #include "view.h" -#include "fddpcode.h" FSTATIC FLMINT ViewOutputLFH2_0( FLMUINT Col, diff --git a/flaim/util/viewlhdr.cpp b/flaim/util/viewlhdr.cpp index 36e63ec..0ca7f1c 100644 --- a/flaim/util/viewlhdr.cpp +++ b/flaim/util/viewlhdr.cpp @@ -203,7 +203,7 @@ FSTATIC FLMINT ViewSetupLogHeaderMenu( /* Display the maximum roll-forward log file size. */ - if( uiDbVersion >= FLM_VER_4_3) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { if (!ViewAddMenuItem( LBL_RFL_MAX_FILE_SIZE, LABEL_WIDTH, VAL_IS_NUMBER | DISP_DECIMAL_HEX, @@ -227,7 +227,7 @@ FSTATIC FLMINT ViewSetupLogHeaderMenu( Col, Row++, 0, bc, fc, bc, fc)) return( 0); - if (uiDbVersion >= FLM_VER_4_3) + if (uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { /* Display the auto turn off aborted transactions flag. */ @@ -268,7 +268,7 @@ FSTATIC FLMINT ViewSetupLogHeaderMenu( /* Display the last committed transaction ID */ - if( uiDbVersion >= FLM_VER_4_31) + if( uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { if (!ViewAddMenuItem( LBL_LAST_RFL_COMMIT_ID, LABEL_WIDTH, VAL_IS_NUMBER | DISP_DECIMAL, @@ -389,7 +389,7 @@ FSTATIC FLMINT ViewSetupLogHeaderMenu( Col, Row++, 0, bc, fc, bc, fc)) return( 0); - if (uiDbVersion >= FLM_VER_4_3) + if (uiDbVersion >= FLM_FILE_FORMAT_VER_4_3) { FLMBYTE ucBuf[ 64]; diff --git a/flaim/util/viewsrch.cpp b/flaim/util/viewsrch.cpp index dde8532..d44f227 100644 --- a/flaim/util/viewsrch.cpp +++ b/flaim/util/viewsrch.cpp @@ -23,7 +23,6 @@ //------------------------------------------------------------------------- #include "view.h" -#include "fddpcode.h" /******************************************************************** Desc: ?