Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1439 lines
42 KiB

  1. /*
  2. * MAPI 1.0 property handling routines
  3. *
  4. *
  5. * PROPUTIL.C -
  6. *
  7. * Useful routines for manipulating and comparing property values
  8. */
  9. #include <_apipch.h>
  10. //
  11. //
  12. // WARNING! WARNING! WARNING! 32-bit Intel Specific!
  13. //
  14. //
  15. #define SIZEOF_FLOAT 4
  16. #define SIZEOF_DOUBLE 8
  17. #define SIZEOF_LONG_DOUBLE 8
  18. // Make linker happy.
  19. BOOL _fltused;
  20. //
  21. //
  22. //
  23. //
  24. #define cchBufMax 256
  25. #if defined (_AMD64_) || defined(_IA64_)
  26. #define AlignProp(_cb) Align8(_cb)
  27. #else
  28. #define AlignProp(_cb) (_cb)
  29. #endif
  30. #ifdef OLD_STUFF
  31. //#ifdef OLDSTUFF_DBCS
  32. ULONG ulchStrCount (LPTSTR, ULONG, LANGID);
  33. ULONG ulcbStrCount (LPTSTR, ULONG, LANGID);
  34. //#endif // DBCS
  35. #endif //OLD_STUFF
  36. // $MAC - Mac 68K compiler bug
  37. #ifdef _M_M68K
  38. #pragma optimize( TEXT(""), off)
  39. #endif
  40. /*
  41. - PropCopyMore()
  42. -
  43. *
  44. * Copies a property pointed to by lpSPropValueSrc into the property pointed
  45. * to by lpSPropValueDst. No memory allocation is done unless the property
  46. * is one of the types that do not fit within a SPropValue, eg. STRING8
  47. * For these large properties, memory is allocated using
  48. * the AllocMore function passed as a parameter.
  49. */
  50. STDAPI_(SCODE)
  51. PropCopyMore( LPSPropValue lpSPropValueDst,
  52. LPSPropValue lpSPropValueSrc,
  53. ALLOCATEMORE * lpfAllocateMore,
  54. LPVOID lpvObject )
  55. {
  56. SCODE sc;
  57. ULONG ulcbValue;
  58. LPBYTE lpbValueSrc;
  59. UNALIGNED LPBYTE * lppbValueDst;
  60. // validate parameters
  61. AssertSz( lpSPropValueDst && !IsBadReadPtr( lpSPropValueDst, sizeof( SPropValue ) ),
  62. TEXT("lpSPropValueDst fails address check") );
  63. AssertSz( lpSPropValueSrc && !IsBadReadPtr( lpSPropValueSrc, sizeof( SPropValue ) ),
  64. TEXT("lpSPropValueDst fails address check") );
  65. AssertSz( !lpfAllocateMore || !IsBadCodePtr( (FARPROC)lpfAllocateMore ),
  66. TEXT("lpfAllocateMore fails address check") );
  67. AssertSz( !lpvObject || !IsBadReadPtr( lpvObject, sizeof( LPVOID ) ),
  68. TEXT("lpfAllocateMore fails address check") );
  69. // Copy the part that fits in the SPropValue struct (including the tag).
  70. // This is a little wasteful for complicated properties
  71. // because it copies more than is strictly necessary, but
  72. // it saves time for small properties and saves code in general
  73. MemCopy( (BYTE *) lpSPropValueDst,
  74. (BYTE *) lpSPropValueSrc,
  75. sizeof(SPropValue) );
  76. switch ( PROP_TYPE(lpSPropValueSrc->ulPropTag) )
  77. {
  78. // Types whose values fit in the 64-bit Value of the property
  79. // or whose values aren't anything PropCopyMore can interpret
  80. case PT_UNSPECIFIED:
  81. case PT_NULL:
  82. case PT_OBJECT:
  83. case PT_I2:
  84. case PT_LONG:
  85. case PT_R4:
  86. case PT_DOUBLE:
  87. case PT_CURRENCY:
  88. case PT_ERROR:
  89. case PT_BOOLEAN:
  90. case PT_SYSTIME:
  91. case PT_APPTIME:
  92. case PT_I8:
  93. return SUCCESS_SUCCESS;
  94. case PT_BINARY:
  95. ulcbValue = lpSPropValueSrc->Value.bin.cb;
  96. lpbValueSrc = lpSPropValueSrc->Value.bin.lpb;
  97. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.bin.lpb;
  98. break;
  99. case PT_STRING8:
  100. ulcbValue = (lstrlenA(lpSPropValueSrc->Value.lpszA) + 1) * sizeof(CHAR);
  101. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpszA;
  102. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpszA;
  103. break;
  104. case PT_UNICODE:
  105. ulcbValue = (lstrlenW(lpSPropValueSrc->Value.lpszW) + 1) * sizeof(WCHAR);
  106. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpszW;
  107. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpszW;
  108. break;
  109. case PT_CLSID:
  110. ulcbValue = sizeof(GUID);
  111. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.lpguid;
  112. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.lpguid;
  113. break;
  114. case PT_MV_CLSID:
  115. ulcbValue = lpSPropValueSrc->Value.MVguid.cValues * sizeof(GUID);
  116. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVguid.lpguid;
  117. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVguid.lpguid;
  118. break;
  119. case PT_MV_I2:
  120. ulcbValue = lpSPropValueSrc->Value.MVi.cValues * sizeof(short int);
  121. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVi.lpi;
  122. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVi.lpi;
  123. break;
  124. case PT_MV_LONG:
  125. ulcbValue = lpSPropValueSrc->Value.MVl.cValues * sizeof(LONG);
  126. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVl.lpl;
  127. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVl.lpl;
  128. break;
  129. case PT_MV_R4:
  130. ulcbValue = lpSPropValueSrc->Value.MVflt.cValues * SIZEOF_FLOAT;
  131. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVflt.lpflt;
  132. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVflt.lpflt;
  133. break;
  134. case PT_MV_DOUBLE:
  135. case PT_MV_APPTIME:
  136. ulcbValue = lpSPropValueSrc->Value.MVdbl.cValues * SIZEOF_DOUBLE;
  137. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVdbl.lpdbl;
  138. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVdbl.lpdbl;
  139. break;
  140. case PT_MV_CURRENCY:
  141. ulcbValue = lpSPropValueSrc->Value.MVcur.cValues * sizeof(CURRENCY);
  142. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVcur.lpcur;
  143. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVcur.lpcur;
  144. break;
  145. case PT_MV_SYSTIME:
  146. ulcbValue = lpSPropValueSrc->Value.MVat.cValues * sizeof(FILETIME);
  147. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVat.lpat;
  148. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVat.lpat;
  149. break;
  150. case PT_MV_I8:
  151. ulcbValue = lpSPropValueSrc->Value.MVli.cValues * sizeof(LARGE_INTEGER);
  152. lpbValueSrc = (LPBYTE) lpSPropValueSrc->Value.MVli.lpli;
  153. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVli.lpli;
  154. break;
  155. case PT_MV_BINARY:
  156. {
  157. // Multi-valued binaries are copied in memory into a single
  158. // allocated buffer in the following way:
  159. //
  160. // cb1, pb1 ... cbn, pbn, b1,0, b1,1 ... b2,0 b2,1 ...
  161. //
  162. // The cbn and pbn parameters form the SBinary array that
  163. // will be pointed to by lpSPropValueDst->Value.MVbin.lpbin.
  164. // The remainder of the allocation is used to store the binary
  165. // data for each of the elements of the array. Thus pb1 points
  166. // to the b1,0, etc.
  167. UNALIGNED SBinaryArray * pSBinaryArray = (UNALIGNED SBinaryArray * ) (&lpSPropValueSrc->Value.MVbin);
  168. ULONG uliValue;
  169. UNALIGNED SBinary * pSBinarySrc;
  170. UNALIGNED SBinary * pSBinaryDst;
  171. LPBYTE pbData;
  172. ulcbValue = pSBinaryArray->cValues * sizeof(SBinary);
  173. for ( uliValue = 0, pSBinarySrc = pSBinaryArray->lpbin;
  174. uliValue < pSBinaryArray->cValues;
  175. uliValue++, pSBinarySrc++ )
  176. ulcbValue += AlignProp(pSBinarySrc->cb);
  177. // Allocate a buffer to hold it all
  178. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVbin.lpbin;
  179. sc = (*lpfAllocateMore)( ulcbValue,
  180. lpvObject,
  181. (LPVOID *) lppbValueDst );
  182. if ( sc != SUCCESS_SUCCESS )
  183. {
  184. DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_BINARY property") );
  185. return sc;
  186. }
  187. // And copy it all in
  188. pbData = (LPBYTE) ((LPSBinary) *lppbValueDst + pSBinaryArray->cValues);
  189. for ( uliValue = 0,
  190. pSBinarySrc = pSBinaryArray->lpbin,
  191. pSBinaryDst = (LPSBinary) *lppbValueDst;
  192. uliValue < pSBinaryArray->cValues;
  193. uliValue++, pSBinarySrc++, pSBinaryDst++ )
  194. {
  195. pSBinaryDst->cb = pSBinarySrc->cb;
  196. pSBinaryDst->lpb = pbData;
  197. MemCopy( pbData, pSBinarySrc->lpb, (UINT) pSBinarySrc->cb );
  198. pbData += AlignProp(pSBinarySrc->cb);
  199. }
  200. return SUCCESS_SUCCESS;
  201. }
  202. case PT_MV_STRING8:
  203. {
  204. // Multi-valued STRING8 properties are copied into a single
  205. // allocated block of memory in the following way:
  206. //
  207. // | Allocated buffer |
  208. // |---------------------------------------|
  209. // | pszA1, pszA2 ... | szA1[], szA2[] ... |
  210. // |------------------|--------------------|
  211. // | LPSTR array | String data |
  212. //
  213. // Where pszAn are the elements of the LPSTR array pointed
  214. // to by lpSPropValueDst->Value.MVszA. Each pszAn points
  215. // to its corresponding string, szAn, stored later in the
  216. // buffer. The szAn are stored starting at the first byte
  217. // past the end of the LPSTR array.
  218. UNALIGNED SLPSTRArray * pSLPSTRArray = (UNALIGNED SLPSTRArray *) (&lpSPropValueSrc->Value.MVszA);
  219. ULONG uliValue;
  220. LPSTR * pszASrc;
  221. LPSTR * pszADst;
  222. LPBYTE pbSzA;
  223. ULONG ulcbSzA;
  224. // Figure out the size of the buffer we need
  225. ulcbValue = pSLPSTRArray->cValues * sizeof(LPSTR);
  226. for ( uliValue = 0, pszASrc = pSLPSTRArray->lppszA;
  227. uliValue < pSLPSTRArray->cValues;
  228. uliValue++, pszASrc++ )
  229. ulcbValue += (lstrlenA(*pszASrc) + 1) * sizeof(CHAR);
  230. // Allocate the buffer to hold the strings
  231. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVszA.lppszA;
  232. sc = (*lpfAllocateMore)( ulcbValue,
  233. lpvObject,
  234. (LPVOID *) lppbValueDst );
  235. if ( sc != SUCCESS_SUCCESS )
  236. {
  237. DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_STRING8 property") );
  238. return sc;
  239. }
  240. // Copy the strings into the buffer and set pointers
  241. // to them in the LPSTR array at the beginning of the buffer
  242. for ( uliValue = 0,
  243. pszASrc = pSLPSTRArray->lppszA,
  244. pszADst = (LPSTR *) *lppbValueDst,
  245. pbSzA = (LPBYTE) (pszADst + pSLPSTRArray->cValues);
  246. uliValue < pSLPSTRArray->cValues;
  247. uliValue++, pszASrc++, pszADst++ )
  248. {
  249. ulcbSzA = (lstrlenA(*pszASrc) + 1) * sizeof(CHAR);
  250. *pszADst = (LPSTR) pbSzA;
  251. MemCopy( pbSzA, (LPBYTE) *pszASrc, (UINT) ulcbSzA );
  252. pbSzA += ulcbSzA;
  253. }
  254. return SUCCESS_SUCCESS;
  255. }
  256. case PT_MV_UNICODE:
  257. {
  258. // Multi-valued UNICODE properties are copied into a single
  259. // allocated block of memory in the following way:
  260. //
  261. // | Allocated buffer |
  262. // |---------------------------------------|
  263. // | pszW1, pszW2 ... | szW1[], szW2[] ... |
  264. // |------------------|--------------------|
  265. // | LPWSTR array | String data |
  266. //
  267. // Where pszWn are the elements of the LPWSTR array pointed
  268. // to by lpSPropValueDst->Value.MVszW. Each pszWn points
  269. // to its corresponding string, szWn, stored later in the
  270. // buffer. The szWn are stored starting at the first byte
  271. // past the end of the LPWSTR array.
  272. UNALIGNED SWStringArray * pSWStringArray = (UNALIGNED SWStringArray *) (&lpSPropValueSrc->Value.MVszW);
  273. ULONG uliValue;
  274. UNALIGNED LPWSTR * pszWSrc;
  275. UNALIGNED LPWSTR * pszWDst;
  276. LPBYTE pbSzW;
  277. ULONG ulcbSzW;
  278. // Figure out the size of the buffer we need
  279. ulcbValue = pSWStringArray->cValues * sizeof(LPWSTR);
  280. for ( uliValue = 0, pszWSrc = pSWStringArray->lppszW;
  281. uliValue < pSWStringArray->cValues;
  282. uliValue++, pszWSrc++ )
  283. ulcbValue += (lstrlenW(*pszWSrc) + 1) * sizeof(WCHAR);
  284. // Allocate the buffer to hold the strings
  285. lppbValueDst = (LPBYTE *) &lpSPropValueDst->Value.MVszW.lppszW;
  286. sc = (*lpfAllocateMore)( ulcbValue,
  287. lpvObject,
  288. (LPVOID *) lppbValueDst );
  289. if ( sc != SUCCESS_SUCCESS )
  290. {
  291. DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst PT_MV_UNICODE property") );
  292. return sc;
  293. }
  294. // Copy the strings into the buffer and set pointers
  295. // to them in the LPWSTR array at the beginning of the buffer
  296. for ( uliValue = 0,
  297. pszWSrc = pSWStringArray->lppszW,
  298. pszWDst = (LPWSTR *) *lppbValueDst,
  299. pbSzW = (LPBYTE) (pszWDst + pSWStringArray->cValues);
  300. uliValue < pSWStringArray->cValues;
  301. uliValue++, pszWSrc++, pszWDst++ )
  302. {
  303. ulcbSzW = (lstrlenW(*pszWSrc) + 1) * sizeof(WCHAR);
  304. *((UNALIGNED LPWSTR *) pszWDst) = (LPWSTR) pbSzW;
  305. Assert(ulcbSzW < 0xFfff);
  306. MemCopy( pbSzW, (LPBYTE) *pszWSrc, (UINT) ulcbSzW );
  307. pbSzW += ulcbSzW;
  308. }
  309. return SUCCESS_SUCCESS;
  310. }
  311. default:
  312. DebugTrace( TEXT("PropCopyMore() - Unsupported/Unimplemented property type 0x%04x"), PROP_TYPE(lpSPropValueSrc->ulPropTag) );
  313. return MAPI_E_NO_SUPPORT;
  314. }
  315. sc = (*lpfAllocateMore)( ulcbValue, lpvObject, (LPVOID *) lppbValueDst );
  316. if ( sc != SUCCESS_SUCCESS )
  317. {
  318. DebugTrace( TEXT("PropCopyMore() - OOM allocating space for dst property") );
  319. return sc;
  320. }
  321. MemCopy( *lppbValueDst, lpbValueSrc, (UINT) ulcbValue );
  322. return SUCCESS_SUCCESS;
  323. }
  324. // $MAC - Mac 68K compiler bug
  325. #ifdef _M_M68K
  326. #pragma optimize( TEXT(""), on)
  327. #endif
  328. /*
  329. - UlPropSize()
  330. *
  331. * Returns the size of the property pointed to by lpSPropValue
  332. */
  333. STDAPI_(ULONG)
  334. UlPropSize( LPSPropValue lpSPropValue )
  335. {
  336. // parameter validation
  337. AssertSz( lpSPropValue && !IsBadReadPtr( lpSPropValue, sizeof( SPropValue ) ),
  338. TEXT("lpSPropValue fails address check") );
  339. switch ( PROP_TYPE(lpSPropValue->ulPropTag) )
  340. {
  341. case PT_I2: return sizeof(short int);
  342. case PT_LONG: return sizeof(LONG);
  343. case PT_R4: return SIZEOF_FLOAT;
  344. case PT_APPTIME:
  345. case PT_DOUBLE: return SIZEOF_DOUBLE;
  346. case PT_BOOLEAN: return sizeof(unsigned short int);
  347. case PT_CURRENCY: return sizeof(CURRENCY);
  348. case PT_SYSTIME: return sizeof(FILETIME);
  349. case PT_CLSID: return sizeof(GUID);
  350. case PT_I8: return sizeof(LARGE_INTEGER);
  351. case PT_ERROR: return sizeof(SCODE);
  352. case PT_BINARY: return lpSPropValue->Value.bin.cb;
  353. case PT_STRING8: return (lstrlenA( lpSPropValue->Value.lpszA ) + 1) * sizeof(CHAR);
  354. case PT_UNICODE: return (lstrlenW( lpSPropValue->Value.lpszW ) + 1) * sizeof(WCHAR);
  355. case PT_MV_I2: return lpSPropValue->Value.MVi.cValues * sizeof(short int);
  356. case PT_MV_LONG: return lpSPropValue->Value.MVl.cValues * sizeof(LONG);
  357. case PT_MV_R4: return lpSPropValue->Value.MVflt.cValues * SIZEOF_FLOAT;
  358. case PT_MV_APPTIME:
  359. case PT_MV_DOUBLE: return lpSPropValue->Value.MVdbl.cValues * SIZEOF_DOUBLE;
  360. case PT_MV_CURRENCY: return lpSPropValue->Value.MVcur.cValues * sizeof(CURRENCY);
  361. case PT_MV_SYSTIME: return lpSPropValue->Value.MVat.cValues * sizeof(FILETIME);
  362. case PT_MV_I8: return lpSPropValue->Value.MVli.cValues * sizeof(LARGE_INTEGER);
  363. case PT_MV_BINARY:
  364. {
  365. ULONG ulcbSize = 0;
  366. ULONG uliValue;
  367. for ( uliValue = 0;
  368. uliValue < lpSPropValue->Value.MVbin.cValues;
  369. uliValue++ )
  370. ulcbSize += AlignProp((lpSPropValue->Value.MVbin.lpbin + uliValue)->cb);
  371. return ulcbSize;
  372. }
  373. case PT_MV_STRING8:
  374. {
  375. ULONG ulcbSize = 0;
  376. ULONG uliValue;
  377. for ( uliValue = 0;
  378. uliValue < lpSPropValue->Value.MVszA.cValues;
  379. uliValue++ )
  380. ulcbSize += (lstrlenA(*(lpSPropValue->Value.MVszA.lppszA + uliValue)) + 1) * sizeof(CHAR);
  381. return ulcbSize;
  382. }
  383. case PT_MV_UNICODE:
  384. {
  385. ULONG ulcbSize = 0;
  386. ULONG uliValue;
  387. for ( uliValue = 0;
  388. uliValue < lpSPropValue->Value.MVszW.cValues;
  389. uliValue++ )
  390. ulcbSize += (lstrlenW(*(lpSPropValue->Value.MVszW.lppszW + uliValue)) + 1) * sizeof(WCHAR);
  391. return ulcbSize;
  392. }
  393. }
  394. return 0;
  395. }
  396. /**************************************************************************
  397. * GetInstance
  398. *
  399. * Purpose
  400. * Fill in an SPropValue with an instance of an MV propvalue
  401. *
  402. * Parameters
  403. * pvalMv The Mv property
  404. * pvalSv The Sv propery to fill
  405. * uliInst The instance with which to fill pvalSv
  406. */
  407. STDAPI_(void)
  408. GetInstance(LPSPropValue pvalMv, LPSPropValue pvalSv, ULONG uliInst)
  409. {
  410. switch (PROP_TYPE(pvalSv->ulPropTag))
  411. {
  412. case PT_I2:
  413. pvalSv->Value.li = pvalMv->Value.MVli.lpli[uliInst];
  414. break;
  415. case PT_LONG:
  416. pvalSv->Value.l = pvalMv->Value.MVl.lpl[uliInst];
  417. break;
  418. case PT_R4:
  419. pvalSv->Value.flt = pvalMv->Value.MVflt.lpflt[uliInst];
  420. break;
  421. case PT_DOUBLE:
  422. pvalSv->Value.dbl = pvalMv->Value.MVdbl.lpdbl[uliInst];
  423. break;
  424. case PT_CURRENCY:
  425. pvalSv->Value.cur = pvalMv->Value.MVcur.lpcur[uliInst];
  426. break;
  427. case PT_APPTIME :
  428. pvalSv->Value.at = pvalMv->Value.MVat.lpat[uliInst];
  429. break;
  430. case PT_SYSTIME:
  431. pvalSv->Value.ft = pvalMv->Value.MVft.lpft[uliInst];
  432. break;
  433. case PT_STRING8:
  434. pvalSv->Value.lpszA = pvalMv->Value.MVszA.lppszA[uliInst];
  435. break;
  436. case PT_BINARY:
  437. pvalSv->Value.bin = pvalMv->Value.MVbin.lpbin[uliInst];
  438. break;
  439. case PT_UNICODE:
  440. pvalSv->Value.lpszW = pvalMv->Value.MVszW.lppszW[uliInst];
  441. break;
  442. case PT_CLSID:
  443. pvalSv->Value.lpguid = &pvalMv->Value.MVguid.lpguid[uliInst];
  444. break;
  445. default:
  446. DebugTrace( TEXT("GetInstance() - Unsupported/unimplemented property type 0x%08lx"), PROP_TYPE(pvalMv->ulPropTag) );
  447. pvalSv->ulPropTag = PT_NULL;
  448. return;
  449. }
  450. }
  451. LPTSTR
  452. PszNormalizePsz(LPTSTR pszIn, BOOL fExact)
  453. {
  454. LPTSTR pszOut = NULL;
  455. UINT cb = 0;
  456. if (fExact)
  457. return pszIn;
  458. cb = sizeof(CHAR) * (lstrlen(pszIn) + 1);
  459. if (FAILED(MAPIAllocateBuffer(cb, (LPVOID *)&pszOut)))
  460. return NULL;
  461. MemCopy(pszOut, pszIn, cb);
  462. #if defined(WIN16) || defined(WIN32)
  463. CharUpper(pszOut);
  464. #else
  465. //$TODO: This should be inlined in the mapinls.h for non WIN
  466. //$ but I didn't want to do all the cases of CharUpper.
  467. //$DRM What about other languages?
  468. {
  469. CHAR *pch;
  470. for (pch = pszOut; *pch; pch++)
  471. {
  472. if (*pch >= 'a' && *pch <= 'z')
  473. *pch = (CHAR)(*pch - 'a' + 'A');
  474. }
  475. }
  476. #endif
  477. return pszOut;
  478. }
  479. #ifdef TABLES
  480. /*
  481. - FPropContainsProp()
  482. -
  483. * Compares two properties to see if one TEXT("contains") the other
  484. * according to a fuzzy level heuristic.
  485. *
  486. * The method of comparison depends on the type of the properties
  487. * being compared and the fuzzy level:
  488. *
  489. * Property types Fuzzy Level Comparison
  490. * -------------- ----------- ----------
  491. * PT_STRING8 FL_FULLSTRING Returns TRUE if the value of the source
  492. * PT_BINARY and target string are equivalent. With
  493. * no other flags is equivalent to
  494. * RES_PROPERTY with RELOP_EQ
  495. * returns FALSE otherwise.
  496. *
  497. * PT_STRING8 FL_SUBSTRING Returns TRUE if Pattern is contained
  498. * PT_BINARY as a substring in Target
  499. * returns FALSE otherwise.
  500. *
  501. * PT_STRING8 FL_IGNORECASE All comparisons are done case insensitively
  502. *
  503. * PT_STRING8 FL_IGNORENONSPACE THIS IS NOT (YET?) IMPLEMENTED
  504. * All comparisons ignore what in unicode are
  505. * called TEXT("non-spacing characters") such as
  506. * diacritics.
  507. *
  508. * PT_STRING8 FL_LOOSE Provider adds value by doing as much of
  509. * FL_IGNORECASE and FL_IGNORESPACE as he wants
  510. *
  511. * PT_STRING8 FL_PREFIX Pattern and Target are compared only up to
  512. * PT_BINARY the length of Pattern
  513. *
  514. * PT_STRING8 any other Ignored
  515. *
  516. *
  517. * PT_BINARY any not defined Returns TRUE if the value of the property
  518. * above pointed to by lpSPropValueTarget contains the
  519. * sequence of bytes which is the value of
  520. * the property pointed to by lpSPropValuePattern;
  521. * returns FALSE otherwise.
  522. *
  523. * Error returns:
  524. *
  525. * FALSE If the properties being compared are not both of the same
  526. * type, or if one or both of those properties is not one
  527. * of the types listed above, or if the fuzzy level is not
  528. * one of those listed above.
  529. */
  530. STDAPI_(BOOL)
  531. FPropContainsProp( LPSPropValue lpSPropValueTarget,
  532. LPSPropValue lpSPropValuePattern,
  533. ULONG ulFuzzyLevel )
  534. {
  535. SPropValue sval;
  536. ULONG uliInst;
  537. LCID lcid = GetUserDefaultLCID();
  538. DWORD dwCSFlags = ((!(ulFuzzyLevel & FL_IGNORECASE)-1) & (NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH)) |
  539. ((!(ulFuzzyLevel & FL_IGNORENONSPACE)-1) & NORM_IGNORENONSPACE);
  540. // Validate parameters
  541. AssertSz( lpSPropValueTarget && !IsBadReadPtr( lpSPropValueTarget, sizeof( SPropValue ) ),
  542. TEXT("lpSPropValueTarget fails address check") );
  543. AssertSz( lpSPropValuePattern && !IsBadReadPtr( lpSPropValuePattern, sizeof( SPropValue ) ),
  544. TEXT("lpSPropValuePattern fails address check") );
  545. if (ulFuzzyLevel & FL_LOOSE)
  546. dwCSFlags |= NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH;
  547. if ( !(lpSPropValuePattern->ulPropTag & MV_FLAG)
  548. && lpSPropValueTarget->ulPropTag & MV_FLAG)
  549. {
  550. sval.ulPropTag = lpSPropValueTarget->ulPropTag & ~MV_FLAG;
  551. uliInst = lpSPropValueTarget->Value.MVbin.cValues;
  552. while (uliInst-- > 0)
  553. {
  554. GetInstance(lpSPropValueTarget, &sval, uliInst);
  555. if (FPropContainsProp(&sval, lpSPropValuePattern, ulFuzzyLevel))
  556. return TRUE;
  557. }
  558. return FALSE;
  559. }
  560. if ( PROP_TYPE(lpSPropValuePattern->ulPropTag) !=
  561. PROP_TYPE(lpSPropValueTarget->ulPropTag) )
  562. return FALSE;
  563. switch ( PROP_TYPE(lpSPropValuePattern->ulPropTag) )
  564. {
  565. case PT_STRING8:
  566. // [PaulHi] 2/16/99 single byte string version
  567. if (ulFuzzyLevel & FL_SUBSTRING)
  568. {
  569. return FRKFindSubpsz(lpSPropValueTarget->Value.lpszA,
  570. lstrlenA(lpSPropValueTarget->Value.lpszA),
  571. lpSPropValuePattern->Value.lpszA,
  572. lstrlenA(lpSPropValuePattern->Value.lpszA),
  573. ulFuzzyLevel);
  574. }
  575. else // FL_PREFIX or FL_FULLSTRING
  576. {
  577. UINT cch;
  578. if (ulFuzzyLevel & FL_PREFIX)
  579. {
  580. cch = (UINT)lstrlenA(lpSPropValuePattern->Value.lpszA);
  581. if (cch > (UINT)lstrlenA(lpSPropValueTarget->Value.lpszA))
  582. return(FALSE);
  583. }
  584. else
  585. cch = (UINT)-1;
  586. return CompareStringA(lcid, dwCSFlags,
  587. lpSPropValueTarget->Value.lpszA, cch,
  588. lpSPropValuePattern->Value.lpszA, cch) == 2;
  589. }
  590. case PT_UNICODE:
  591. // [PaulHi] 2/16/99 double byte string version
  592. if (ulFuzzyLevel & FL_SUBSTRING)
  593. {
  594. LPSTR lpszTarget = ConvertWtoA(lpSPropValueTarget->Value.lpszW);
  595. LPSTR lpszPattern = ConvertWtoA(lpSPropValuePattern->Value.lpszW);
  596. BOOL bRtn = FALSE;
  597. if (lpszTarget && lpszPattern)
  598. {
  599. bRtn = FRKFindSubpsz(lpszTarget,
  600. lstrlenA(lpszTarget),
  601. lpszPattern,
  602. lstrlenA(lpszPattern),
  603. ulFuzzyLevel);
  604. }
  605. LocalFreeAndNull(&lpszTarget);
  606. LocalFreeAndNull(&lpszPattern);
  607. return bRtn;
  608. }
  609. else // FL_PREFIX or FL_FULLSTRING
  610. {
  611. UINT cch;
  612. if (ulFuzzyLevel & FL_PREFIX)
  613. {
  614. cch = (UINT)lstrlen(lpSPropValuePattern->Value.lpszW);
  615. if (cch > (UINT)lstrlen(lpSPropValueTarget->Value.lpszW))
  616. return(FALSE);
  617. }
  618. else
  619. cch = (UINT)-1;
  620. return CompareString(lcid, dwCSFlags,
  621. lpSPropValueTarget->Value.lpszW, cch,
  622. lpSPropValuePattern->Value.lpszW, cch) == 2;
  623. }
  624. break;
  625. case PT_BINARY:
  626. if (ulFuzzyLevel & FL_SUBSTRING)
  627. return FRKFindSubpb(lpSPropValueTarget->Value.bin.lpb,
  628. lpSPropValueTarget->Value.bin.cb,
  629. lpSPropValuePattern->Value.bin.lpb,
  630. lpSPropValuePattern->Value.bin.cb);
  631. else if (ulFuzzyLevel & FL_PREFIX)
  632. {
  633. if (lpSPropValuePattern->Value.bin.cb > lpSPropValueTarget->Value.bin.cb)
  634. return FALSE;
  635. }
  636. else // FL_FULLSTRING
  637. if (lpSPropValuePattern->Value.bin.cb != lpSPropValueTarget->Value.bin.cb)
  638. return FALSE;
  639. return !memcmp(lpSPropValuePattern->Value.bin.lpb,
  640. lpSPropValueTarget->Value.bin.lpb,
  641. (UINT) lpSPropValuePattern->Value.bin.cb);
  642. case PT_MV_STRING8:
  643. {
  644. SPropValue spvT, spvP;
  645. ULONG i;
  646. // [PaulHi] 2/16/99 single byte string version
  647. // To do MV_STRING we will break up the individual strings in the target
  648. // into single STRING prop values and pass them recursively back into this
  649. // function.
  650. // We expect the pattern MV prop to contain exactly one string. It's kind
  651. // of hard to decide what the behavior should be otherwise.
  652. if (lpSPropValuePattern->Value.MVszA.cValues != 1)
  653. {
  654. DebugTrace( TEXT("FPropContainsProp() - PT_MV_STRING8 of pattern must have cValues == 1\n"));
  655. return(FALSE);
  656. }
  657. // Turn off the MV flag and pass in each string seperately
  658. spvP.ulPropTag = spvT.ulPropTag = lpSPropValuePattern->ulPropTag & ~MV_FLAG;
  659. spvP.Value.lpszA = *lpSPropValuePattern->Value.MVszA.lppszA;
  660. for (i = 0; i < lpSPropValueTarget->Value.MVszA.cValues; i++)
  661. {
  662. spvT.Value.lpszA = lpSPropValueTarget->Value.MVszA.lppszA[i];
  663. if (FPropContainsProp(&spvT,
  664. &spvP,
  665. ulFuzzyLevel))
  666. {
  667. return(TRUE);
  668. }
  669. }
  670. return(FALSE);
  671. }
  672. break;
  673. case PT_MV_UNICODE:
  674. {
  675. SPropValue spvT, spvP;
  676. ULONG i;
  677. // [PaulHi] 2/16/99 double byte string version
  678. // To do MV_STRING we will break up the individual strings in the target
  679. // into single STRING prop values and pass them recursively back into this
  680. // function.
  681. // We expect the pattern MV prop to contain exactly one string. It's kind
  682. // of hard to decide what the behavior should be otherwise.
  683. if (lpSPropValuePattern->Value.MVszW.cValues != 1)
  684. {
  685. DebugTrace( TEXT("FPropContainsProp() - PT_MV_UNICODE of pattern must have cValues == 1\n"));
  686. return(FALSE);
  687. }
  688. // Turn off the MV flag and pass in each string seperately
  689. spvP.ulPropTag = spvT.ulPropTag = lpSPropValuePattern->ulPropTag & ~MV_FLAG;
  690. spvP.Value.lpszW = *lpSPropValuePattern->Value.MVszW.lppszW;
  691. for (i = 0; i < lpSPropValueTarget->Value.MVszW.cValues; i++)
  692. {
  693. spvT.Value.lpszW = lpSPropValueTarget->Value.MVszW.lppszW[i];
  694. if (FPropContainsProp(&spvT,
  695. &spvP,
  696. ulFuzzyLevel))
  697. {
  698. return(TRUE);
  699. }
  700. }
  701. return(FALSE);
  702. }
  703. break;
  704. default:
  705. DebugTrace( TEXT("FPropContainsProp() - Unsupported/unimplemented property type 0x%08lx\n"), PROP_TYPE(lpSPropValuePattern->ulPropTag) );
  706. return FALSE;
  707. } // end switch(ulPropTag)
  708. }
  709. /*
  710. - FPropCompareProp()
  711. -
  712. * Compares the property pointed to by lpSPropValue1 with the property
  713. * pointed to by lpSPropValue2 using the binary relational operator
  714. * specified by ulRelOp. The order of comparison is:
  715. *
  716. * Property1 Operator Property2
  717. */
  718. STDAPI_(BOOL)
  719. FPropCompareProp( LPSPropValue lpSPropValue1,
  720. ULONG ulRelOp,
  721. LPSPropValue lpSPropValue2 )
  722. {
  723. SPropValue sval;
  724. ULONG uliInst;
  725. // Validate parameters
  726. AssertSz( lpSPropValue1 && !IsBadReadPtr( lpSPropValue1, sizeof( SPropValue ) ),
  727. TEXT("lpSPropValue1 fails address check") );
  728. AssertSz( lpSPropValue2 && !IsBadReadPtr( lpSPropValue2, sizeof( SPropValue ) ),
  729. TEXT("lpSPropValue2 fails address check") );
  730. if ( !(lpSPropValue2->ulPropTag & MV_FLAG)
  731. && lpSPropValue1->ulPropTag & MV_FLAG)
  732. {
  733. sval.ulPropTag = lpSPropValue1->ulPropTag & ~MV_FLAG;
  734. uliInst = lpSPropValue1->Value.MVbin.cValues;
  735. while (uliInst-- > 0)
  736. {
  737. GetInstance(lpSPropValue1, &sval, uliInst);
  738. if (FPropCompareProp(&sval, ulRelOp, lpSPropValue2))
  739. return TRUE;
  740. }
  741. return FALSE;
  742. }
  743. // If the prop types don't match then the properties are not
  744. // equal but otherwise uncomparable
  745. //
  746. if (PROP_TYPE(lpSPropValue1->ulPropTag) !=
  747. PROP_TYPE(lpSPropValue2->ulPropTag))
  748. return (ulRelOp == RELOP_NE);
  749. switch ( ulRelOp )
  750. {
  751. case RELOP_LT:
  752. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) < 0;
  753. case RELOP_LE:
  754. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) <= 0;
  755. case RELOP_GT:
  756. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) > 0;
  757. case RELOP_GE:
  758. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) >= 0;
  759. case RELOP_EQ:
  760. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) == 0;
  761. case RELOP_NE:
  762. return LPropCompareProp( lpSPropValue1, lpSPropValue2 ) != 0;
  763. case RELOP_RE:
  764. return FALSE;
  765. }
  766. DebugTrace( TEXT("FPropCompareProp() - Unknown relop 0x%08lx"), ulRelOp );
  767. return FALSE;
  768. }
  769. /*
  770. - LPropCompareProp()
  771. -
  772. * Description:
  773. *
  774. * Compares two properties to determine the ordering
  775. * relation between the two. For property types which
  776. * have no intrinsic ordering (eg. BOOLEAN, ERROR, etc.)
  777. * this function simply determines if the two are equal
  778. * or not equal. If they are not equal, the returned
  779. * value is not defined, but it will be non-zero and
  780. * will be consistent across calls.
  781. *
  782. *
  783. * Returns:
  784. *
  785. * < 0 if property A is TEXT("less than") property B
  786. * > 0 if property A is TEXT("greater than") property B
  787. * 0 if property A TEXT("equals") property B
  788. *
  789. */
  790. STDAPI_(LONG)
  791. LPropCompareProp( LPSPropValue lpSPropValueA,
  792. LPSPropValue lpSPropValueB )
  793. {
  794. ULONG uliinst;
  795. ULONG ulcinst;
  796. LONG lRetval;
  797. LCID lcid = GetUserDefaultLCID();
  798. // Validate parameters
  799. AssertSz( lpSPropValueA && !IsBadReadPtr( lpSPropValueA, sizeof( SPropValue ) ),
  800. TEXT("lpSPropValueA fails address check") );
  801. AssertSz( lpSPropValueB && !IsBadReadPtr( lpSPropValueB, sizeof( SPropValue ) ),
  802. TEXT("lpSPropValueB fails address check") );
  803. Assert( PROP_TYPE(lpSPropValueA->ulPropTag) ==
  804. PROP_TYPE(lpSPropValueB->ulPropTag) );
  805. if (lpSPropValueA->ulPropTag & MV_FLAG)
  806. {
  807. ulcinst = min(lpSPropValueA->Value.MVi.cValues, lpSPropValueB->Value.MVi.cValues);
  808. for (uliinst = 0; uliinst < ulcinst; uliinst++)
  809. {
  810. switch (PROP_TYPE(lpSPropValueA->ulPropTag))
  811. {
  812. case PT_MV_I2:
  813. if (lRetval = lpSPropValueA->Value.MVi.lpi[uliinst] - lpSPropValueB->Value.MVi.lpi[uliinst])
  814. return lRetval;
  815. break;
  816. case PT_MV_LONG:
  817. if (lRetval = lpSPropValueA->Value.MVl.lpl[uliinst] - lpSPropValueB->Value.MVl.lpl[uliinst])
  818. return lRetval;
  819. break;
  820. case PT_MV_R4:
  821. if (lpSPropValueA->Value.MVflt.lpflt[uliinst] != lpSPropValueB->Value.MVflt.lpflt[uliinst])
  822. return lpSPropValueA->Value.MVflt.lpflt[uliinst] < lpSPropValueB->Value.MVflt.lpflt[uliinst] ? -1 : 1;
  823. break;
  824. case PT_MV_DOUBLE:
  825. if (lpSPropValueA->Value.MVdbl.lpdbl[uliinst] != lpSPropValueB->Value.MVdbl.lpdbl[uliinst])
  826. return lpSPropValueA->Value.MVdbl.lpdbl[uliinst] < lpSPropValueB->Value.MVdbl.lpdbl[uliinst] ? -1 : 1;
  827. break;
  828. case PT_MV_SYSTIME:
  829. lRetval = lpSPropValueA->Value.MVft.lpft[uliinst].dwHighDateTime == lpSPropValueB->Value.MVft.lpft[uliinst].dwHighDateTime ?
  830. (lpSPropValueA->Value.MVft.lpft[uliinst].dwLowDateTime != lpSPropValueB->Value.MVft.lpft[uliinst].dwLowDateTime ?
  831. (lpSPropValueA->Value.MVft.lpft[uliinst].dwLowDateTime < lpSPropValueB->Value.MVft.lpft[uliinst].dwLowDateTime ?
  832. -1 : 1) : 0) : (lpSPropValueA->Value.MVft.lpft[uliinst].dwHighDateTime < lpSPropValueB->Value.MVft.lpft[uliinst].dwHighDateTime ? -1 : 1);
  833. if (lRetval)
  834. return lRetval;
  835. break;
  836. case PT_MV_BINARY:
  837. lRetval = lpSPropValueA->Value.MVbin.lpbin[uliinst].cb != lpSPropValueB->Value.MVbin.lpbin[uliinst].cb ?
  838. (lpSPropValueA->Value.MVbin.lpbin[uliinst].cb < lpSPropValueB->Value.MVbin.lpbin[uliinst].cb ?
  839. -1 : 1) : memcmp(lpSPropValueA->Value.MVbin.lpbin[uliinst].lpb,
  840. lpSPropValueB->Value.MVbin.lpbin[uliinst].lpb,
  841. (UINT) lpSPropValueA->Value.MVbin.lpbin[uliinst].cb);
  842. if (lRetval)
  843. return lRetval;
  844. break;
  845. case PT_MV_STRING8:
  846. lRetval = CompareStringA(lcid, NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,
  847. lpSPropValueA->Value.MVszA.lppszA[uliinst], -1,
  848. lpSPropValueB->Value.MVszA.lppszA[uliinst], -1) - 2;
  849. if (lRetval)
  850. return lRetval;
  851. break;
  852. case PT_MV_UNICODE:
  853. lRetval = CompareStringW(lcid, NORM_IGNORECASE | NORM_IGNORENONSPACE | NORM_IGNOREKANATYPE,
  854. lpSPropValueA->Value.MVszW.lppszW[uliinst], -1,
  855. lpSPropValueB->Value.MVszW.lppszW[uliinst], -1) - 2;
  856. if (lRetval)
  857. return lRetval;
  858. break;
  859. case PT_MV_I8:
  860. case PT_MV_CURRENCY:
  861. lRetval = lpSPropValueA->Value.MVli.lpli[uliinst].HighPart == lpSPropValueB->Value.MVli.lpli[uliinst].HighPart ?
  862. (lpSPropValueA->Value.MVli.lpli[uliinst].LowPart != lpSPropValueB->Value.MVli.lpli[uliinst].LowPart ?
  863. (lpSPropValueA->Value.MVli.lpli[uliinst].LowPart < lpSPropValueB->Value.MVli.lpli[uliinst].LowPart ?
  864. -1 : 1) : 0) : (lpSPropValueA->Value.MVli.lpli[uliinst].HighPart < lpSPropValueB->Value.MVli.lpli[uliinst].HighPart ? -1 : 1);
  865. if (lRetval)
  866. return lRetval;
  867. break;
  868. case PT_MV_CLSID:
  869. lRetval = memcmp(&lpSPropValueA->Value.MVguid.lpguid[uliinst],
  870. &lpSPropValueB->Value.MVguid.lpguid[uliinst],
  871. sizeof(GUID));
  872. break;
  873. case PT_MV_APPTIME: //$ NYI
  874. default:
  875. DebugTrace( TEXT("PropCompare() - Unknown or NYI property type 0x%08lx. Assuming equal"), PROP_TYPE(lpSPropValueA->ulPropTag) );
  876. return 0;
  877. }
  878. }
  879. return lpSPropValueA->Value.MVi.cValues - lpSPropValueB->Value.MVi.cValues;
  880. }
  881. else
  882. {
  883. switch ( PROP_TYPE(lpSPropValueA->ulPropTag) )
  884. {
  885. case PT_NULL:
  886. //$ By definition any PT_NULL property is equal to
  887. //$ every other PT_NULL property. (Is this right?)
  888. return 0;
  889. case PT_LONG:
  890. case PT_ERROR:
  891. return (lpSPropValueA->Value.l == lpSPropValueB->Value.l) ? 0 :
  892. (lpSPropValueA->Value.l > lpSPropValueB->Value.l) ? 1 : -1;
  893. case PT_BOOLEAN:
  894. return (LONG) !!lpSPropValueA->Value.b - (LONG) !!lpSPropValueB->Value.b;
  895. case PT_I2:
  896. return (LONG) lpSPropValueA->Value.i - (LONG) lpSPropValueB->Value.i;
  897. case PT_I8:
  898. case PT_CURRENCY:
  899. return lpSPropValueA->Value.li.HighPart == lpSPropValueB->Value.li.HighPart ?
  900. (lpSPropValueA->Value.li.LowPart != lpSPropValueB->Value.li.LowPart ?
  901. (lpSPropValueA->Value.li.LowPart < lpSPropValueB->Value.li.LowPart ?
  902. -1 : 1) : 0) : (lpSPropValueA->Value.li.HighPart < lpSPropValueB->Value.li.HighPart ? -1 : 1);
  903. case PT_SYSTIME:
  904. return lpSPropValueA->Value.ft.dwHighDateTime == lpSPropValueB->Value.ft.dwHighDateTime ?
  905. (lpSPropValueA->Value.ft.dwLowDateTime != lpSPropValueB->Value.ft.dwLowDateTime ?
  906. (lpSPropValueA->Value.ft.dwLowDateTime < lpSPropValueB->Value.ft.dwLowDateTime ?
  907. -1 : 1) : 0) : (lpSPropValueA->Value.ft.dwHighDateTime < lpSPropValueB->Value.ft.dwHighDateTime ? -1 : 1);
  908. case PT_R4:
  909. return lpSPropValueA->Value.flt != lpSPropValueB->Value.flt ?
  910. (lpSPropValueA->Value.flt < lpSPropValueB->Value.flt ?
  911. -1 : 1) : 0;
  912. case PT_DOUBLE:
  913. case PT_APPTIME:
  914. return lpSPropValueA->Value.dbl != lpSPropValueB->Value.dbl ?
  915. (lpSPropValueA->Value.dbl < lpSPropValueB->Value.dbl ?
  916. -1 : 1) : 0;
  917. case PT_BINARY:
  918. // The following tediousness with assignment de-ICEs WIN16SHP
  919. {
  920. LPBYTE pbA = lpSPropValueA->Value.bin.lpb;
  921. LPBYTE pbB = lpSPropValueB->Value.bin.lpb;
  922. lRetval = min(lpSPropValueA->Value.bin.cb, lpSPropValueB->Value.bin.cb);
  923. lRetval = memcmp(pbA, pbB, (UINT) lRetval);
  924. }
  925. if (lRetval != 0)
  926. return lRetval;
  927. else if (lpSPropValueA->Value.bin.cb == lpSPropValueB->Value.bin.cb)
  928. return 0L;
  929. else if (lpSPropValueA->Value.bin.cb < lpSPropValueB->Value.bin.cb)
  930. return -1L;
  931. else
  932. return 1L;
  933. case PT_UNICODE:
  934. //$ REVIEW: If we NORM_IGNORENONSPACE then our sorts will look
  935. //$ REVIEW: wrong for languages which define an ordering for
  936. //$ REVIEW: diacritics.
  937. return CompareStringW(lcid, NORM_IGNORECASE | NORM_IGNOREKANATYPE,
  938. lpSPropValueA->Value.lpszW, -1, lpSPropValueB->Value.lpszW, -1) - 2;
  939. case PT_STRING8:
  940. //$ REVIEW: If we NORM_IGNORENONSPACE then our sorts will look
  941. //$ REVIEW: wrong for languages which define an ordering for
  942. //$ REVIEW: diacritics.
  943. return CompareStringA(lcid, NORM_IGNORECASE | NORM_IGNOREKANATYPE | NORM_IGNOREWIDTH,
  944. lpSPropValueA->Value.lpszA, -1, lpSPropValueB->Value.lpszA, -1) - 2;
  945. case PT_CLSID:
  946. {
  947. GUID UNALIGNED *lpguidA = lpSPropValueA->Value.lpguid;
  948. GUID UNALIGNED *lpguidB = lpSPropValueB->Value.lpguid;
  949. return memcmp(lpguidA, lpguidB, sizeof(GUID));
  950. }
  951. case PT_OBJECT: // Not supported
  952. case PT_UNSPECIFIED: // Not supported
  953. default:
  954. DebugTrace( TEXT("PropCompare() - Unknown or NYI property type 0x%08lx. Assuming equal"), PROP_TYPE(lpSPropValueA->ulPropTag) );
  955. return 0;
  956. }
  957. }
  958. }
  959. /**************************************************************************
  960. * HrAddColumns
  961. *
  962. * Purpose
  963. * Add space for the properties in ptaga to the column set for the table.
  964. * The specified properties will be the first properties returned on
  965. * subsequent QueryRows calls.
  966. * Any properties that were already in the column set, but weren't
  967. * in the new array will be placed at the end of the new column
  968. * set. This call is most often used on RECIPIENT tables.
  969. *
  970. * Parameters
  971. * pmt A pointer to an LPMAPITABLE
  972. * ptaga counted array of props to be moved up front or added
  973. * lpfnAllocBuf pointer to MAPIAllocateBuffer
  974. * lpfnFreeBuf pointer to MAPIFreeBuffer
  975. */
  976. STDAPI_(HRESULT)
  977. HrAddColumns( LPMAPITABLE pmt,
  978. LPSPropTagArray ptaga,
  979. LPALLOCATEBUFFER lpfnAllocBuf,
  980. LPFREEBUFFER lpfnFreeBuf)
  981. {
  982. HRESULT hr;
  983. hr = HrAddColumnsEx(pmt, ptaga, lpfnAllocBuf, lpfnFreeBuf, NULL);
  984. DebugTraceResult(HrAddColumns, hr);
  985. return hr;
  986. }
  987. /**************************************************************************
  988. * HrAddColumnsEx
  989. *
  990. * Purpose
  991. * add space for the properties in ptaga to the columns set for the pmt.
  992. * The specified properties will be the first properties returned on
  993. * subsequent QueryRows calls. Any properties that were already in the
  994. * column set, but weren't in the new array will be placed at the end
  995. * of the new column set. This call is most often used on RECIPIENT
  996. * tables. The extended version of this call allows the caller to
  997. * filter the original proptags (e.g., to force UNICODE to STRING8).
  998. *
  999. * Parameters
  1000. * pmt pointer to an LPMAPITABLE
  1001. * ptagaIn counted array of properties to be moved up front
  1002. * or added
  1003. * lpfnAllocBuf pointer to MAPIAllocateBuffer
  1004. * lpfnFreeBuf pointer to MAPIFreeBuffer
  1005. * lpfnFilterColumns callback function applied to the table's column set
  1006. */
  1007. STDAPI_(HRESULT)
  1008. HrAddColumnsEx( LPMAPITABLE pmt,
  1009. LPSPropTagArray ptagaIn,
  1010. LPALLOCATEBUFFER lpfnAllocBuf,
  1011. LPFREEBUFFER lpfnFreeBuf,
  1012. void (FAR *lpfnFilterColumns)(LPSPropTagArray ptaga))
  1013. {
  1014. HRESULT hr = hrSuccess;
  1015. SCODE sc = S_OK;
  1016. LPSPropTagArray ptagaOld = NULL; /* old, original columns on pmt */
  1017. LPSPropTagArray ptagaExtend = NULL; /* extended columns on pmt */
  1018. ULONG ulcPropsOld;
  1019. ULONG ulcPropsIn;
  1020. ULONG ulcPropsFinal;
  1021. UNALIGNED ULONG *pulPTEnd;
  1022. UNALIGNED ULONG *pulPTOld;
  1023. UNALIGNED ULONG *pulPTOldMac;
  1024. // Do some parameter checking.
  1025. AssertSz(!FBadUnknown((LPUNKNOWN) pmt),
  1026. TEXT("HrAddColumnsEx: bad table object"));
  1027. AssertSz( !IsBadReadPtr(ptagaIn, CbNewSPropTagArray(0))
  1028. && !IsBadReadPtr(ptagaIn, CbSPropTagArray(ptagaIn)),
  1029. TEXT("Bad Prop Tag Array given to HrAddColumnsEx."));
  1030. AssertSz(!IsBadCodePtr((FARPROC) lpfnAllocBuf),
  1031. TEXT("HrAddColumnsEx: lpfnAllocBuf fails address check"));
  1032. AssertSz(!IsBadCodePtr((FARPROC) lpfnFreeBuf),
  1033. TEXT("HrAddColumnsEx: lpfnFreeBuf fails address check"));
  1034. AssertSz(!lpfnFilterColumns || !IsBadCodePtr((FARPROC) lpfnFilterColumns),
  1035. TEXT("HrAddColumnsEx: lpfnFilterColumns fails address check"));
  1036. // Find out which columns are already set on the table.
  1037. //
  1038. hr = pmt->lpVtbl->QueryColumns(pmt, TBL_ALL_COLUMNS, &ptagaOld);
  1039. if (HR_FAILED(hr))
  1040. goto exit;
  1041. AssertSz( !IsBadReadPtr( ptagaOld, CbNewSPropTagArray(0))
  1042. && !IsBadReadPtr( ptagaOld, CbSPropTagArray(ptagaOld)),
  1043. TEXT("Bad Prop Tag Array returned from QueryColumns."));
  1044. // Give the caller an opportunity to filter the source column set,
  1045. // for instance, to force UNICODE to STRING8
  1046. //
  1047. if (lpfnFilterColumns)
  1048. {
  1049. (*lpfnFilterColumns)(ptagaOld);
  1050. }
  1051. ulcPropsOld = ptagaOld->cValues;
  1052. ulcPropsIn = ptagaIn->cValues;
  1053. // Allocate space for the maximum possible number of new columns.
  1054. //
  1055. sc = (lpfnAllocBuf)(CbNewSPropTagArray(ulcPropsOld + ulcPropsIn),
  1056. (LPVOID *)&ptagaExtend);
  1057. if (FAILED(sc))
  1058. {
  1059. hr = ResultFromScode(sc);
  1060. goto exit;
  1061. }
  1062. // Fill in the front of the extended prop tag array with the set
  1063. // of properties which must be at known locations in the array.
  1064. //
  1065. MemCopy(ptagaExtend, ptagaIn, CbSPropTagArray(ptagaIn));
  1066. // If one of the old columns isn't in the given array, then put it after
  1067. // the given tags.
  1068. ulcPropsFinal = ptagaIn->cValues;
  1069. pulPTEnd = &(ptagaExtend->aulPropTag[ulcPropsFinal]);
  1070. pulPTOld = ptagaOld->aulPropTag;
  1071. pulPTOldMac = pulPTOld + ulcPropsOld;
  1072. while (pulPTOld < pulPTOldMac)
  1073. {
  1074. UNALIGNED ULONG *pulPTIn;
  1075. UNALIGNED ULONG *pulPTInMac;
  1076. pulPTIn = ptagaIn->aulPropTag;
  1077. pulPTInMac = pulPTIn + ulcPropsIn;
  1078. while ( pulPTIn < pulPTInMac
  1079. && *pulPTOld != *pulPTIn)
  1080. ++pulPTIn;
  1081. if (pulPTIn >= pulPTInMac)
  1082. {
  1083. // This property is not one of the input ones so put it in the next
  1084. // available position after the input ones.
  1085. //
  1086. *pulPTEnd = *pulPTOld;
  1087. ++pulPTEnd;
  1088. ++ulcPropsFinal;
  1089. }
  1090. ++pulPTOld;
  1091. }
  1092. // Set the total number of prop tags in the extended tag array.
  1093. //
  1094. ptagaExtend->cValues = ulcPropsFinal;
  1095. // Tell the table to return the extended column set.
  1096. //
  1097. hr = pmt->lpVtbl->SetColumns(pmt, ptagaExtend, 0L);
  1098. exit:
  1099. (lpfnFreeBuf)(ptagaExtend);
  1100. (lpfnFreeBuf)(ptagaOld);
  1101. DebugTraceResult(HrAddColumnsEx, hr);
  1102. return hr;
  1103. }
  1104. #endif