/***************************************************************************** * * * BTKEY.C * * * * Copyright (C) Microsoft Corporation 1989 - 1994. * * All Rights reserved. * * * ****************************************************************************** * * * Module Intent * * * * Functions to deal with (i.e. size, compare) keys of all types. * * * ****************************************************************************** * * * Current Owner: BinhN * * * *****************************************************************************/ /***************************************************************************** * * Revision History: Created 05/11/89 by JohnSc * * 08/21/90 JohnSc autodocified * 3/05/97 erinfox Change errors to HRESULTS * *****************************************************************************/ static char s_aszModule[] = __FILE__; /* For error report */ #include #include #include #include #include #include #include #include #include "common.h" #include <_mvutil.h> // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // When ligature tables are implemented again, take this out !!!!!!!!!! //#define NOCHARTABLES_FIXME // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! /***************************************************************************** * * * Macros * * * *****************************************************************************/ #define StCopy(st1, st2) (ST)QVCOPY((st1), (st2), (LONG)*(st2)) #define CbLenSt(st) ((WORD)*(st)) /*************************************************************************** * * @doc INTERNAL * * @func SHORT PASCAL FAR | WCmpKey | * Compare two keys. * * @parm KEY | key1 | * the UNCOMPRESSED keys to compare * * @parm KEY | key2 | * the UNCOMPRESSED keys to compare * * @parm QBTHR | qbthr | * qbthr->bth.rgchFormat[0] - key type * [qbthr->??? - other info ???] * * @rdesc -1 if key1 < key2; 0 if key1 == key2; 1 if key1 > key2 * args OUT: [if comparing compressed keys, change state in qbthr->???] * * @comm Might be best to have this routine assume keys are expanded * and do something else to compare keys in the scan routines. * We're assuming fixed length keys are SZs. Alternative * would be to use a memcmp() function. * ***************************************************************************/ PUBLIC SHORT PASCAL FAR WCmpKey(KEY key1, KEY key2, QBTHR qbthr) { SHORT w; LONG l; KT kt = (KT)qbthr->bth.rgchFormat[ 0 ]; LONG l1, l2; switch (kt) { #ifdef FULL_BTREE // { case KT_VSTI: { SZ sz1, sz2; WORD wl1,wl2; BYTE far *qbLigatures = NULL; wl1=(WORD)FoFromSz((SZ)key1).dwOffset; sz1 = (SZ)key1; ADVANCE_FO(sz1); key1 = (KEY)sz1; wl2=(WORD)FoFromSz((SZ)key2).dwOffset; sz2 = (SZ)key2; ADVANCE_FO(sz2); key2 = (KEY)sz2; if (qbthr->lrglpCharTab) qbLigatures=(BYTE FAR *)((LPCHARTAB)*qbthr->lrglpCharTab)->lpLigature; w=WCmpiSnn((SZ)key1, (SZ)key2, qbLigatures , wl1, wl2); break; } case KT_SZDEL: // assume keys have been expanded for delta codeds case KT_SZDELMIN: case KT_SZ: case KT_SZMIN: case '1': case '2': case '3': case '4': case '5': // assume null term case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': w = STRCMP((char *)key1, (char *)key2); break; case KT_SZI: w = WCmpiSz((SZ)key1, (SZ)key2, (BYTE FAR *)((LPCHARTAB)*qbthr->lrglpCharTab)->lpLigature); break; case KT_SZISCAND: w = WCmpiScandSz((SZ)key1, (SZ)key2); break; case KT_SZMAP: #ifdef NOCHARTABLES_FIXME w=STRCMP((SZ)key1, (SZ)key2); #else if (PRIMARYLANGID(LANGIDFROMLCID(qbthr->bth.lcid)) == LANG_JAPANESE) w = StringJCompare (0L, (SZ)key1, STRLEN((char *)key1), (SZ)key2, STRLEN((char *)key2)); else w = StrFntMappedLigatureComp((SZ)key1, (SZ)key2, qbthr->lrglpCharTab); #endif break; #endif // } case KT_EXTSORT: if (qbthr->pITSortKey == NULL || FAILED(qbthr->pITSortKey->Compare((LPCVOID) key1, (LPCVOID) key2, &l, NULL))) { l = 0; ITASSERT(FALSE); } // Reduce the long -/0/+ result to a word -/0/+. w = (SHORT) ((LOWORD(l) & 0x7fff) | ((LOWORD(l) >> 1) & 0x7fff) | HIWORD(l)); break; #ifdef FULL_BTREE // { case KT_ST: case KT_STMIN: case KT_STDEL: case KT_STDELMIN: w = WCmpSt((ST)key1, (ST)key2); break; #endif // } case KT_LONG: l1 = *(LONG FAR *)key1; l2 = *(LONG FAR *)key2; if (l1 < l2) w = -1; else if (l2 < l1) w = 1; else w = 0; break; } return w; } /*************************************************************************** * * @doc INTERNAL * * @func SHORT PASCAL FAR | CbSizeKey | * Return the key size (compressed or un-) in bytes * * @parm KEY | key * @parm QBTHR | qbthr * @parm BOOL | fCompressed | * TRUE to get the compressed size, * FALSE to get the uncompressed size. * * @rdesc size of the key in bytes * * @comm It's impossible to tell how much suffix was discarded for * the KT_*MIN key types. * ***************************************************************************/ PUBLIC SHORT PASCAL CbSizeKey(KEY key, QBTHR qbthr, BOOL fCompressed) { SHORT cb; DWORD dwKeySize; KT kt = (KT)qbthr->bth.rgchFormat[ 0 ]; switch(kt) { #ifdef FULL_BTREE // { case KT_SZ: case KT_SZMIN: case KT_SZI: case KT_SZISCAND: case KT_SZMAP: cb = STRLEN((char *)key) + 1; break; case KT_VSTI: cb = (SHORT)LenSzFo((LPBYTE)key) + (SHORT)FoFromSz((LPBYTE)key).dwOffset; break; case KT_SZDEL: case KT_SZDELMIN: if (fCompressed) cb = 1 + STRLEN((char *)key + 1) + 1; else cb = *(QB)key + STRLEN((char *)key + 1) + 1; break; case KT_ST: case KT_STMIN: case KT_STI: cb = CbLenSt((ST)key) + 1/* ? */; break; case KT_STDEL: case KT_STDELMIN: if (fCompressed) cb = 1 + CbLenSt((ST)key + 1); else cb = *(QB)key + CbLenSt((ST)key + 1) + 1; break; #endif // } case KT_EXTSORT: if (qbthr->pITSortKey == NULL || FAILED(qbthr->pITSortKey->GetSize((LPCVOID) key, &dwKeySize))) { dwKeySize = 0; ITASSERT(FALSE); } // Key size can't exceed 32K - 1. Such a key never should have been // allowed in to begin with. We'll assert for the debug version. // We'll use 32K - 1 for the size for now, but there's a pretty // good chance a GP fault will occur if the sort object // ever has to visit parts of the key at 32K and beyond! if (dwKeySize <= 0x7fff) cb = (SHORT) dwKeySize; else { cb = 0x7fff; ITASSERT(FALSE); } break; case KT_LONG: cb = sizeof(LONG); break; case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': cb = kt - '0'; break; case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': cb = kt - 'a' + 10; break; } return cb; } /*************************************************************************** * * @doc INTERNAL * * @func BOOL FAR PASCAL | FIsPrefix | * Determines whether string key1 is a prefix of key2. * * @parm HBT | hbt | * handle to a btree with string keys * * @parm KEY | key1 | * Uncompressed key * * @parm KEY | key2 | * Uncompressed key * * @rdesc TRUE if the string key1 is a prefix of the string key2 * FALSE if it isn't or if hbt doesn't contain string keys * * @comm Bugs: Doesn't work on STs yet * * Method: temporarily shortens the second string so it can * compare prefixes * ***************************************************************************/ PUBLIC BOOL FAR PASCAL FIsPrefix(HBT hbt, KEY key1, KEY key2) { QBTHR qbthr; KT kt; BOOL f; ERRB errb; HRESULT hr; #ifdef FULL_BTREE SHORT cb1, cb2; unsigned char c; #endif if ((qbthr = (QBTHR) _GLOBALLOCK(hbt)) == NULL) { SetErrCode (&errb, E_INVALIDARG); return(FALSE); } assert(qbthr != NULL); kt = (KT)qbthr->bth.rgchFormat[ 0 ]; switch(kt) { #ifdef FULL_BTREE // { case KT_SZ: case KT_SZMIN: case KT_SZI: case KT_SZISCAND: case KT_SZDEL: case KT_SZDELMIN: case KT_SZMAP: /* both keys assumed to have been decompressed */ cb1 = STRLEN((char *)key1); cb2 = STRLEN((char *)key2); break; case KT_ST: case KT_STMIN: case KT_STI: case KT_STDEL: case KT_STDELMIN: /* STs unimplemented */ SetErrCode (&errb, E_NOTSUPPORTED); _GLOBALUNLOCK(hbt); return FALSE; break; #endif // } case KT_EXTSORT: if (qbthr->pITSortKey == NULL || FAILED(hr = qbthr->pITSortKey->IsRelated((LPCVOID) key1, (LPCVOID) key2, (DWORD) IITSK_KEYRELATION_PREFIX, NULL))) { ITASSERT(FALSE); f = FALSE; } else f = (GetScode(hr) == S_OK); _GLOBALUNLOCK(hbt); return (f); break; case KT_LONG: case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': default: /* prefix doesn't make sense */ SetErrCode (&errb, E_NOTSUPPORTED); _GLOBALUNLOCK(hbt); return FALSE; break; } #ifdef FULL_BTREE // { // The length check and truncation method works as long as // ligatures aren't involved. We won't worry about this for // IT 4.0 because the CharTab KTs won't be used. if (cb1 > cb2) { _GLOBALUNLOCK(hbt); return FALSE; } // Truncate longer string (key2). c = ((SZ)key2)[ cb1 ]; ((SZ)key2)[ cb1 ] = '\0'; switch (kt) { case KT_SZ: case KT_SZMIN: case KT_SZDEL: case KT_SZDELMIN: f = STRCMP((char *)key1, (char *)key2) <=0; break; case KT_SZI: f = WCmpiSz((SZ)key1, (SZ)key2, (BYTE FAR *) (*((LPCHARTAB FAR *)qbthr->lrglpCharTab))->lpLigature) <= 0; break; case KT_SZISCAND: f = WCmpiScandSz((SZ)key1, (SZ)key2) <= 0; break; case KT_SZMAP: #ifdef NOCHARTABLES_FIXME f=(STRCMP((SZ)key1, (SZ)key2) <= 0); #else if (PRIMARYLANGID(LANGIDFROMLCID(qbthr->bth.lcid)) == LANG_JAPANESE) f = (StringJCompare (0L, (SZ)key1, STRLEN((char *)key1), (SZ)key2, STRLEN((char *)key2)) <= 0); else f = (StrFntMappedLigatureComp((SZ)key1, (SZ)key2, qbthr->lrglpCharTab) <= 0); #endif break; default: assert(FALSE); break; } // Restore the longer string. ((SZ)key2)[ cb1 ] = c; _GLOBALUNLOCK(hbt); return f; #endif // } } /* EOF */